| /* |
| * Routines for comparing AIF objects. |
| * |
| * Copyright (c) 1996-2002 by Guardsoft Pty Ltd. |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif /* HAVE_CONFIG_H */ |
| |
| #include <stdio.h> |
| #include <string.h> |
| #include <math.h> |
| |
| #include "aif.h" |
| #include "aiferr.h" |
| #include "aifint.h" |
| |
| int |
| AIFIsZero(AIF *a, int *val) |
| { |
| char * f; |
| char * d; |
| |
| if ( a == (AIF *)NULL || val == (int *)NULL ) |
| { |
| SetAIFError(AIFERR_BADARG, NULL); |
| return -1; |
| } |
| |
| f = AIF_FORMAT(a); |
| d = AIF_DATA(a); |
| |
| return _aif_is_zero(&f, &d, AIF_LEN(a), val); |
| } |
| |
| int |
| _aif_is_zero(char **fds, char **data, int len, int *val) |
| { |
| int i; |
| int nv; |
| int bytes; |
| char c; |
| char * target; |
| AIFIndex * ix; |
| char * fmt; |
| AIFDOUBLEST v; |
| |
| if ( **fds == FDS_NAME ) |
| { |
| *fds = _fds_skipto(*fds, "/"); |
| (*fds)++; |
| } |
| |
| switch ( FDSType(*fds) ) |
| { |
| case AIF_UNION: |
| bytes = FDSTypeSize(*fds); |
| *val = 1; /* zero unless shown otherwise */ |
| |
| (*fds)++; /* past open brace */ |
| |
| _fds_skip_typename(fds); |
| |
| while ( **fds != FDS_UNION_END ) |
| { |
| *fds = strchr(*fds, FDS_UNION_FIELD_NAME_END) + 1; /* to start of field */ |
| |
| if ( (i = FDSTypeSize(*fds)) < 0 ) |
| return -1; |
| |
| fmt = _aif_alloc( sizeof(char) * i ); |
| target = fmt; |
| memcpy(target, *data, i); |
| |
| if ( _aif_is_zero(fds, &target, len, val) < 0 ) |
| { |
| _aif_free(fmt); |
| return -1; |
| } |
| |
| if ( *val == 0 ) |
| return 0; /* zero res means no need to look further */ |
| if ( **fds == FDS_UNION_FIELD_SEP ) |
| (*fds)++; |
| } |
| |
| *fds = strchr(*fds, FDS_AGGREGATE_END) + 1; /*past close brace*/ |
| *data += bytes; |
| |
| return 0; |
| |
| case AIF_ENUM: |
| *fds = _fds_base_type(*fds); |
| bytes = _fds_count_bytes(fds); |
| *val = _aif_int_is_zero(*data, bytes); |
| (*data) += bytes; |
| |
| return 0; |
| |
| case AIF_POINTER: |
| *val = (_get_pointer_type(*data) == AIF_PTR_NIL); |
| _fds_skip_data(fds, data); |
| return 0; |
| |
| case AIF_CHARACTER: |
| bytes = _fds_count_bytes(fds); |
| |
| if ( _aif_to_char(*data, &c) < 0 ) |
| return -1; |
| |
| *val = (c == '\0'); |
| (*data) += bytes; |
| |
| return 0; |
| |
| case AIF_INTEGER: |
| case AIF_BOOLEAN: /* if it is FALSE, val = 1, if it is TRUE, val = 0 */ |
| bytes = _fds_count_bytes(fds); |
| *val = _aif_int_is_zero(*data, bytes); |
| (*data) += bytes; |
| |
| return 0; |
| |
| case AIF_FLOATING: |
| bytes = _fds_count_bytes(fds); |
| |
| if ( _aif_to_doublest(*data, bytes, &v) < 0 ) |
| return -1; |
| |
| *val = (v == (AIFDOUBLEST)0.0L); |
| (*data) += bytes; |
| |
| return 0; |
| |
| case AIF_ARRAY: |
| ix = FDSArrayIndexInit(*fds); |
| |
| _fds_advance(fds); /* skip over the entire array fds */ |
| |
| for ( i = 0 ; i < ix->i_nel ; i++ ) |
| { |
| fmt = ix->i_btype; |
| |
| if ( _aif_is_zero(&fmt, data, ix->i_bsize, &nv) < 0 ) |
| return -1; |
| |
| if ( nv == 0 ) /* no need to look further */ |
| { |
| *val = 0; |
| return 0; |
| } |
| } |
| |
| AIFArrayIndexFree(ix); |
| |
| *val = 1; |
| |
| return 0; |
| |
| /* |
| ** only uses the public section in AIF_AGGREGATE |
| */ |
| case AIF_AGGREGATE: |
| *val = 1; /* zero unless shown otherwise */ |
| |
| (*fds)++; /* past open brace */ |
| _fds_skip_typename(fds); |
| |
| while ( **fds != FDS_AGGREGATE_ACCESS_SEP ) |
| { |
| *fds = strchr(*fds, FDS_AGGREGATE_FIELD_NAME_END) + 1; /* to start of field */ |
| |
| if ( _aif_is_zero(fds, data, len, val) < 0 ) |
| return -1; |
| |
| if ( *val == 0 ) |
| return 0; /* zero res means no need to look further */ |
| if ( **fds == FDS_AGGREGATE_FIELD_SEP ) |
| (*fds)++; |
| } |
| |
| *fds = strchr(*fds, FDS_AGGREGATE_END) + 1; /*past close brace*/ |
| |
| return 0; |
| |
| case AIF_STRING: |
| (*fds)++; /* past "s" */ |
| bytes = (*(*data)++ & 0xff) << 8; |
| bytes += *(*data)++ & 0xff; |
| |
| *data += bytes; |
| |
| *val = (bytes == 0); |
| |
| return 0; |
| |
| default: |
| SetAIFError(AIFERR_TYPE, NULL); |
| return -1; |
| } |
| } |
| |
| int |
| _aif_int_is_zero(char *data, int len) |
| { |
| int i; |
| |
| for ( i = 0 ; i < len ; i++ ) |
| if ( (int)*data++ != 0 ) |
| return 0; |
| |
| return 1; |
| } |
| |
| /* |
| * Compare types of two AIF values. Return true if they are equivalent, |
| * false if not. |
| */ |
| int |
| AIFTypeCompare(AIF *a1, AIF *a2) |
| { |
| return FDSTypeCompare(AIF_FORMAT(a1), AIF_FORMAT(a2)); |
| } |
| |
| int |
| AIFCompare(int depth, AIF *a1, AIF *a2, int *res) |
| { |
| char * f1; |
| char * f2; |
| char * d1; |
| char * d2; |
| |
| if ( a1 == (AIF *)NULL || a2 == (AIF *)NULL ) |
| { |
| SetAIFError(AIFERR_BADARG, NULL); |
| return -1; |
| } |
| |
| f1 = AIF_FORMAT(a1); |
| f2 = AIF_FORMAT(a2); |
| d1 = AIF_DATA(a1); |
| d2 = AIF_DATA(a2); |
| |
| return _aif_compare(depth, res, &f1, &d1, &f2, &d2); |
| } |
| |
| int |
| _aif_cmp_int(int *res, char *d1, int l1, char *d2, int l2) |
| { |
| int i; |
| int l; |
| char * r1; |
| char * r2 = NULL; |
| |
| r1 = (char *)_aif_alloc(l2); |
| |
| _aif_neg_int(r1, d2, l2); |
| |
| _aif_add_int(&r2, &l, d1, l1, r1, l2); |
| |
| _aif_free(r1); |
| |
| if ( *r2 & 0x80 ) |
| { |
| /* |
| ** negative result => a < b |
| */ |
| _aif_free(r2); |
| *res = -1; |
| return 0; |
| } |
| |
| /* |
| ** Check for zero |
| */ |
| |
| for ( i = 0 ; i < MAX(l1, l2) ; i++ ) |
| { |
| if ( r2[i] != 0x0 ) |
| { |
| /* |
| ** positive result => a > b |
| */ |
| _aif_free(r2); |
| *res = 1; |
| return 0; |
| } |
| } |
| |
| /* |
| ** zero result => a = b |
| */ |
| _aif_free(r2); |
| *res = 0; |
| return 0; |
| } |
| |
| int |
| _aif_cmp_float(int *res, char *d1, int l1, char *d2, int l2) |
| { |
| AIFDOUBLEST v1; |
| AIFDOUBLEST v2; |
| |
| if |
| ( |
| _aif_to_doublest(d1, l1, &v1) < 0 |
| || |
| _aif_to_doublest(d2, l2, &v2) < 0 |
| ) |
| return -1; |
| |
| if ( v1 < v2 ) |
| *res = -1; |
| else if ( v1 > v2 ) |
| *res = 1; |
| else |
| *res = 0; |
| |
| return 0; |
| } |
| |
| int |
| _aif_cmp_char(int *res, char *d1, char *d2) |
| { |
| char v1; |
| char v2; |
| |
| if |
| ( |
| _aif_to_char(d1, &v1) < 0 |
| || |
| _aif_to_char(d2, &v2) < 0 |
| ) |
| return -1; |
| |
| if ( v1 < v2 ) |
| *res = -1; |
| else if ( v1 > v2 ) |
| *res = 1; |
| else |
| *res = 0; |
| |
| return 0; |
| } |
| |
| /* |
| * Compare two AIF values. |
| * |
| * For numeric values, sets res to: |
| * |
| * -1 if d1 < d2 |
| * 0 if d1 == d2 |
| * 1 if d1 > d2 |
| * |
| * For other values, sets res to: |
| * |
| * 0 if d1 == d2 |
| * 1 if d1 != d2 |
| * |
| * For array type, res is 0 if all elements are equal, 1 otherwise. |
| * The parameters f1, d1, f2, d2 are advanced through their structures; on |
| * return, they are in the position following the relevant parts. |
| * The return value is negative if there is a type failure. |
| */ |
| int |
| _aif_compare(int depth, int *res, char **f1, char **d1, char **f2, char **d2) |
| { |
| int i; |
| int l3; |
| int success; /* value to return indicating type match */ |
| int bytes1; |
| int bytes2; /* number of bytes in arithmetic data */ |
| char * fmt; |
| char * d3 = NULL; |
| AIFIndex * ix1; |
| AIFIndex * ix2; |
| AIFLONGEST val1; |
| AIFLONGEST val2; |
| |
| /* these cmp_by_name, f2_x* and d2_x* are used by 'case AIF_AGGREGATE' */ |
| int cmp_by_name = 0; |
| char * f2_x1; |
| char * f2_x2; |
| char * d2_x1; |
| char * d2_x2; |
| |
| ResetAIFError(); |
| |
| /* |
| ** resolve names and references first |
| */ |
| _fds_resolve(f1); |
| _fds_resolve(f2); |
| |
| if ( FDSType(*f1) == AIF_REFERENCE ) |
| { |
| fmt = _fds_lookup(f1); |
| return _aif_compare(depth, res, &fmt, d1, f2, d2); |
| } |
| |
| if ( FDSType(*f2) == AIF_REFERENCE ) |
| { |
| fmt = _fds_lookup(f2); |
| return _aif_compare(depth, res, f1, d1, &fmt, d2); |
| } |
| |
| switch ( FDSType(*f1) ) |
| { |
| case AIF_POINTER: |
| if ( FDSType(*f2) == AIF_POINTER ) |
| { |
| int t1 = _get_pointer_type(*d1); |
| int t2 = _get_pointer_type(*d2); |
| |
| if ( depth == -1 ) |
| { |
| *res = 0; |
| |
| _fds_skip_data(f1, d1); |
| _fds_skip_data(f2, d2); |
| |
| return 0; |
| } |
| else if ( depth == 1 ) |
| depth = -1; |
| else if ( depth > 1 ) |
| depth--; |
| |
| /* |
| * Can't compare invalid pointers |
| */ |
| if ( t1 == AIF_PTR_INVALID || t2 == AIF_PTR_INVALID ) |
| { |
| *res = 0; |
| |
| _fds_skip_data(f1, d1); |
| _fds_skip_data(f2, d2); |
| |
| SetAIFError(AIFERR_ARITH, NULL); |
| |
| return -1; |
| } |
| |
| /* |
| * pointers are equal only if they refer to the same target |
| * this also prevents infinite recursion |
| */ |
| if ( t1 == AIF_PTR_REFERENCE || t2 == AIF_PTR_REFERENCE ) { |
| if (t1 == AIF_PTR_REFERENCE && t2 == AIF_PTR_REFERENCE) { |
| *res = (_get_pointer_name(*d1) != _get_pointer_name(*d2)); |
| } else { |
| *res = 1; |
| } |
| |
| _fds_skip_data(f1, d1); |
| _fds_skip_data(f2, d2); |
| |
| return 0; |
| } |
| |
| /* |
| * null pointers are equal only if they are both null |
| */ |
| if ( t1 == AIF_PTR_NIL || t2 == AIF_PTR_NIL ) |
| { |
| *res = (t1 != t2); |
| |
| _fds_skip_data(f1, d1); |
| _fds_skip_data(f2, d2); |
| |
| return 0; |
| } |
| |
| /* |
| * both point to something real so compare targets |
| */ |
| |
| _find_target(f1, d1, 0); |
| _find_target(f2, d2, 1); |
| |
| return _aif_compare(depth, res, f1, d1, f2, d2); |
| } |
| else |
| { |
| /* |
| ** incompatible types |
| */ |
| SetAIFError(AIFERR_CONV, NULL); |
| *res = 1; |
| return -1; |
| } |
| |
| case AIF_UNION: |
| bytes1 = FDSTypeSize(*f1); |
| bytes2 = FDSTypeSize(*f2); |
| |
| if ( FDSType(*f2) != AIF_UNION ) |
| { |
| SetAIFError(AIFERR_CONV, NULL); |
| *res = 1; |
| return -1; |
| } |
| |
| (*f1)++; /* past open brace */ |
| (*f2)++; /* past open brace */ |
| _fds_skip_typename(f1); |
| _fds_skip_typename(f2); |
| |
| *res = 0; /* first assumption, they are equal */ |
| |
| while ( **f1 != FDS_UNION_END ) |
| { |
| int size1, size2; |
| char *temp1, *temp2, *data1, *data2; |
| |
| if ( **f2 == FDS_UNION_END ) |
| { |
| /* |
| ** f1 has more fields |
| */ |
| SetAIFError(AIFERR_CONV, NULL); |
| |
| *res = 1; /* in a sense, d1 > d2 */ |
| |
| return -1; |
| } |
| |
| *f1 = strchr(*f1, FDS_UNION_FIELD_NAME_END) + 1; |
| *f2 = strchr(*f2, FDS_UNION_FIELD_NAME_END) + 1; |
| |
| size1 = FDSTypeSize(*f1); |
| size2 = FDSTypeSize(*f2); |
| temp1 = _aif_alloc( sizeof(char) * size1 ); |
| temp2 = _aif_alloc( sizeof(char) * size2 ); |
| data1 = temp1; |
| data2 = temp2; |
| memcpy(data1, *d1, size1); |
| memcpy(data2, *d2, size2); |
| |
| success = _aif_compare(depth, res, f1, &data1, f2, &data2); |
| _aif_free(temp1); |
| _aif_free(temp2); |
| |
| /* |
| ** non-zero res means no need to look further |
| */ |
| if ( *res ) |
| return 0; |
| |
| if ( **f1 == FDS_UNION_FIELD_SEP ) |
| (*f1)++; |
| |
| if ( **f2 == FDS_UNION_FIELD_SEP ) |
| (*f2)++; |
| } |
| |
| if ( **f2 != FDS_UNION_END ) |
| { |
| /* |
| ** f2 has more fields |
| */ |
| SetAIFError(AIFERR_CONV, NULL); |
| |
| *res = -1; /* in a sense, d1 < d2 */ |
| |
| return -1; |
| } |
| |
| *f1 = strchr(*f1, FDS_UNION_END) + 1; /*past close brace*/ |
| *f2 = strchr(*f2, FDS_UNION_END) + 1; /*past close brace*/ |
| *d1 += bytes1; |
| *d2 += bytes2; |
| |
| return 0; |
| |
| case AIF_ENUM: |
| switch ( FDSType(*f2) ) |
| { |
| case AIF_ENUM: |
| *f1 = _fds_base_type(*f1); |
| *f2 = _fds_base_type(*f2); |
| |
| bytes1 = _fds_count_bytes(f1); |
| bytes2 = _fds_count_bytes(f2); |
| |
| success = _aif_cmp_int(res, *d1, bytes1, *d2, bytes2); |
| |
| *d1 += bytes1; |
| *d2 += bytes2; |
| |
| return success; |
| |
| default: |
| SetAIFError(AIFERR_CONV, NULL); |
| *res = 1; |
| return -1; |
| } |
| break; |
| |
| case AIF_INTEGER: |
| switch ( FDSType(*f2) ) |
| { |
| case AIF_INTEGER: |
| bytes1 = _fds_count_bytes(f1); |
| bytes2 = _fds_count_bytes(f2); |
| |
| success = _aif_cmp_int(res, *d1, bytes1, *d2, bytes2); |
| |
| *d1 += bytes1; |
| *d2 += bytes2; |
| |
| return success; |
| |
| case AIF_FLOATING: |
| bytes1 = _fds_count_bytes(f1); |
| _aif_int_to_aif_float(&fmt, &d3, &l3, *d1, bytes1); |
| *d1 += bytes1; |
| |
| if ( l3 < 0 ) |
| { |
| *res = 1; |
| return -1; |
| } |
| |
| bytes2 = _fds_count_bytes(f2); |
| success = _aif_cmp_float(res, d3, l3, *d2, bytes2); |
| *d2 += bytes2; |
| _aif_free(fmt); |
| _aif_free(d3); |
| |
| return success; |
| |
| default: |
| SetAIFError(AIFERR_CONV, NULL); |
| *res = 1; |
| return -1; |
| } |
| break; |
| |
| case AIF_FLOATING: |
| switch ( FDSType(*f2) ) |
| { |
| case AIF_INTEGER: |
| bytes2 = _fds_count_bytes(f2); |
| _aif_int_to_aif_float(&fmt, &d3, &l3, *d2, bytes2); |
| *d2 += bytes2; |
| |
| if ( l3 < 0 ) |
| { |
| *res = 1; |
| return -1; |
| } |
| |
| bytes1 = _fds_count_bytes(f1); |
| success = _aif_cmp_float(res, *d1, bytes1, d3, l3); |
| *d1 += bytes1; |
| _aif_free(fmt); |
| _aif_free(d3); |
| |
| return success; |
| |
| case AIF_FLOATING: |
| bytes1 = _fds_count_bytes(f1); |
| bytes2 = _fds_count_bytes(f2); |
| |
| success = _aif_cmp_float(res, *d1, bytes1, *d2, bytes2); |
| |
| *d1 += bytes1; |
| *d2 += bytes2; |
| |
| return success; |
| |
| default: |
| SetAIFError(AIFERR_CONV, NULL); |
| *res = 1; |
| return -1; |
| } |
| break; |
| |
| case AIF_CHARACTER: |
| switch ( FDSType(*f2) ) |
| { |
| case AIF_CHARACTER: |
| bytes1 = _fds_count_bytes(f1); |
| bytes2 = _fds_count_bytes(f2); |
| |
| success = _aif_cmp_char(res, *d1, *d2); |
| |
| *d1 += bytes1; |
| *d2 += bytes2; |
| |
| return success; |
| |
| default: |
| SetAIFError(AIFERR_CONV, NULL); |
| *res = 1; |
| return -1; |
| } |
| break; |
| |
| case AIF_ARRAY: |
| switch ( FDSType(*f2) ) |
| { |
| case AIF_ARRAY: |
| ix1 = FDSArrayIndexInit(*f1); |
| ix2 = FDSArrayIndexInit(*f2); |
| |
| /* |
| ** skip over the entire array fds |
| */ |
| _fds_advance(f1); |
| _fds_advance(f2); |
| |
| *res = 0; /* first assumption, they are equal */ |
| |
| if ( ix1->i_nel != ix2->i_nel ) |
| { |
| SetAIFError(AIFERR_SIZE, NULL); |
| AIFArrayIndexFree(ix1); |
| AIFArrayIndexFree(ix2); |
| |
| *res = 1; |
| return -1; |
| } |
| |
| for ( i = 0 ; i < ix1->i_nel ; i++ ) |
| { |
| char * fmt1; |
| char * fmt2; |
| |
| fmt1 = ix1->i_btype; |
| fmt2 = ix2->i_btype; |
| |
| success = _aif_compare(depth, res, &fmt1, d1, &fmt2, d2); |
| if ( success < 0 ) |
| { |
| AIFArrayIndexFree(ix1); |
| AIFArrayIndexFree(ix2); |
| /* Do not need to set 'res' here, |
| * It's already set from the call |
| * to _aif_compare() |
| */ |
| return -1; |
| } |
| |
| if ( *res != 0 ) |
| { |
| /* |
| ** no need to continue |
| */ |
| AIFArrayIndexFree(ix1); |
| AIFArrayIndexFree(ix2); |
| return 0; |
| } |
| } |
| |
| AIFArrayIndexFree(ix1); |
| AIFArrayIndexFree(ix2); |
| |
| return 0; |
| |
| default: |
| SetAIFError(AIFERR_CONV, NULL); |
| *res = 1; |
| return -1; |
| } |
| |
| /* |
| ** only uses the public section in AIF_AGGREGATE |
| */ |
| case AIF_AGGREGATE: |
| /* |
| ** aggregate equivalence: we ignore field names |
| */ |
| |
| if ( FDSType(*f2) != AIF_AGGREGATE ) |
| { |
| SetAIFError(AIFERR_CONV, NULL); |
| *res = 1; |
| return -1; |
| } |
| |
| if ( AIFGetOption(AIFOPT_CMP_METHOD) == AIF_CMP_BY_NAME ) |
| { |
| cmp_by_name = 1; |
| f2_x1 = *f2; |
| d2_x1 = *d2; |
| f2_x2 = NULL; |
| d2_x2 = NULL; |
| _fds_skip_data(&f2_x1, &d2_x1); |
| if ( _fds_aggregate_arrange(*f1, *f2, *d2, &f2_x2, &d2_x2) < 0 ) |
| { |
| SetAIFError(AIFERR_CONV, NULL); |
| *res = 1; |
| return -1; |
| } |
| |
| *f2 = f2_x2; |
| *d2 = d2_x2; |
| /* at the end, we assign f2_x1 to f2, d2_x1 to d2, |
| ** and we free f2_x2 and d2_x2 */ |
| } |
| |
| (*f1)++; /* past open brace */ |
| (*f2)++; /* past open brace */ |
| _fds_skip_typename(f1); |
| _fds_skip_typename(f2); |
| |
| *res = 0; /* first assumption, they are equal */ |
| |
| while ( **f1 != FDS_AGGREGATE_ACCESS_SEP ) |
| { |
| if ( **f2 == FDS_AGGREGATE_ACCESS_SEP ) |
| { |
| /* |
| ** f1 has more fields |
| */ |
| SetAIFError(AIFERR_CONV, NULL); |
| |
| *res = 1; /* in a sense, d1 > d2 */ |
| |
| if (cmp_by_name == 1) |
| { |
| _aif_free(f2_x2); |
| _aif_free(d2_x2); |
| *f2 = f2_x1; |
| *d2 = d2_x1; |
| } |
| return -1; |
| } |
| |
| *f1 = strchr(*f1, FDS_AGGREGATE_FIELD_NAME_END) + 1; /* to start of field */ |
| *f2 = strchr(*f2, FDS_AGGREGATE_FIELD_NAME_END) + 1; /* to start of field */ |
| |
| success = _aif_compare(depth, res, f1, d1, f2, d2); |
| |
| if ( success < 0 ) |
| { |
| if (cmp_by_name == 1) |
| { |
| _aif_free(f2_x2); |
| _aif_free(d2_x2); |
| *f2 = f2_x1; |
| *d2 = d2_x1; |
| } |
| /* Do not need to set 'res' here, |
| * It's already set from the call |
| * to _aif_compare() |
| */ |
| return -1; |
| } |
| |
| /* |
| ** non-zero res means no need to look further |
| */ |
| if ( *res ) |
| { |
| if (cmp_by_name == 1) |
| { |
| _aif_free(f2_x2); |
| _aif_free(d2_x2); |
| *f2 = f2_x1; |
| *d2 = d2_x1; |
| } |
| return 0; |
| } |
| |
| if ( **f1 == FDS_AGGREGATE_FIELD_SEP ) |
| (*f1)++; |
| |
| if ( **f2 == FDS_AGGREGATE_FIELD_SEP ) |
| (*f2)++; |
| } |
| |
| if ( **f2 != FDS_AGGREGATE_ACCESS_SEP ) |
| { |
| /* |
| ** f2 has more fields |
| */ |
| SetAIFError(AIFERR_CONV, NULL); |
| |
| *res = -1; /* in a sense, d1 < d2 */ |
| |
| if (cmp_by_name == 1) |
| { |
| _aif_free(f2_x2); |
| _aif_free(d2_x2); |
| *f2 = f2_x1; |
| *d2 = d2_x1; |
| } |
| return -1; |
| } |
| |
| *f1 = strchr(*f1, FDS_AGGREGATE_END) + 1; /*past close brace*/ |
| *f2 = strchr(*f2, FDS_AGGREGATE_END) + 1; /*past close brace*/ |
| |
| if (cmp_by_name == 1) |
| { |
| _aif_free(f2_x2); |
| _aif_free(d2_x2); |
| *f2 = f2_x1; |
| *d2 = d2_x1; |
| } |
| return 0; |
| |
| case AIF_STRING: |
| if ( FDSType(*f2) != AIF_STRING ) |
| { |
| SetAIFError(AIFERR_CONV, NULL); |
| *res = 1; |
| return -1; |
| } |
| |
| (*f1)++; /* past "s" */ |
| (*f2)++; /* past "s" */ |
| |
| bytes1 = (*(*d1)++ & 0xff) << 8; |
| bytes1 += *(*d1)++ & 0xff; |
| bytes2 = (*(*d2)++ & 0xff) << 8; |
| bytes2 += *(*d2)++ & 0xff; |
| |
| *res = strncmp(*d1, *d2, MIN(bytes1, bytes2)); |
| |
| *d1 += bytes1; |
| *d2 += bytes2; |
| |
| if ( *res ) |
| return 0; |
| |
| if ( bytes1 == bytes2 ) |
| { |
| /* |
| ** they are the same in length and contents |
| */ |
| return 0; |
| } |
| else |
| { |
| /* |
| ** they start the same, but one is longer |
| */ |
| *res = (bytes1 < bytes2) ? -1 : 1; |
| return 0; |
| } |
| |
| case AIF_BOOLEAN: |
| bytes1 = _fds_count_bytes_na(f1); |
| bytes2 = _fds_count_bytes_na(f2); |
| |
| switch ( FDSType(*f2) ) |
| { |
| case AIF_BOOLEAN: |
| _aif_to_longest(*d1, bytes1, &val1); |
| _aif_to_longest(*d2, bytes2, &val2); |
| |
| if( val1 == val2) |
| *res = 0; |
| else |
| *res = 1; |
| |
| *d1 += bytes1; |
| *d2 += bytes2; |
| |
| _fds_advance(f1); |
| _fds_advance(f2); |
| |
| return 0; |
| |
| default: |
| SetAIFError(AIFERR_CONV, NULL); |
| *res = 1; |
| return -1; |
| } |
| |
| case AIF_VOID: |
| if ( FDSType(*f2) == AIF_VOID ) |
| *res = 0; |
| else |
| *res = 1; |
| |
| return 0; |
| |
| default: |
| SetAIFError(AIFERR_TYPE, NULL); |
| *res = 1; |
| return -1; |
| } |
| } |
| |
| int |
| _aif_eps(char *lo_fds, char *lo_data, int lo_len, char *hi_fds, char *hi_data, int hi_len, char *a_fds, char *a_data, int a_len, int *val) |
| { |
| int ft; |
| char * fds_ref; |
| |
| int lo_i, hi_i, a_i; |
| double lo_d, hi_d, a_d; |
| |
| AIFLONGEST lo_ll, hi_ll, a_ll; |
| AIFDOUBLEST lo_dd, hi_dd, a_dd; |
| |
| ResetAIFError(); |
| |
| _fds_resolve(&a_fds); |
| |
| if ( FDSType(a_fds) == AIF_REFERENCE ) |
| { |
| fds_ref = _fds_lookup(&a_fds); |
| return _aif_eps(lo_fds, lo_data, lo_len, hi_fds, hi_data, hi_len, fds_ref, a_data, a_len, val); |
| } |
| |
| switch ( ft = FDSType(a_fds) ) |
| { |
| case AIF_BOOLEAN: |
| |
| if ( FDSType(lo_fds) != AIF_BOOLEAN ) |
| { |
| SetAIFError(AIFERR_BADARG, NULL); |
| return -1; |
| } |
| |
| if ( _aif_to_longest(lo_data, lo_len, &lo_ll) < 0 || |
| _aif_to_longest(a_data, a_len, &a_ll) < 0 ) |
| return -1; |
| |
| lo_i = (int) lo_ll; |
| hi_i = (int) hi_ll; |
| a_i = (int) a_ll; |
| |
| if ( lo_i == 0 && a_i == 0 ) |
| *val = -1; |
| else if ( lo_i == -1 && a_i == 0 ) |
| *val = 0; |
| else if ( a_i == -1 ) |
| *val = 1; |
| |
| return 0; |
| |
| case AIF_INTEGER: |
| case AIF_CHARACTER: |
| case AIF_ENUM: |
| |
| if ( FDSType(lo_fds) != ft || |
| FDSType(hi_fds) != ft ) |
| { |
| SetAIFError(AIFERR_BADARG, NULL); |
| return -1; |
| } |
| |
| if ( _aif_to_longest(lo_data, lo_len, &lo_ll) < 0 || |
| _aif_to_longest(a_data, a_len, &a_ll) < 0 || |
| _aif_to_longest(hi_data, hi_len, &hi_ll) < 0 ) |
| return -1; |
| |
| lo_i = (int) lo_ll; |
| hi_i = (int) hi_ll; |
| a_i = (int) a_ll; |
| |
| if ( a_i < lo_i ) |
| *val = -1; |
| else if ( lo_i <= a_i && a_i <= hi_i ) |
| *val = 0; |
| else if (a_i > hi_i ) |
| *val = 1; |
| |
| return 0; |
| |
| case AIF_STRING: |
| |
| if ( FDSType(lo_fds) != AIF_STRING || |
| FDSType(hi_fds) != AIF_STRING ) |
| { |
| SetAIFError(AIFERR_BADARG, NULL); |
| return -1; |
| } |
| |
| if ( _aif_to_longest(lo_data + 2, lo_len - 2, &lo_ll) < 0 || |
| _aif_to_longest(a_data + 2, a_len - 2, &a_ll) < 0 || |
| _aif_to_longest(hi_data + 2, hi_len - 2, &hi_ll) < 0 ) |
| return -1; |
| |
| lo_i = (int) lo_ll; |
| hi_i = (int) hi_ll; |
| a_i = (int) a_ll; |
| |
| if ( a_i < lo_i ) |
| *val = -1; |
| else if ( lo_i <= a_i && a_i <= hi_i ) |
| *val = 0; |
| else if (a_i > hi_i ) |
| *val = 1; |
| |
| return 0; |
| |
| case AIF_FLOATING: |
| |
| if ( FDSType(lo_fds) != AIF_FLOATING || |
| FDSType(hi_fds) != AIF_FLOATING ) |
| { |
| SetAIFError(AIFERR_BADARG, NULL); |
| return -1; |
| } |
| |
| if ( _aif_to_doublest(lo_data, lo_len, &lo_dd) < 0 || |
| _aif_to_doublest(a_data, a_len, &a_dd) < 0 || |
| _aif_to_doublest(hi_data, hi_len, &hi_dd) < 0 ) |
| return -1; |
| |
| lo_d = (int) lo_dd; |
| hi_d = (int) hi_dd; |
| a_d = (int) a_dd; |
| |
| if ( a_d < lo_d ) |
| *val = -1; |
| else if ( lo_d <= a_d && a_d <= hi_d ) |
| *val = 0; |
| else if (a_d > hi_d ) |
| *val = 1; |
| |
| return 0; |
| |
| case AIF_ARRAY: |
| { |
| int tmp, i; |
| AIFIndex * ix; |
| |
| char * t_fmt; |
| char * t_dt1; |
| char * t_dt2; |
| int t_len; |
| |
| ix = FDSArrayIndexInit(a_fds); |
| |
| t_dt1 = a_data; |
| |
| for ( i = 0 ; i < ix->i_nel ; i++ ) |
| { |
| |
| t_fmt = ix->i_btype; |
| t_dt2 = t_dt1; |
| |
| _fds_skip_data(&t_fmt, &t_dt1); |
| t_len = t_dt1 - t_dt2; |
| |
| if ( _aif_eps(lo_fds, lo_data, lo_len, hi_fds, hi_data, hi_len, ix->i_btype, t_dt2, t_len, &tmp) < 0 ) |
| { |
| AIFArrayIndexFree(ix); |
| return -1; |
| } |
| |
| if ( tmp == 0 || tmp == 1 ) |
| { |
| AIFArrayIndexFree(ix); |
| *val = tmp; |
| return 0; |
| } |
| } |
| |
| AIFArrayIndexFree(ix); |
| *val = -1; |
| return 0; |
| } |
| |
| /* only works with the public section in AIF_AGGREGATE */ |
| case AIF_AGGREGATE: |
| { |
| int tmp; |
| |
| char * t_ft1; |
| char * t_ft2; |
| char * t_dt1; |
| char * t_dt2; |
| int t_len; |
| |
| a_fds++; |
| _fds_skip_typename(&a_fds); |
| |
| t_dt1 = a_data; |
| t_ft1 = a_fds; |
| |
| while ( *t_ft1 != ';' ) |
| { |
| |
| t_ft1 = strchr(t_ft1, FDS_AGGREGATE_FIELD_NAME_END) + 1; |
| |
| t_dt2 = t_dt1; |
| t_ft2 = t_ft1; |
| |
| _fds_skip_data(&t_ft1, &t_dt1); |
| t_len = t_dt1 - t_dt2; |
| |
| if ( _aif_eps(lo_fds, lo_data, lo_len, hi_fds, hi_data, hi_len, t_ft2, t_dt2, t_len, &tmp) < 0 ) |
| { |
| return -1; |
| } |
| |
| if ( tmp == 0 || tmp == 1 ) |
| { |
| *val = tmp; |
| return 0; |
| } |
| } |
| |
| *val = -1; |
| return 0; |
| } |
| |
| case AIF_POINTER: |
| { |
| int tmp; |
| |
| // FIXME:_find_target(a_fds, a_data, &a_len, 0); |
| |
| if ( _aif_eps(lo_fds, lo_data, lo_len, hi_fds, hi_data, hi_len, a_fds, a_data, a_len, &tmp) < 0 ) |
| { |
| return -1; |
| } |
| |
| *val = tmp; |
| return 0; |
| } |
| |
| default: |
| SetAIFError(AIFERR_TYPE, NULL); |
| return -1; |
| } |
| } |
| |
| /* AIFEPS |
| * |
| * return_value is in val |
| * |
| * AIF_BOOLEAN (type of lo & hi is AIF_BOOLEAN) |
| * val = -1 if !lo & !a |
| * val = 0 if lo & !a |
| * val = 1 if a |
| * |
| * AIF_INTEGER, AIF_CHAR, AIF_ENUM, AIF_STRING (type of lo & hi is AIF_INTEGER) |
| * val = -1 if a < lo |
| * val = 0 if lo <= a <= hi |
| * val = 1 if a > hi |
| * |
| * AIF_FLOATING (type of lo & hi is AIF_FLOATING) |
| * val = -1 if a < lo |
| * val = 0 if lo <= a <= hi |
| * val = 1 if a > hi |
| * |
| * AIF_ARRAY (type of lo & hi is the base of AIF_ARRAY) |
| * val = -1 if eps(a[i]) == -1 for ALL i |
| * val = 0 if eps(a[i]) == 0 for ANY i |
| * val = 1 if eps(a[i]) == 1 for ANY i |
| * |
| * AIF_AGGREGATE (type of lo & hi is AIF_AGGREGATE) |
| * val = -1 if eps(element[i]) == -1 for ALL i |
| * val = 0 if eps(element[i]) == 0 for ANY i |
| * val = 1 if eps(element[i]) == 1 for ANY i |
| * |
| * AIF_POINTER (type of lo & hi is the base of AIF_POINTER) |
| * val = eps(a) if a = *p |
| * |
| * Other types |
| * ERROR |
| */ |
| |
| int |
| AIFEPS(AIF *lo, AIF *hi, AIF *a, int *val) |
| { |
| return _aif_eps(AIF_FORMAT(lo), AIF_DATA(lo), AIF_LEN(lo), AIF_FORMAT(hi), AIF_DATA(hi), AIF_LEN(hi), AIF_FORMAT(a), AIF_DATA(a), AIF_LEN(a), val); |
| } |
| |
| |
| AIF * |
| AIFDiff(int depth, AIF *a1, AIF *a2) |
| { |
| int rl; |
| char * rd = NULL; |
| char * rf = NULL; |
| char * f1; |
| char * f2; |
| char * d1; |
| char * d2; |
| |
| if ( a1 == (AIF *)NULL || a2 == (AIF *)NULL ) |
| { |
| SetAIFError(AIFERR_BADARG, NULL); |
| return NULL; |
| } |
| |
| f1 = AIF_FORMAT(a1); |
| f2 = AIF_FORMAT(a2); |
| d1 = AIF_DATA(a1); |
| d2 = AIF_DATA(a2); |
| |
| if ( _aif_diff(depth, &rf, &rd, &rl, &f1, &d1, &f2, &d2) < 0 ) |
| return (AIF *)NULL; |
| |
| return _make_aif(rf, rd, rl); |
| } |
| |
| /* |
| * Compare two AIF values. Generates an AIF value that represents the |
| * 'difference' between the values. Returns 0 for success or -1 on error. |
| * |
| * In the case of scalar values the difference is: val1 - val2 |
| * In the case of booleans it is TRUE if they are different |
| * In the case of strings it is a string containing '1' in the positions |
| * where characters differ and '0' in positions where they are the same. |
| * In the case of null pointers, the difference is a null pointer |
| * |
| * Complex objects can also be compared. In this case the above rules are |
| * applied to each field or element in the object. |
| */ |
| int |
| _aif_diff(int depth, char **rf, char **rd, int *rl, |
| char **f1, char **d1, |
| char **f2, char **d2) |
| { |
| int i; |
| int bytes1; |
| int bytes2; |
| char * fmt; |
| int datalen; /* to keep track of the length of the resultant data */ |
| int currentlen; /* current data length */ |
| |
| /* these cmp_by_name, f2_x* and d2_x* are used by 'case AIF_AGGREGATE' */ |
| int cmp_by_name = 0; |
| char * f2_x1; |
| char * f2_x2; |
| char * d2_x1; |
| char * d2_x2; |
| |
| ResetAIFError(); |
| |
| _fds_resolve(f1); |
| _fds_resolve(f2); |
| |
| if ( FDSType(*f1) == AIF_REFERENCE ) |
| { |
| fmt = _fds_lookup(f1); |
| return _aif_diff(depth, rf, rd, rl, &fmt, d1, f2, d2); |
| } |
| |
| if ( FDSType(*f2) == AIF_REFERENCE ) |
| { |
| fmt = _fds_lookup(f2); |
| return _aif_diff(depth, rf, rd, rl, f1, d1, &fmt, d2); |
| } |
| |
| switch ( FDSType(*f1) ) |
| { |
| case AIF_INTEGER: |
| case AIF_FLOATING: |
| case AIF_CHARACTER: |
| case AIF_ADDRESS: |
| return _aif_binary_op(AIFOP_SUB, rf, rd, rl, f1, d1, f2, d2); |
| |
| /* returns FALSE if they are the same */ |
| case AIF_BOOLEAN: |
| bytes1 = _fds_count_bytes_na(f1); |
| bytes2 = _fds_count_bytes_na(f2); |
| |
| switch ( FDSType(*f2) ) |
| { |
| case AIF_BOOLEAN: |
| { |
| AIFLONGEST val1; |
| AIFLONGEST val2; |
| AIFLONGEST val3; |
| |
| *rl = MAX(bytes1, bytes2); |
| |
| if ( *rd == NULL ) |
| *rd = (char *)_aif_alloc(*rl); |
| |
| _aif_to_longest(*d1, bytes1, &val1); |
| _aif_to_longest(*d2, bytes2, &val2); |
| val3 = val1 ^ val2; |
| _longest_to_aif(rd, *rl, val3); |
| |
| if ( *rf == NULL ) |
| *rf = strdup(AIF_BOOLEAN_TYPE(*rl)); |
| |
| *d1 += bytes1; |
| *d2 += bytes2; |
| |
| _fds_advance(f1); |
| _fds_advance(f2); |
| } |
| |
| return 0; |
| |
| default: |
| SetAIFError(AIFERR_CONV, NULL); |
| return -1; |
| } |
| break; |
| |
| case AIF_ARRAY: |
| { |
| AIFIndex * ix1; |
| AIFIndex * ix2; |
| char * fmt1; |
| char * fmt2; |
| char * fres = NULL; |
| char * dres = NULL; |
| |
| if ( FDSType(*f2) != AIF_ARRAY ) |
| { |
| SetAIFError(AIFERR_TYPE, NULL); |
| return -1; |
| } |
| |
| ix1 = FDSArrayIndexInit(*f1); |
| ix2 = FDSArrayIndexInit(*f2); |
| |
| if ( ix1->i_nel != ix2->i_nel ) |
| { |
| SetAIFError(AIFERR_SIZE, NULL); |
| AIFArrayIndexFree(ix1); |
| AIFArrayIndexFree(ix2); |
| return -1; |
| } |
| |
| if ( *rd == NULL ) |
| { |
| /* We allocate rd as big as d1. |
| * Note: Since _aif_diff can produce result which |
| * is bigger than its arguments, (eg: _aif_diff |
| * with STRINGS and POINTERS), we also need to |
| * keep track of the length of rd, and resize it |
| * when it's not enough. |
| */ |
| |
| char * temp1 = *f1; |
| char * temp2 = *d1; |
| int temp3 = 0; |
| |
| _fds_skip_data(&temp1, &temp2); |
| temp3 = temp2 - (*d1); |
| *rd = (char *)_aif_alloc(temp3); |
| datalen = temp3; |
| } |
| |
| if ( *rf == NULL ) |
| *rf = strdup(*f1); |
| |
| _fds_advance(f1); /* skip over the entire array fds */ |
| _fds_advance(f2); |
| |
| /* |
| ** If nel[12] > MAX_ADDRESS then we are not going to be |
| ** able to address all the data in the array. What should |
| ** we do? |
| */ |
| |
| currentlen = 0; /* start of our data result region */ |
| |
| for ( i = 0 ; i < ix1->i_nel ; i++ ) |
| { |
| int dl; |
| |
| if ( dres != NULL ) |
| { |
| _aif_free(dres); |
| dres = NULL; |
| } |
| |
| if ( fres != NULL ) |
| { |
| _aif_free(fres); |
| fres = NULL; |
| } |
| |
| fmt1 = ix1->i_btype; |
| fmt2 = ix2->i_btype; |
| |
| if ( _aif_diff(depth, &fres, &dres, &dl, &fmt1, d1, &fmt2, d2) < 0 ) |
| { |
| AIFArrayIndexFree(ix1); |
| AIFArrayIndexFree(ix2); |
| return -1; |
| } |
| |
| AIFArrayIndexInc(ix1); |
| AIFArrayIndexInc(ix2); |
| |
| /* Is the *rd large enough? */ |
| if (datalen < (currentlen + dl)) |
| { |
| *rd = _aif_resize(*rd, datalen + BUFSIZ); |
| datalen += BUFSIZ; |
| } |
| |
| memcpy(*rd + currentlen, dres, dl); |
| currentlen += dl; |
| } |
| |
| *rl = currentlen; |
| |
| { |
| /* we need to modify 'rf' because it is |
| * possible that _aif_diff returns something |
| * that has a different fds than the operands |
| */ |
| |
| char *t1, *t2; |
| int len; |
| |
| t1 = _fds_base_type(*rf); |
| |
| /* if it is multi-dimensional array, move t1 |
| * to the base type |
| */ |
| |
| while ( *t1 == FDS_ARRAY_START ) |
| t1 = _fds_base_type(t1); |
| |
| /* we want to keep the FDS_NAME */ |
| while ( *t1 == FDS_NAME ) |
| { |
| t1++; |
| t1 = (char *)_fds_skipnum(t1)+1; |
| } |
| |
| t2 = t1; |
| _fds_advance(&t2); |
| |
| len = strlen(fres); |
| memmove(t1, fres, len); |
| t1 += len; |
| |
| /* this part is necessary because it |
| * is possible that the array is part of a |
| * larger structure (ie: we don't want to cut |
| * the rest of the fds) |
| */ |
| if ( *t2 != '\0' ) |
| { |
| len = strlen(t2); |
| memmove(t1, t2, len+1); |
| } |
| else |
| *t1 = '\0'; |
| } |
| |
| _aif_free(fres); |
| _aif_free(dres); |
| |
| fmt = *rf; |
| _fds_advance(&fmt); |
| *fmt = '\0'; |
| |
| AIFArrayIndexFree(ix1); |
| AIFArrayIndexFree(ix2); |
| } |
| |
| return 0; |
| |
| /* only works with the public section in AIF_AGGREGATE */ |
| case AIF_AGGREGATE: |
| if ( FDSType(*f2) != AIF_AGGREGATE ) |
| { |
| SetAIFError(AIFERR_TYPE, NULL); |
| return -1; |
| } |
| |
| if ( AIFGetOption(AIFOPT_CMP_METHOD) == AIF_CMP_BY_NAME ) |
| { |
| cmp_by_name = 1; |
| f2_x1 = *f2; |
| d2_x1 = *d2; |
| f2_x2 = NULL; |
| d2_x2 = NULL; |
| _fds_skip_data(&f2_x1, &d2_x1); |
| if ( _fds_aggregate_arrange(*f1, *f2, *d2, &f2_x2, &d2_x2) < 0 ) |
| { |
| SetAIFError(AIFERR_CONV, NULL); |
| return -1; |
| } |
| *f2 = f2_x2; |
| *d2 = d2_x2; |
| /* at the end, we assign f2_x1 to f2, d2_x1 to d2, |
| ** and we free f2_x2 and d2_x2 */ |
| } |
| |
| if ( *rd == NULL ) |
| { |
| /* We allocate rd as big as d1. |
| * Note: Since _aif_diff can produce result which |
| * is bigger than its arguments, (eg: _aif_diff |
| * with STRINGS and POINTERS), we also need to |
| * keep track of the length of rd, and resize it |
| * when it's not enough. |
| */ |
| |
| char * temp1 = *f1; |
| char * temp2 = *d1; |
| int temp3 = 0; |
| |
| _fds_skip_data(&temp1, &temp2); |
| temp3 = temp2 - (*d1); |
| *rd = (char *)_aif_alloc(temp3); |
| datalen = temp3; |
| } |
| |
| if ( *rf == NULL ) |
| *rf = strdup(*f1); |
| |
| currentlen = 0; /* start of our data result region */ |
| |
| (*f1)++; /* past open brace */ |
| (*f2)++; /* past open brace */ |
| _fds_skip_typename(f1); |
| _fds_skip_typename(f2); |
| |
| while ( **f1 != ';' ) |
| { /* do one field */ |
| int dl; |
| char * dres = NULL; |
| char * fres = NULL; |
| |
| if (**f2 == ';') { /* f1 has more fields */ |
| SetAIFError(AIFERR_TYPE, NULL); |
| if (cmp_by_name == 1) |
| { |
| _aif_free(f2_x2); |
| _aif_free(d2_x2); |
| *f2 = f2_x1; |
| *d2 = d2_x1; |
| } |
| return -1; |
| } |
| |
| *f1 = strchr(*f1, FDS_AGGREGATE_FIELD_NAME_END) + 1; /* to start of field*/ |
| *f2 = strchr(*f2, FDS_AGGREGATE_FIELD_NAME_END) + 1; /* to start of field*/ |
| |
| fmt = *f1; |
| |
| if ( _aif_diff(depth, &fres, &dres, &dl, f1, d1, f2, d2) < 0 ) |
| { |
| if (cmp_by_name == 1) |
| { |
| _aif_free(f2_x2); |
| _aif_free(d2_x2); |
| *f2 = f2_x1; |
| *d2 = d2_x1; |
| } |
| return -1; /* non-zero res means no need to look further */ |
| } |
| |
| /* Is the *rd large enough? */ |
| if (datalen < (currentlen + dl)) |
| { |
| *rd = _aif_resize(*rd, datalen + BUFSIZ); |
| datalen += BUFSIZ; |
| } |
| |
| memcpy(*rd + currentlen, dres, dl); |
| currentlen += dl; |
| |
| { |
| char *t1, *t2; |
| int len; |
| |
| t1 = strstr(*rf, fmt); |
| t2 = t1; |
| _fds_advance(&t2); |
| |
| len = strlen(fres); |
| memmove(t1, fres, len); |
| t1 += len; |
| |
| if ( t1 != t2 ) |
| { |
| len = strlen(t2); |
| memmove(t1, t2, len+1); |
| } |
| } |
| |
| _aif_free(fres); |
| _aif_free(dres); |
| |
| if ( **f1 == ',' ) |
| (*f1)++; |
| |
| if ( **f2 == ',' ) |
| (*f2)++; |
| } /* one field */ |
| |
| *rl = currentlen; |
| |
| if ( **f2 != ';' ) |
| { /* f2 has more fields */ |
| if (cmp_by_name == 1) |
| { |
| _aif_free(f2_x2); |
| _aif_free(d2_x2); |
| *f2 = f2_x1; |
| *d2 = d2_x1; |
| } |
| SetAIFError(AIFERR_TYPE, NULL); |
| return -1; |
| } |
| |
| fmt = *rf; |
| _fds_advance(&fmt); |
| *fmt = '\0'; |
| |
| *f1 = strchr(*f1, '}') + 1; /* to start of field*/ |
| *f2 = strchr(*f2, '}') + 1; /* to start of field*/ |
| |
| if (cmp_by_name == 1) |
| { |
| _aif_free(f2_x2); |
| _aif_free(d2_x2); |
| *f2 = f2_x1; |
| *d2 = d2_x1; |
| } |
| return 0; |
| |
| case AIF_POINTER: |
| if ( FDSType(*f2) != AIF_POINTER ) |
| { |
| SetAIFError(AIFERR_TYPE, NULL); |
| return -1; |
| } |
| else |
| { |
| int ret; |
| int len; |
| |
| int t1 = _get_pointer_type(*d1); |
| int t2 = _get_pointer_type(*d2); |
| |
| if ( depth == -1 ) |
| { |
| if ( *rf == NULL ) |
| { |
| char *tmp2 = (t1 == AIF_PTR_NIL) ? *f1 : *f2; |
| char *tmp1 = tmp2; |
| _fds_advance(&tmp1); |
| len = tmp1 - tmp2; |
| *rf = _aif_alloc(sizeof(char)*len + 1); |
| strncpy(*rf, tmp2, len); |
| (*rf)[len] = '\0'; |
| } |
| |
| if ( *rd != NULL ) |
| _aif_free(*rd); |
| *rd = _aif_alloc(1); |
| *rl = 1; |
| **rd = AIF_PTR_NIL; |
| |
| _fds_skip_data(f1, d1); |
| _fds_skip_data(f2, d2); |
| |
| return 0; |
| |
| } |
| else if ( depth == 1 ) |
| depth = -1; |
| else if ( depth > 1 ) |
| depth--; |
| |
| /* |
| * Can't compute diff of invalid pointers |
| */ |
| if ( t1 == AIF_PTR_INVALID || t2 == AIF_PTR_INVALID ) |
| { |
| _fds_skip_data(f1, d1); |
| _fds_skip_data(f2, d2); |
| |
| SetAIFError(AIFERR_ARITH, NULL); |
| |
| return -1; |
| } |
| |
| if ( t1 == AIF_PTR_REFERENCE || |
| t2 == AIF_PTR_REFERENCE ) |
| { |
| if ( *rf == NULL ) |
| { |
| char *tmp2 = (t1==AIF_PTR_REFERENCE)? *f1 : *f2; |
| char *tmp1 = tmp2; |
| _fds_advance(&tmp1); |
| len = tmp1 - tmp2; |
| *rf = _aif_alloc(sizeof(char)*len + 1); |
| strncpy(*rf, tmp2, len); |
| (*rf)[len] = '\0'; |
| } |
| |
| if ( *rd != NULL ) |
| _aif_free(*rd); |
| *rd = _aif_alloc(5); /* 1 + 4 (ptr name) */ |
| *rl = 5; |
| |
| if (t1 == AIF_PTR_REFERENCE) { |
| memcpy(*rd, d1, 5); |
| } else { |
| memcpy(*rd, d2, 5); |
| } |
| |
| _fds_skip_data(f1, d1); |
| _fds_skip_data(f2, d2); |
| |
| return 0; |
| } |
| |
| /* |
| * target1 is null, make target2 as the result |
| */ |
| if ( t1 == AIF_PTR_NIL ) |
| { |
| if ( *rf == NULL ) |
| { |
| char * tmp_f = *f2; |
| _fds_advance(&tmp_f); |
| len = tmp_f - *f2; |
| *rf = _aif_alloc(sizeof(char)*len + 1); |
| strncpy(*rf, *f2, len); |
| (*rf)[len] = '\0'; |
| } |
| |
| if ( *rd != NULL ) |
| _aif_free(*rd); |
| |
| { |
| char * tmp_d = *d2; |
| _fds_skip_data(f2, d2); |
| len = *d2 - tmp_d; |
| *rd = _aif_alloc(sizeof(char)*len); |
| *rl = len; |
| memcpy(*rd, tmp_d, len); |
| } |
| |
| _fds_skip_data(f1, d1); |
| |
| return 0; |
| } |
| |
| /* |
| * target2 is null, make target1 as the result |
| */ |
| if ( t2 == AIF_PTR_NIL ) |
| { |
| if ( *rf == NULL ) |
| { |
| char * tmp_f = *f1; |
| _fds_advance(&tmp_f); |
| len = tmp_f - *f1; |
| *rf = _aif_alloc(sizeof(char)*len + 1); |
| strncpy(*rf, *f1, len); |
| (*rf)[len] = '\0'; |
| } |
| |
| if ( *rd != NULL ) |
| _aif_free(*rd); |
| |
| { |
| char * tmp_d = *d1; |
| _fds_skip_data(f1, d1); |
| len = *d1 - tmp_d; |
| *rd = _aif_alloc(sizeof(char)*len); |
| *rl = len; |
| memcpy(*rd, tmp_d, len); |
| } |
| |
| _fds_skip_data(f2, d2); |
| |
| return 0; |
| } |
| |
| /* |
| * Allocate space for new fds and data. |
| * FIXME: what if length > BUFSIZE! |
| */ |
| if ( *rf == NULL ) |
| { |
| *rf = _aif_alloc(BUFSIZ); |
| **rf = '\0'; |
| strcat(*rf, "^"); |
| } |
| |
| if ( *rd != NULL ) |
| _aif_free(*rd); |
| |
| char * res_data = *rd = (char *)_aif_alloc(BUFSIZ); |
| *res_data++ = (char) AIF_PTR_NORMAL; |
| |
| char *addr_fr = NULL; |
| char *addr_dr = NULL; |
| int addr_len; |
| |
| /* |
| * Skip to address |
| */ |
| (*f1)++; |
| *d1 += (t1 == AIF_PTR_NAME) ? 5 : 1; |
| (*f2)++; |
| *d2 += (t2 == AIF_PTR_NAME) ? 5 : 1; |
| |
| /* |
| * Calculate address difference |
| */ |
| ret = _aif_diff(0, &addr_fr, &addr_dr, &addr_len, f1, d1, f2, d2); |
| if (ret < 0) |
| return ret; |
| |
| /* |
| * Copy address fds and data to result |
| */ |
| strcat(*rf, addr_fr); |
| memcpy(res_data, addr_dr, addr_len); |
| res_data += addr_len; |
| |
| char * target_f = NULL; |
| char * target_d = NULL; |
| |
| /* |
| * Now calculate difference of target |
| */ |
| ret = _aif_diff(depth, &target_f, &target_d, rl, f1, d1, f2, d2); |
| if (ret < 0) |
| return ret; |
| |
| /* |
| * Copy target fds and result to result |
| */ |
| strcat(*rf, target_f); |
| memcpy(res_data, target_d, *rl); |
| |
| return ret; |
| |
| } |
| |
| case AIF_STRING: |
| if ( FDSType(*f2) != AIF_STRING ) |
| { |
| SetAIFError(AIFERR_TYPE, NULL); |
| return -1; |
| } |
| |
| (*f1)++; /* past "s" */ |
| (*f2)++; /* past "s" */ |
| |
| bytes1 = (*(*d1)++ & 0xff) << 8; |
| bytes1 += *(*d1)++ & 0xff; |
| bytes2 = (*(*d2)++ & 0xff) << 8; |
| bytes2 += *(*d2)++ & 0xff; |
| |
| if ( *rd != NULL ) |
| _aif_free(*rd); |
| |
| *rd = _aif_alloc(bytes1 + bytes2 + 2); |
| *rl = bytes1 + bytes2 + 2; |
| |
| if ( bytes1 == bytes2 ) |
| { |
| int i; |
| int is_equal = 1; |
| |
| (*rd)[0] = (bytes1 >> 8) & 0xff; |
| (*rd)[1] = bytes1 & 0xff; |
| |
| for (i=0; i<bytes1; i++) |
| { |
| if ( strncmp((*d1)+i, (*d2)+i, 1) ) |
| { |
| (*rd)[2+i] = '1'; |
| is_equal = 0; |
| } |
| else |
| (*rd)[2+i] = '0'; |
| } |
| |
| if ( is_equal == 1 ) |
| { |
| (*rd)[0] = (0 >> 8) & 0xff; |
| (*rd)[1] = 0 & 0xff; |
| } |
| } |
| else if ( bytes1 > bytes2 ) |
| { |
| int i; |
| |
| (*rd)[0] = (bytes1 >> 8) & 0xff; |
| (*rd)[1] = bytes1 & 0xff; |
| |
| for ( i = 0 ; i < bytes2 ; i++ ) |
| (*rd)[2+i] = strncmp((*d1)+i, (*d2)+i, 1) ? '1' : '0'; |
| for ( i = 0 ; i < bytes1 - bytes2 ; i++ ) |
| (*rd)[bytes2+2+i] = '1'; |
| |
| } |
| else if ( bytes1 < bytes2 ) |
| { |
| int i; |
| |
| (*rd)[0] = (bytes2 >> 8) & 0xff; |
| (*rd)[1] = bytes2 & 0xff; |
| |
| for ( i = 0 ; i < bytes1 ; i++ ) |
| (*rd)[2+i] = strncmp((*d1)+i, (*d2)+i, 1) ? '1' : '0'; |
| for ( i = 0 ; i < bytes2 - bytes1 ; i++ ) |
| (*rd)[bytes1+2+i] = '1'; |
| |
| } |
| |
| *d1 += bytes1; |
| *d2 += bytes2; |
| |
| if ( *rf == NULL ) |
| *rf = strdup(AIF_STRING_TYPE()); |
| |
| return 0; |
| |
| default: |
| SetAIFError(AIFERR_TYPE, NULL); |
| return -1; |
| } |
| } |
| |
| |
| |
| |
| |
| |
| |