blob: 294845b3757e28dc6599ef84cbacefec79f526e4 [file] [log] [blame]
/*
* Routines dealing with format descriptor strings (FDS).
*
* 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 <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include "aif.h"
#include "aiferr.h"
#include "aifint.h"
static char _fds_type_str[NUM_AIF_TYPES][12] =
{
{ FDS_INVALID, '%', 'd', FDS_INVALID, '\0' },
{ FDS_INTEGER, '%', 'c', '%', 'd', '\0' },
{ FDS_FLOATING, '%', 'd', '\0' },
{ FDS_POINTER, '%', 's', '%', 's', '\0' },
{ FDS_ARRAY_START, '%', 's', FDS_ARRAY_END, '%', 's', '\0' },
{ FDS_STRUCT_START, '%', 's', FDS_ID, ';', ';', ';', FDS_STRUCT_END, '\0' },
{ FDS_UNION_START, '%', 's', FDS_ID, FDS_UNION_END, '\0' },
{ FDS_FUNCTION, FDS_FUNCTION_ARG_END, '%', 's', '\0' },
{ FDS_VOID, '%', 'd', '\0' },
{ FDS_REGION, '%', 'd', '%', 's', '\0' },
{ '%', FDS_NAME, '%', 'd', FDS_NAME_END, '%', 's', '\0' },
{ FDS_REFERENCE, '%', 'd', FDS_REFERENCE_END, '\0' },
{ FDS_STRING, '\0' },
{ FDS_CHARACTER, '\0' },
{ FDS_RANGE, '%', 'd',
FDS_RANGE_SEP, FDS_RANGE_SEP,
'%', 'd', '%', 's', '\0' },
{ FDS_ENUM_START, '%', 's', FDS_ID, FDS_ENUM_END, FDS_INTEGER, '%', 'c', '4', '\0' },
{ FDS_BOOLEAN, '%', 'd', '\0' },
{ FDS_ADDRESS, '%', 'd', '\0' },
{ FDS_CHAR_POINTER, '%', 's', '\0' }
};
static char _fds_array_end[] = {FDS_ARRAY_END, '\0'};
static char _fds_function_arg_end[] = {FDS_FUNCTION_ARG_END, '\0'};
static char _fds_name_end[] = {FDS_NAME_END, '\0'};
static char _fds_enum_end[] = {FDS_ENUM_END, '\0'};
static char _fds_enum_const_name_end[] = {FDS_ENUM_SEP, '\0' };
static char _fds_enum_const_end[] = { FDS_ENUM_CONST_SEP, FDS_ENUM_END, '\0' };
static char _fds_struct_access_sep[] = {FDS_STRUCT_ACCESS_SEP, '\0'};
static char _fds_struct_field_name_end[] = {FDS_STRUCT_FIELD_NAME_END, '\0' };
static char _fds_struct_field_end[] = { FDS_STRUCT_ACCESS_SEP, FDS_STRUCT_FIELD_SEP, FDS_STRUCT_END, '\0' };
static char _fds_union_field_name_end[] = {FDS_UNION_FIELD_NAME_END, '\0' };
static char _fds_union_field_end[] = { FDS_UNION_FIELD_SEP, FDS_UNION_END, '\0' };
static char _fds_buf[BUFSIZ];
char *
_fds_skipnum(char *str)
{
if ( str == NULL )
return NULL;
while ( *str != '\0' && isdigit((int)*str) )
str++;
return str;
}
char *
_fds_skipto(char *str, char *set)
{
char * s;
if ( str == NULL )
return NULL;
for ( ; *str != '\0' ; str++ )
{
if
(
*str == FDS_STRUCT_START
||
*str == FDS_UNION_START
||
*str == FDS_ARRAY_START
||
*str == FDS_ENUM_START
)
{
str = _fds_skiptomatch(str);
str++;
}
for ( s = set ; *s != '\0' ; s++ )
if ( *s == *str )
return str;
}
return str;
}
/*
* Convert an ascii number to a number. NOTE: silently truncates
* the number to fit in sizeof int.
*/
int
_fds_getnum(char *str)
{
int n;
char * p;
char * t;
p = _fds_skipnum(str);
if ( *p == '\0' )
return strtoul(str, NULL, 10);
n = p - str;
t = (char *)_aif_alloc(n + 1);
memcpy(t, str, n);
t[n] = '\0';
n = strtoul(t, NULL, 10);
_aif_free(t);
return n;
}
int
FDSType(char *str)
{
int type;
if
(
str == NULL
||
*str == '\0'
)
return AIF_INVALID;
switch ( *str )
{
case FDS_BOOLEAN: /* boolean */
type = AIF_BOOLEAN;
break;
case FDS_CHARACTER: /* character */
type = AIF_CHARACTER;
break;
case FDS_INTEGER: /* integer */
type = AIF_INTEGER;
break;
case FDS_FLOATING: /* floating */
type = AIF_FLOATING;
break;
case FDS_POINTER: /* pointer */
type = AIF_POINTER;
break;
case FDS_ARRAY_START: /* array */
type = AIF_ARRAY;
break;
case FDS_STRUCT_START: /* struct */
type = AIF_STRUCT;
break;
case FDS_UNION_START: /* union */
type = AIF_UNION;
break;
case FDS_ENUM_START: /* enumeration */
type = AIF_ENUM;
break;
case FDS_RANGE: /* range */
type = AIF_INTEGER;
break;
case FDS_FUNCTION: /* function */
type = AIF_FUNCTION;
break;
case FDS_STRING: /* string */
type = AIF_STRING;
break;
case FDS_CHAR_POINTER: /* char pointer */
type = AIF_CHAR_POINTER;
break;
case FDS_ADDRESS: /* address */
type = AIF_ADDRESS;
break;
case FDS_VOID: /* void */
type = AIF_VOID;
break;
case FDS_REGION: /* ZPL region */
type = AIF_REGION;
break;
case FDS_NAME: /* named component */
type = AIF_NAME;
break;
case FDS_REFERENCE: /* reference to named component*/
type = AIF_REFERENCE;
break;
default:
type = AIF_INVALID;
}
return type;
}
/* extracts the base type of a pointer or array type, specified by the */
/* type descriptor. */
char *
FDSBaseType(char *type)
{
do
{
if ( (type = _fds_base_type(type)) == NULL )
return NULL;
}
while ( FDSType(type) == AIF_ARRAY || FDSType(type) == AIF_POINTER );
return type;
}
char *
_fds_base_type(char *type)
{
char * p;
if ( type == NULL || *type == '\0' )
return NULL;
switch ( *type++ )
{
case FDS_FUNCTION: /* function */
p = _fds_skipto(type, _fds_function_arg_end);
p++;
break;
case FDS_POINTER: /* pointer */
_fds_advance(&type); /* skip address */
p = type;
break;
case FDS_ARRAY_START: /* array */
p = _fds_skipto(type, _fds_array_end);
p++;
break;
case FDS_ENUM_START: /* enum */
p = _fds_skipto(type, _fds_enum_end);
p++;
break;
case FDS_RANGE: /* range */
p = _fds_skipnum(type); /* skip MinValue */
p += 2; /* skip '..' */
p = _fds_skipnum(p); /* skip MaxValue */
break;
case FDS_REGION: /* region */
p = type + 1; /* skip FDS_REGION Rank */
break;
default:
return NULL;
}
return p;
}
/* In AIF, we can find out about the size of the AIF object by looking at the
* AIF_LEN(), but this method cannot be used to find out about the size
* of each individual element in a struct. To overcome this problem, we can use
* FDSTypeSize() with the FDS for each element.
*
* However, FDSTypeSize() cannot be used to know the real size if the struct
* contains references or strings (since we also need to access the data to
* know the size of these data types).
*
* We use FDSDataSize() to overcome the limitation of FDSTypeSize(). It can
* access FDS and the data of an AIF object to calculate the (real) size of
* the data.
*/
int
FDSDataSize(char *fds, char *data)
{
char * tmp1 = fds;
char * tmp2 = data;
ResetAIFError();
_fds_skip_data(&tmp1, &tmp2);
if ( AIFError() == AIFERR_NOERR )
return (tmp2-data);
else
return -1;
}
/*
* Gets the size of a type in bytes, specified by the type descriptor.
* If the size cannot fit in a int, then it is silently truncated.
* returns size if successful, -1 otherwise.
*
* Note: we no longer know the size of structs or unions so these are
* always -1.
*/
int
FDSTypeSize(char *type)
{
int s;
int min;
int max;
int rank;
int size;
int subsize;
if ( type == NULL || *type == '\0' )
return -1;
switch ( *type )
{
case FDS_ADDRESS:
case FDS_BOOLEAN: /* boolean */
return _fds_getnum(type + 1);
case FDS_CHARACTER: /* character */
return 1;
case FDS_INTEGER: /* integer */
return _fds_getnum(type + 2);
case FDS_REFERENCE: /* reference use */
return 0;
case FDS_NAME: /* named component */
return FDSTypeSize(strchr(type, FDS_NAME_END) + 1);
case FDS_FUNCTION: /* function */
return FDSTypeSize(strchr(type, FDS_FUNCTION_ARG_END) + 1);
case FDS_POINTER: /* pointer */
return FDSTypeSize(type+1);
case FDS_FLOATING: /* floating */
case FDS_VOID: /* void */
return _fds_getnum(type + 1);
case FDS_STRUCT_START: /* struct */
type++; /* past open brace */
size = 0;
subsize = 0;
_fds_skipid(&type);
while ( *type != FDS_STRUCT_END )
{
if ( *type == FDS_STRUCT_ACCESS_SEP )
{
type++;
continue;
}
type = strchr(type, FDS_STRUCT_FIELD_NAME_END) + 1;
/* to start of field */
if ( (subsize = FDSTypeSize(type)) < 0 )
return -1;
size += subsize;
_fds_advance(&type);
if ( *type == FDS_STRUCT_FIELD_SEP )
type++;
}
return size;
case FDS_UNION_START:
type++; /* past open brace */
size = 0;
subsize = 0;
_fds_skipid(&type);
while ( *type != FDS_UNION_END )
{
type = strchr(type, FDS_UNION_FIELD_NAME_END) + 1;
/* to start of field */
if ( (subsize = FDSTypeSize(type)) < 0 )
return -1;
if ( subsize > size )
size = subsize;
_fds_advance(&type);
if ( *type == FDS_UNION_FIELD_SEP )
type++;
}
return size;
case FDS_ARRAY_START: /* array */
if ( (s = FDSTypeSize(_fds_base_type(type))) < 0 )
return -1;
min = _fds_array_min_index(type);
max = _fds_array_max_index(type);
return s * (max - min + 1);
case FDS_ENUM_START: /* enumeration */
return 4; /* all enumerations are based on 4-byte integers */
case FDS_RANGE: /* range */
return FDSTypeSize(_fds_base_type(type));
case FDS_REGION: /* region */
rank = _fds_getnum(type + 1);
s = FDSTypeSize(_fds_base_type(type));
return rank * s * 2;
case FDS_CHAR_POINTER:
case FDS_STRING:
default:
return -1;
}
/* NOT REACHED */
}
int
FDSIsSigned(char *fds)
{
if ( *fds++ == FDS_INTEGER )
return (int)(*fds == FDS_INTEGER_SIGNED);
return 0;
}
/*
* We support nested calls to TypeToFDS() by making a copy of any
* string arguments before overwriting the static buffer. e.g.
*
* TypeToFDS(AIF_ARRAY,
* TypeToFDS(AIF_RANGE, 0, 10,
* TypeToFDS(AIF_INTEGER, 4)
* ),
* TypeToFDS(AIF_INTEGER, 10)
* );
*/
char *
TypeToFDS(int type, ...)
{
va_list args;
int v1;
int v2;
char * v3;
char * v4;
if ( type < 0 || type >= NUM_AIF_TYPES )
type = AIF_INVALID;
va_start(args, type);
switch ( type )
{
case AIF_INTEGER:
v1 = va_arg(args, int);
v2 = va_arg(args, int);
snprintf(_fds_buf, BUFSIZ-1, _fds_type_str[type], v1 ? FDS_INTEGER_SIGNED : FDS_INTEGER_UNSIGNED, v2);
break;
case AIF_FLOATING:
case AIF_VOID:
case AIF_REFERENCE:
v1 = va_arg(args, int);
snprintf(_fds_buf, BUFSIZ-1, _fds_type_str[type], v1);
break;
case AIF_POINTER:
v3 = va_arg(args, char *);
if (v3 == NULL)
v3 = strdup("x");
else
v3 = strdup(v3);
v4 = strdup(va_arg(args, char *));
snprintf(_fds_buf, BUFSIZ-1, _fds_type_str[type], v3, v4);
_aif_free(v3);
_aif_free(v4);
break;
case AIF_FUNCTION:
v3 = strdup(va_arg(args, char *));
snprintf(_fds_buf, BUFSIZ-1, _fds_type_str[type], v3);
_aif_free(v3);
break;
case AIF_ENUM:
v3 = va_arg(args, char *);
if (v3 == NULL)
v3 = strdup("");
else
v3 = strdup(v3);
v1 = va_arg(args, int);
snprintf(_fds_buf, BUFSIZ-1, _fds_type_str[type], v3, v1 ? FDS_INTEGER_SIGNED : FDS_INTEGER_UNSIGNED);
_aif_free(v3);
break;
case AIF_CHAR_POINTER:
v3 = strdup(va_arg(args, char *));
snprintf(_fds_buf, BUFSIZ-1, _fds_type_str[type], v3);
_aif_free(v3);
break;
case AIF_ADDRESS:
case AIF_BOOLEAN:
v1 = va_arg(args, int);
snprintf(_fds_buf, BUFSIZ-1, _fds_type_str[type], v1);
break;
case AIF_STRING:
case AIF_CHARACTER:
strcpy(_fds_buf, _fds_type_str[type]);
break;
case AIF_STRUCT:
case AIF_UNION:
v3 = va_arg(args, char *);
if (v3 == NULL)
v3 = strdup("");
else
v3 = strdup(v3);
snprintf(_fds_buf, BUFSIZ-1, _fds_type_str[type], v3);
_aif_free(v3);
break;
case AIF_RANGE:
v1 = va_arg(args, int);
v2 = va_arg(args, int);
v3 = strdup(va_arg(args, char *));
snprintf(_fds_buf, BUFSIZ-1, _fds_type_str[type], v1, v2, v3);
_aif_free(v3);
break;
case AIF_ARRAY:
v3 = strdup(va_arg(args, char *));
v4 = strdup(va_arg(args, char *));
snprintf(_fds_buf, BUFSIZ-1, _fds_type_str[type], v3, v4);
_aif_free(v3);
_aif_free(v4);
break;
case AIF_NAME:
case AIF_REGION:
v1 = va_arg(args, int);
v3 = va_arg(args, char *);
if ( v3 == NULL )
v3 = strdup("");
else
v3 = strdup(v3);
snprintf(_fds_buf, BUFSIZ-1, _fds_type_str[type], v1, v3);
_aif_free(v3);
break;
case AIF_INVALID:
default:
snprintf(_fds_buf, BUFSIZ-1, _fds_type_str[AIF_INVALID], 0);
}
va_end(args);
return _fds_buf;
}
int
FDSTypeCompare(char *f1, char *f2)
{
int n;
int res;
char * n1;
char * n2;
char * t1;
char * t2;
AIFIndex * ix1;
AIFIndex * ix2;
if ( *f1 == FDS_NAME )
{
f1 = _fds_skipto(f1, _fds_name_end);
f1++;
}
if ( *f2 == FDS_NAME )
{
f2 = _fds_skipto(f2, _fds_name_end);
f2++;
}
if ( FDSType(f1) != FDSType(f2) )
return 0;
switch ( FDSType(f1) )
{
case AIF_ENUM:
res = strcmp(f1, f2) == 0;
break;
case AIF_INTEGER:
case AIF_FLOATING:
case AIF_VOID:
case AIF_REGION:
case AIF_ADDRESS:
case AIF_BOOLEAN:
res = FDSTypeSize(f1) == FDSTypeSize(f2);
break;
case AIF_POINTER:
case AIF_FUNCTION:
res = FDSTypeCompare(FDSBaseType(f1), FDSBaseType(f2));
break;
case AIF_REFERENCE:
res = FDSType(f2) == FDSType(f1);
break;
case AIF_ARRAY:
ix1 = FDSArrayIndexInit(f1);
ix2 = FDSArrayIndexInit(f1);
if ( ix1->i_rank != ix2->i_rank )
{
AIFArrayIndexFree(ix1);
AIFArrayIndexFree(ix2);
return 0;
}
for ( n = 0 ; n < ix1->i_rank ; n++ )
{
if ( ix1->i_max[n] - ix1->i_min[n] != ix2->i_max[n] - ix2->i_min[n] )
{
AIFArrayIndexFree(ix1);
AIFArrayIndexFree(ix2);
return 0;
}
}
res = FDSTypeSize(ix1->i_btype) == FDSTypeSize(ix2->i_btype);
AIFArrayIndexFree(ix1);
AIFArrayIndexFree(ix2);
break;
case AIF_UNION:
case AIF_STRUCT:
if ( FDSNumFields(f1) != FDSNumFields(f2) )
{
res = 0;
break;
}
for ( n = 0 ; n < FDSNumFields(f1) ; n++ )
{
if
(
FDSStructFieldByNumber(f1, n, &n1, &t1) < 0
||
FDSStructFieldByNumber(f2, n, &n2, &t2) < 0
)
return 0;
_aif_free(n1);
_aif_free(n2);
if ( !FDSTypeCompare(t1, t2) )
{
_aif_free(t1);
_aif_free(t2);
return 0;
}
_aif_free(t1);
_aif_free(t2);
}
res = 1;
break;
case AIF_CHAR_POINTER:
case AIF_STRING:
case AIF_CHARACTER:
res = 1;
break;
default:
res = 0;
}
return res;
}
/************************************************************
********************** ARRAY ROUTINES **********************
************************************************************/
/* extracts the index type of an array type, specified by the */
/* type descriptor. */
/* index type descriptor is returned if a valid (not a NULL) pointer to */
/* char is passed as parameter. */
/* returns 0 if successful, -1 otherwise. */
char *
FDSArrayIndexType(char *type)
{
char * p;
char * pi;
char * index;
if
(
type == NULL
||
*type == '\0'
||
*type != FDS_ARRAY_START
||
*++type != FDS_RANGE
)
return NULL;
p = _fds_skipnum(++type); /* skip MinValue */
p += 2; /* skip '..' */
p = _fds_skipnum(p); /* skip MaxValue */
pi = p;
p = _fds_skipto(p, _fds_array_end);
*p = 0;
index = strdup(pi);
*p = FDS_ARRAY_END;
return index;
}
int
_fds_array_min_index(char *type)
{
if ( *++type != FDS_RANGE )
return -1;
return _fds_getnum(++type);
}
int
FDSArrayMinIndex(char *fds, int n)
{
while ( FDSType(fds) == AIF_ARRAY && n > 0 )
{
fds = _fds_base_type(fds);
n--;
}
return (n == 0) ? _fds_array_min_index(fds) : -1;
}
int
_fds_array_max_index(char *type)
{
char * p;
if ( *++type != FDS_RANGE )
return -1;
p = _fds_skipnum(++type); /* skip MinValue */
p += 2; /* skip '..' */
return _fds_getnum(p);
}
int
FDSArrayMaxIndex(char *fds, int n)
{
while ( FDSType(fds) == AIF_ARRAY && n > 0 )
{
fds = _fds_base_type(fds);
n--;
}
return (n == 0) ? _fds_array_max_index(fds) : -1;
}
/*
* Calculate the number of dimensions of an array.
*/
int
FDSArrayRank(char *fds)
{
int d = 0;
while ( FDSType(fds) == AIF_ARRAY )
{
fds = _fds_base_type(fds);
d++;
}
return d;
}
/*
* Calculate the total size of an array
*/
int
FDSArraySize(char *fds)
{
int min;
int max;
int size = 1;
while ( FDSType(fds) == AIF_ARRAY )
{
min = _fds_array_min_index(fds);
max = _fds_array_max_index(fds);
fds = _fds_base_type(fds);
size *= max - min + 1;
}
return size;
}
char *
FDSRangeInit(int min, int max)
{
return strdup(TypeToFDS(AIF_RANGE, min, max, "is4"));
}
char *
FDSArrayInit(int min, int max, char *btype)
{
char * res;
char * range = FDSRangeInit(min, max);
res = strdup(TypeToFDS(AIF_ARRAY, range, btype));
_aif_free(range);
return res;
}
/*
* Parse array type descriptor and extract the minimum and maximum
* array index values for each dimension. Also, if size is not NULL,
* will return the size of dimension.
*/
void
FDSArrayBounds(char *fds, int rank, int **min, int **max, int **size)
{
int i;
int * mn;
int * mx;
int * s=NULL;
*min = (int *)_aif_alloc(rank*sizeof(int));
*max = (int *)_aif_alloc(rank*sizeof(int));
if( size != NULL )
*size = (int *)_aif_alloc(rank*sizeof(int));
mn = *min;
mx = *max;
if ( size != NULL )
s = *size;
for ( i = 0 ; i < rank ; i++)
{
*mn = _fds_array_min_index(fds);
*mx = _fds_array_max_index(fds);
if ( size != NULL )
{
*s = *mx - *mn + 1;
s++;
}
fds = _fds_base_type(fds);
mn++;
mx++;
}
}
/*
* Extract info about an array. Returns the index type of the
* first dimension (assumes all dimensions are the same type),
* the element type of the array, and the number of dimensions
* of the array. It is the responsibility of the caller to free
* memory allocated to el.
*
*/
void
FDSArrayInfo(char *fds, int *rank, char **el, char **ix)
{
int d;
if ( ix != NULL )
*ix = FDSArrayIndexType(fds);
d = 0;
while ( FDSType(fds) == AIF_ARRAY )
{
fds = _fds_base_type(fds);
d++;
}
*el = strdup(fds);
*rank = d;
}
AIFIndex *
FDSArrayIndexInit(char *fmt)
{
int d;
int nel = 1;
int rank;
char * btype;
AIFIndex * ix;
FDSArrayInfo(fmt, &rank, &btype, NULL);
if ( rank == 0 )
return (AIFIndex *)NULL;
ix = (AIFIndex *)_aif_alloc(sizeof(AIFIndex));
ix->i_finished = 0;
ix->i_rank = rank;
ix->i_btype = btype;
ix->i_bsize = FDSTypeSize(ix->i_btype);
ix->i_index = (int *)_aif_alloc(ix->i_rank * sizeof(int));
FDSArrayBounds(fmt, ix->i_rank, &(ix->i_min), &(ix->i_max), (int **)NULL);
for ( d = ix->i_rank - 1 ; d >= 0 ; d-- )
{
nel *= ix->i_max[d] - ix->i_min[d] + 1;
ix->i_index[d] = ix->i_min[d];
}
ix->i_nel = nel;
return ix;
}
/************************************************************
********************** STRUCT ROUTINES **********************
************************************************************/
/*
* The fds of a struct has this format:
*
* {name|entry,...;entry,...;entry,...;entry,...}
*
* name is the name of the structure, or empty for an unnamed type
* each entry has the format "name=type"
* a structure comprises 4 sections seperated by ';', corresponding
* to public, private, protected and hidden members
*/
#define STRUCT_START(fds, res) \
if (*(fds) == FDS_NAME) { \
(fds) = _fds_skipto((fds), _fds_name_end); \
(fds)++; \
} \
if ( *(fds++) != FDS_STRUCT_START ) \
return (res); \
while ( *(fds) != FDS_ID ) \
(fds)++; \
(fds)++; \
if ( *(fds) == '\0' ) \
return (res); \
while ( *(fds) == FDS_STRUCT_ACCESS_SEP ) \
(fds)++; \
if ( *(fds) == FDS_STRUCT_END ) \
return (res);
char *
_fds_skiptomatch(char *fds)
{
char ender = NULL;
/*
** assert *fds == '{' or '['; find the matching '}' or ']'
*/
switch ( *fds )
{
case FDS_STRUCT_START:
ender = FDS_STRUCT_END;
break;
case FDS_ARRAY_START:
ender = FDS_ARRAY_END;
break;
case FDS_ENUM_START:
ender = FDS_ENUM_END;
break;
case FDS_UNION_START:
ender = FDS_UNION_END;
break;
}
fds++;
for ( ;; )
{
if ( *fds == ender )
return fds;
if
(
*fds == FDS_STRUCT_START
||
*fds == FDS_UNION_START
||
*fds == FDS_ARRAY_START
||
*fds == FDS_ENUM_START
)
fds = _fds_skiptomatch(fds);
fds++;
}
}
/*
* The function ignores access specifiers
*/
char *
_fds_skiptofield(char *fds, int n)
{
STRUCT_START(fds, NULL);
while ( *fds != '\0' && *fds != FDS_STRUCT_END && n > 0 )
{
if ( *fds == FDS_STRUCT_FIELD_SEP )
n--;
else if ( *fds == FDS_STRUCT_ACCESS_SEP )
{
if
(
*(fds+1) != FDS_STRUCT_ACCESS_SEP
&&
*(fds+1) != FDS_STRUCT_END
)
n--;
}
else if
(
*fds == FDS_STRUCT_START
||
*fds == FDS_UNION_START
||
*fds == FDS_ARRAY_START
||
*fds == FDS_ENUM_START
)
fds = _fds_skiptomatch(fds);
fds++;
}
if ( *fds == '\0' || *fds == FDS_STRUCT_END )
return NULL;
return fds;
}
/*
* The function ignores access specifiers, ie: total number of fields
*/
int
FDSNumFields(char *fds)
{
int n = 0;
if (*fds == FDS_NAME)
{
fds = _fds_skipto(fds, _fds_name_end);
fds++;
}
if ( *(fds++) != FDS_STRUCT_START )
return -1;
while ( *(fds) != FDS_ID )
(fds)++;
(fds)++;
if ( *fds == '\0' )
return -1;
while ( *fds == FDS_STRUCT_ACCESS_SEP )
(fds)++;
if ( *fds == FDS_STRUCT_END )
return 0;
while ( *fds != '\0' && *fds != FDS_STRUCT_END )
{
if ( *fds == FDS_STRUCT_FIELD_SEP )
n++;
else if ( *fds == FDS_STRUCT_ACCESS_SEP )
{
if
(
*(fds+1) != FDS_STRUCT_ACCESS_SEP
&&
*(fds+1) != FDS_STRUCT_END
)
n++;
}
else if
(
*fds == FDS_STRUCT_START
||
*fds == FDS_UNION_START
||
*fds == FDS_ARRAY_START
||
*fds == FDS_ENUM_START
)
fds = _fds_skiptomatch(fds);
fds++;
}
return n + 1;
}
/*
* Returns a newly alloced string for name and type
* The function ignores access specifiers
*/
int
FDSStructFieldByNumber(char *fds, int n, char **name, char **type)
{
if ( (fds = _fds_skiptofield(fds, n)) == NULL )
return -1;
if ( (*name = _field_attribute(fds, NULL, _fds_struct_field_name_end)) == NULL )
return -1;
if ( (*type = _field_attribute(fds, _fds_struct_field_name_end, _fds_struct_field_end)) == NULL )
return -1;
return 0;
}
/*
* Returns a newly alloced string for type
* The function ignores access specifiers
*/
int
FDSStructFieldByName(char *fds, char *name, char **type)
{
char * nm;
STRUCT_START(fds, -1);
while ( *fds != '\0' && *fds != FDS_STRUCT_END )
{
nm = fds;
fds = _fds_skipto(fds, _fds_struct_field_name_end);
if ( *fds == '\0' )
return -1;
*fds = '\0'; /* temporarily */
if ( strcmp(nm, name) == 0 )
{
*fds = FDS_STRUCT_FIELD_NAME_END;
if ( (*type = _field_attribute(
nm,
_fds_struct_field_name_end,
_fds_struct_field_end
)) == NULL )
return -1;
return 0;
}
else
*fds = FDS_STRUCT_FIELD_NAME_END;
fds = _fds_skipto(fds, _fds_struct_field_end);
fds++;
}
return -1;
}
/*
* Arrange the members of AIF struct defined by fds and data into a new_fds
* and a new_data so that the FDS looks like fdsref
*
* If number_of_members of fdsref > number_of_members of fds
* returns -1
* Else
* creates the new_fds and new_data accordingly and returns 0
*
* If fds got more members, the rest will be appended at the end, so
* fdsref can be thought of as a prefix of fds.
*
* The function only works with the public section.
* It does not change fdsref, fds and data.
* It allocates the memory for new_fds and new_data
*/
int
_fds_struct_arrange(char *fdsref, char *fds, char *data, char **new_fds, char **new_data)
{
char * ptr_fds = fds;
char * ptr_data = data;
int len_new_fds;
int len_new_data;
int number_fds = 0; /* number_of_members of fds */
int number_fdsref = 0; /* number_of_members of fdsref */
char * tmp;
int n;
char ** fds_members;
char ** data_members;
int * fds_members_len;
int * data_members_len;
int * fds_members_flag; /* to flag that the member has been copied */
/* calculate the number_of_members of fds and fdsref
** we do not use FDSNumFields() since we are only interested in the
** public section */
tmp = fds;
STRUCT_START(tmp, -1);
while ( *tmp != FDS_STRUCT_ACCESS_SEP )
{
tmp = strchr(tmp, FDS_STRUCT_FIELD_NAME_END) + 1;
if
(
*tmp == FDS_STRUCT_START || *tmp == FDS_UNION_START ||
*tmp == FDS_ARRAY_START || *tmp == FDS_ENUM_START
)
tmp = _fds_skiptomatch(tmp) + 1;
tmp = _fds_skipto(tmp, _fds_struct_field_end);
number_fds++;
}
tmp = fdsref;
STRUCT_START(tmp, -1);
while ( *tmp != FDS_STRUCT_ACCESS_SEP )
{
tmp = strchr(tmp, FDS_STRUCT_FIELD_NAME_END) + 1;
if
(
*tmp == FDS_STRUCT_START || *tmp == FDS_UNION_START ||
*tmp == FDS_ARRAY_START || *tmp == FDS_ENUM_START
)
tmp = _fds_skiptomatch(tmp) + 1;
tmp = _fds_skipto(tmp, _fds_struct_field_end);
number_fdsref++;
}
/* check for the number_of_member variables */
if ( number_fdsref > number_fds )
return -1;
/* allocate new_fds and new_data */
_fds_skip_data(&ptr_fds, &ptr_data);
len_new_fds = ptr_fds - fds;
len_new_data = ptr_data - data;
if (*new_fds == NULL)
*new_fds = _aif_alloc(len_new_fds);
if (*new_data == NULL)
*new_data = _aif_alloc(len_new_data);
/* we divide fds and data into several fields/members
** we store the pointers for easy retrieval */
fds_members = (char **) _aif_alloc(sizeof(char *) * number_fds);
fds_members_len = (int *) _aif_alloc(sizeof(int) * number_fds);
data_members = (char **) _aif_alloc(sizeof(char *) * number_fds);
data_members_len = (int *) _aif_alloc(sizeof(int) * number_fds);
fds_members_flag = (int *) _aif_alloc(sizeof(int) * number_fds);
ptr_fds = fds;
ptr_data = data;
STRUCT_START(ptr_fds, -1);
for (n=0; n<number_fds; n++)
{
fds_members[n] = ptr_fds;
data_members[n] = ptr_data;
ptr_fds = strchr(ptr_fds, FDS_STRUCT_FIELD_NAME_END) + 1;
_fds_skip_data(&ptr_fds, &ptr_data);
fds_members_len[n] = ptr_fds - fds_members[n];
data_members_len[n] = ptr_data - data_members[n];
fds_members_flag[n] = 0;
ptr_fds++;
}
/* we start building up the new_fds and new_data */
ptr_fds = fds;
STRUCT_START(ptr_fds, -1);
memcpy(*new_fds, fds, ptr_fds - fds); /* copy the id to the new_fds */
ptr_fds = *new_fds + (ptr_fds - fds);
ptr_data = *new_data;
tmp = fdsref;
STRUCT_START(tmp, -1);
while ( *tmp != FDS_STRUCT_ACCESS_SEP )
{
char endchar, *end;
if ( *tmp == FDS_STRUCT_FIELD_SEP ) tmp++;
end = tmp;
end = _fds_skipto(end, _fds_struct_field_end);
endchar = *end; /* we store *end since *end can be ',' or ';' */
*end = '\0'; /* temporarily */
for (n=0; n<number_fds; n++)
{
/* we check the fds_members_flag so the function can
** run faster for large data structures */
if ( fds_members_flag[n] == 0 )
{
/* tmp and fds_members[*] contain
** 'field_name=field_type', but we only want
** to compare field_name */
char * temp_a = strchr(tmp, FDS_STRUCT_FIELD_NAME_END);
char * temp_b = strchr(fds_members[n], FDS_STRUCT_FIELD_NAME_END);
int strcmp_res;
*temp_a = *temp_b = '\0'; /* temporarily */
strcmp_res = strcmp(tmp, fds_members[n]);
*temp_a = *temp_b = FDS_STRUCT_FIELD_NAME_END;
if (strcmp_res == 0)
break;
}
}
if (n == number_fds) /* not found, an error */
{
*end = endchar;
_aif_free(fds_members);
_aif_free(fds_members_len);
_aif_free(fds_members_flag);
_aif_free(data_members);
_aif_free(data_members_len);
_aif_free(*new_fds);
_aif_free(*new_data);
return -1;
}
memcpy(ptr_data, data_members[n], data_members_len[n]);
memcpy(ptr_fds, fds_members[n], fds_members_len[n]);
fds_members_flag[n] = 1;
ptr_data += data_members_len[n];
ptr_fds += fds_members_len[n];
*end = endchar;
*(ptr_fds++) = FDS_STRUCT_FIELD_SEP;
tmp = end;
}
/* copy members which have not been copied */
if ( number_fds > number_fdsref )
{
for (n=0; n<number_fds; n++)
{
if ( fds_members_flag[n] == 0 )
{
memcpy(ptr_data, data_members[n], data_members_len[n]);
memcpy(ptr_fds, fds_members[n], fds_members_len[n]);
ptr_data += data_members_len[n];
ptr_fds += fds_members_len[n];
*(ptr_fds++) = FDS_STRUCT_FIELD_SEP;
}
}
}
/* copy the rest of the fds to the new_fds */
ptr_fds--;
memcpy(ptr_fds, fds_members[number_fds-1] + fds_members_len[number_fds-1], len_new_fds - (ptr_fds - *new_fds));
_aif_free(fds_members);
_aif_free(fds_members_len);
_aif_free(fds_members_flag);
_aif_free(data_members);
_aif_free(data_members_len);
return 0;
}
int
FDSStructFieldSize(char *fds, char *name)
{
char *type;
int size;
if ( FDSStructFieldByName(fds, name, &type) )
{
SetAIFError(AIFERR_BADARG, NULL);
return -1;
}
size = FDSTypeSize(type);
_aif_free(type);
return size;
}
/*
* The function ignores access specifiers
* return value indicates the position of the field
* the counter starts at 0, ie: first element is at position 0
* if the field cannot be found, it returns -1
*/
int
FDSStructFieldIndex(char *fds, char *name)
{
int counter = 0;
int len;
char * nm;
STRUCT_START(fds, -1);
while ( *fds != '\0' && *fds != FDS_STRUCT_END )
{
nm = fds;
fds = _fds_skipto(fds, _fds_struct_field_name_end);
if ( *fds == '\0' )
return -1;
len = fds - nm;
if ( strncmp(nm, name, len) == 0 )
return counter;
counter++;
fds = _fds_skipto(fds, _fds_struct_field_end);
fds++;
}
return -1;
}
char *
FDSStructInit(char *id)
{
return strdup(TypeToFDS(AIF_STRUCT, id));
}
/*
* puts the new field in the public section
*/
char *
FDSAddFieldToStruct(char *fds, char *name, char *type)
{
return FDSAddFieldToClass(fds, AIFACC_PUBLIC, name, type);
}
int
FDSStructAdd(char **fds, char *name, char *type)
{
char * temp;
temp = FDSAddFieldToStruct(*fds, name, type);
if ( temp == NULL )
return -1;
_aif_free(*fds);
*fds = temp;
return 0;
}
/*
* returns the data length from field 0 until field n (inclusive)
*/
int
_data_len_index(char *fds, int n)
{
int size = 0;
int subsize = 0;
STRUCT_START(fds, -1);
while ( *fds != '\0' && *fds != FDS_STRUCT_END && n >= 0 )
{
if ( *fds == FDS_STRUCT_ACCESS_SEP )
{
fds++;
continue;
}
fds = _fds_skipto(fds, _fds_struct_field_name_end);
if ( *fds++ == '\0' )
return 0;
/* to start of field */
if ( (subsize = FDSTypeSize(fds)) < 0 )
return -1;
size += subsize;
n--;
_fds_advance(&fds);
if ( *fds == FDS_STRUCT_FIELD_SEP )
fds++;
}
return size;
}
int
_data_len_public(char *fds)
{
int size = 0;
int subsize = 0;
if (*(fds) == FDS_NAME) {
(fds) = _fds_skipto((fds), _fds_name_end);
(fds)++;
}
if ( *(fds++) != FDS_STRUCT_START )
return -1;
while ( *(fds) != FDS_ID )
(fds)++;
(fds)++;
if ( *(fds) == '\0' )
return -1;
if ( *(fds) == FDS_STRUCT_ACCESS_SEP )
return 0;
while ( *fds != FDS_STRUCT_END )
{
if ( *fds == FDS_STRUCT_ACCESS_SEP )
break;
fds = _fds_skipto(fds, _fds_struct_field_name_end);
if ( *fds++ == '\0' )
return 0;
/* to start of field */
if ( (subsize = FDSTypeSize(fds)) < 0 )
return -1;
size += subsize;
_fds_advance(&fds);
if ( *fds == FDS_STRUCT_FIELD_SEP )
fds++;
}
return size;
}
/*
* returns a pointer to a newly allocated structure
*/
char *
_field_attribute(char *s, char *starter, char *ender)
{
int len;
char * np;
char * _fds_field_attr; /* we alloc as needed */
if ( starter != NULL )
{
s = _fds_skipto(s, starter);
if ( *s++ == '\0' )
return NULL;
}
np = s;
s = _fds_skipto(s, ender);
if ( *s == '\0' )
return NULL;
len = s - np;
_fds_field_attr = _aif_alloc(len+1);
memcpy(_fds_field_attr, np, len);
_fds_field_attr[len] = '\0';
return _fds_field_attr;
}
#define ENUM_START(fds, res) \
if (*(fds) == FDS_NAME) { \
(fds) = _fds_skipto((fds), _fds_name_end); \
(fds)++; \
} \
if ( *(fds++) != FDS_ENUM_START ) \
return (res); \
while ( *(fds) != FDS_ID ) \
(fds)++; \
(fds)++; \
if ( *(fds) == '\0' || *(fds) == FDS_ENUM_END ) \
return (res);
/* based on the fds and the enum value,
* the function gives the enum name (string),
* it allocs the string for the caller */
int
FDSEnumConstByValue(char *fds, char **name, int val)
{
int len;
char * nm;
ENUM_START(fds, -1);
while ( *fds != '\0' && *fds != FDS_ENUM_END )
{
nm = fds;
fds = _fds_skipto(fds, _fds_enum_const_name_end);
if ( *fds == '\0' )
return -1;
len = fds - nm;
fds++;
if ( val == _fds_getnum(fds) )
{
*name = _aif_alloc(len + 1);
**name = '\0';
strncat(*name, nm, len);
return 0;
}
fds = _fds_skipto(fds, _fds_enum_const_end);
fds++;
}
return -1;
}
/* based on the fds and the enum name (string),
* the function gives the enum value */
int
FDSEnumConstByName(char *fds, char *name, int *val)
{
int len;
char * nm;
ENUM_START(fds, -1);
while ( *fds != '\0' && *fds != FDS_ENUM_END )
{
nm = fds;
fds = _fds_skipto(fds, _fds_enum_const_name_end);
if ( *fds == '\0' )
return -1;
len = fds - nm;
if ( strncmp(nm, name, len) == 0 )
{
fds++;
*val = _fds_getnum(fds);
return 0;
}
fds = _fds_skipto(fds, _fds_enum_const_end);
fds++;
}
return -1;
}
char *
FDSEnumInit(char *id)
{
return strdup(TypeToFDS(AIF_ENUM, id, 1));
}
char *
FDSAddConstToEnum(char *fds, char *name, int val)
{
int v;
char * nfmt;
char * end;
char field[BUFSIZ];
if ( FDSEnumConstByName(fds, name, &v) == 0 )
{
SetAIFError(AIFERR_BADARG, NULL);
return NULL;
}
/* XXX TODO
if ( FDSEnumFieldByValue(fds, name, &nfmt) == 0 )
{
SetAIFError(AIFERR_BADARG, NULL);
_aif_free(nfmt);
return NULL;
}
*/
snprintf(field, BUFSIZ, "%s%c%d", name, FDS_ENUM_SEP, val);
nfmt = (char *)_aif_alloc(strlen(fds) + strlen(field) + 2);
*nfmt = '\0';
strcpy(nfmt, fds);
if
(
(end = strrchr(nfmt, FDS_ENUM_END)) == NULL
||
end - nfmt < 1
)
{
SetAIFError(AIFERR_BADARG, NULL);
return NULL;
}
if ( *(end-1) != FDS_ID )
*end++ = FDS_ENUM_CONST_SEP;
sprintf(end, "%s%s", field, strrchr(fds, FDS_ENUM_END));
ResetAIFError();
return nfmt;
}
int
FDSEnumAdd(char **fds, char *name, int val)
{
char * temp;
temp = FDSAddConstToEnum(*fds, name, val);
if ( temp == NULL )
return -1;
_aif_free(*fds);
*fds = temp;
return 0;
}
#define UNION_START(fds, res) \
if (*(fds) == FDS_NAME) { \
(fds) = _fds_skipto((fds), _fds_name_end); \
(fds)++; \
} \
if ( *(fds++) != FDS_UNION_START ) \
return (res); \
while ( *(fds) != FDS_ID ) \
(fds)++; \
(fds)++; \
if ( *(fds) == '\0' || *(fds) == FDS_UNION_END ) \
return (res);
int
FDSUnionFieldByName(char *fds, char *name, char **type)
{
int len;
char * nm;
UNION_START(fds, -1);
while ( *fds != '\0' && *fds != FDS_UNION_END )
{
nm = fds;
fds = _fds_skipto(fds, _fds_union_field_name_end);
if ( *fds == '\0' )
return -1;
len = fds - nm;
if ( strncmp(nm, name, len) == 0 )
{
fds++;
nm = fds;
fds = _fds_skipto(fds, _fds_union_field_end);
if ( *fds == '\0' )
return -1;
len = fds - nm;
*type = _aif_alloc(len+1);
strncpy(*type, nm, len);
(*type)[len] = '\0';
return 0;
}
fds = _fds_skipto(fds, _fds_union_field_end);
fds++;
}
return -1;
}
char *
FDSUnionInit(char *id)
{
return strdup(TypeToFDS(AIF_UNION, id));
}
char *
FDSAddFieldToUnion(char *fds, char *name, char *type)
{
char * nfmt;
char * end;
char field[BUFSIZ];
char * dummy;
if ( FDSUnionFieldByName(fds, name, &dummy) == 0 )
{
SetAIFError(AIFERR_BADARG, NULL);
return NULL;
}
/* XXX TODO
if ( FDSEnumFieldByValue(fds, name, &nfmt) == 0 )
{
SetAIFError(AIFERR_BADARG, NULL);
_aif_free(nfmt);
return NULL;
}
*/
snprintf(field, BUFSIZ, "%s%c%s", name, FDS_UNION_FIELD_NAME_END, type);
nfmt = (char *)_aif_alloc(strlen(fds) + strlen(field) + 2);
*nfmt = '\0';
strcpy(nfmt, fds);
if
(
(end = strrchr(nfmt, FDS_UNION_END)) == NULL
||
end - nfmt < 1
)
{
SetAIFError(AIFERR_BADARG, NULL);
return NULL;
}
if ( *(end-1) != FDS_ID )
*end++ = FDS_UNION_FIELD_SEP;
sprintf(end, "%s%c", field, FDS_UNION_END);
ResetAIFError();
return nfmt;
}
int
FDSUnionAdd(char **fds, char *name, char *type)
{
char * temp;
temp = FDSAddFieldToUnion(*fds, name, type);
if ( temp == NULL )
return -1;
_aif_free(*fds);
*fds = temp;
return 0;
}
char *
FDSClassInit(char *id)
{
return FDSStructInit(id);
}
/*
* returns a newly alloced string for name and type
*/
int
FDSClassFieldByName(char *fds, char *name, char **type)
{
return FDSStructFieldByName(fds, name, type);
}
/*
* returns a newly alloced string for name and type
*/
int
FDSClassFieldByNumber(char *fds, int n, char **name, char **type)
{
return FDSStructFieldByNumber(fds, n, name, type);
}
/*
* The function ignores access specifiers
* return value indicates the position of the field
* the counter starts at 0, ie: first element is at position 0
* if the field cannot be found, it returns -1
*/
int
FDSClassFieldIndex(char *fds, char *name)
{
return FDSStructFieldIndex(fds, name);
}
int
FDSClassFieldSize(char *fds, char *name)
{
return FDSStructFieldSize(fds, name);
}
char *
FDSAddFieldToClass(char *fds, aifaccess acc, char *name, char *type)
{
char * temp;
char * nfmt;
char * end;
char * rest;
if ( FDSClassFieldByName(fds, name, &nfmt) == 0 )
{
SetAIFError(AIFERR_BADARG, NULL);
_aif_free(nfmt);
return NULL;
}
nfmt = (char *)_aif_alloc(strlen(fds) + strlen(name) + strlen(type) +3);
*nfmt = '\0';
strcpy(nfmt, fds);
temp = nfmt;
if (*(fds) == FDS_NAME) {
(fds) = _fds_skipto((fds), _fds_name_end);
(fds)++;
}
if (*(temp) == FDS_NAME) {
(temp) = _fds_skipto((temp), _fds_name_end);
(temp)++;
}
if
(
(end = _fds_skipto(temp+1, _fds_struct_access_sep)) == NULL
||
end - temp < 1
)
{
SetAIFError(AIFERR_BADARG, NULL);
_aif_free(nfmt);
return NULL;
}
rest = _fds_skipto(fds+1, _fds_struct_access_sep);
switch ( acc )
{
case AIFACC_PRIVATE:
end = _fds_skipto(++end, _fds_struct_access_sep);
if ( end == NULL )
{
SetAIFError(AIFERR_BADARG, NULL);
_aif_free(nfmt);
return NULL;
}
rest = _fds_skipto(++rest, _fds_struct_access_sep);
/* fall through */
case AIFACC_PROTECTED:
end = _fds_skipto(++end, _fds_struct_access_sep);
if ( end == NULL )
{
SetAIFError(AIFERR_BADARG, NULL);
_aif_free(nfmt);
return NULL;
}
rest = _fds_skipto(++rest, _fds_struct_access_sep);
/* fall through */
case AIFACC_PUBLIC:
break;
}
if ( *(end-1) != FDS_ID && *(end-1) != FDS_STRUCT_ACCESS_SEP )
*end++ = FDS_STRUCT_FIELD_SEP;
sprintf(end, "%s%c%s%s",
name,
FDS_STRUCT_FIELD_NAME_END,
type,
rest);
ResetAIFError();
return nfmt;
}
int
FDSClassAdd(char **fds, aifaccess acc, char *name, char *type)
{
char * temp;
temp = FDSAddFieldToClass(*fds, acc, name, type);
if ( temp == NULL )
return -1;
_aif_free(*fds);
*fds = temp;
return 0;
}
int
FDSSetIdentifier(char **fds, char *id)
{
int id_len;
char * temp;
char * new;
temp = *fds;
id_len = strlen(id);
new = _aif_alloc( strlen(*fds) + strlen(id) + 1 );
*new = '\0';
if ( *temp == FDS_NAME )
{
temp = _fds_skipto(temp, _fds_name_end);
temp++;
strncat(new, *fds, temp - *fds);
}
if ( *temp == FDS_UNION_START ||
*temp == FDS_STRUCT_START ||
*temp == FDS_ENUM_START )
{
if ( *(temp+1) != FDS_ID )
{
_aif_free(new);
SetAIFError(AIFERR_BADARG, NULL);
return -1;
}
strncat(new, temp, 1);
strncat(new, id, id_len);
strcat(new, temp+1);
_aif_free(*fds);
*fds = new;
return 0;
}
else
{
_aif_free(new);
SetAIFError(AIFERR_BADARG, NULL);
return -1;
}
}
char *
FDSGetIdentifier(char *fds)
{
char *temp;
char *id;
int id_len;
if ( *fds == FDS_NAME )
{
fds = _fds_skipto(fds, _fds_name_end);
fds++;
}
if ( *fds == FDS_UNION_START ||
*fds == FDS_STRUCT_START ||
*fds == FDS_ENUM_START )
{
fds++;
if ( *fds == FDS_ID )
{
SetAIFError(AIFERR_BADARG, NULL);
return NULL;
}
temp = fds;
fds = strchr(fds, FDS_ID);
id_len = fds - temp;
id = _aif_alloc( id_len + 1 );
*id = '\0';
strncat(id, temp, id_len);
return id;
}
else
{
SetAIFError(AIFERR_BADARG, NULL);
return NULL;
}
}
void
_fds_advance(char **fds)
{
switch ( FDSType((*fds)++) )
{
case AIF_ADDRESS:
case AIF_BOOLEAN:
*fds = _fds_skipnum(*fds);
break;
case AIF_ENUM:
_fds_skipid(fds);
*fds = _fds_skipto(*fds, _fds_enum_end);
(*fds) += 2;
/* fall through */
case AIF_INTEGER:
*fds += 1; /* u or s */
*fds = _fds_skipnum(*fds);
break;
case AIF_FLOATING:
case AIF_VOID:
*fds = _fds_skipnum(*fds);
break;
case AIF_FUNCTION:
while ( *(*fds)++ != FDS_FUNCTION_ARG_END )
;
_fds_advance(fds);
break;
case AIF_ARRAY:
while ( *(*fds)++ != FDS_ARRAY_END )
; /* past the index type */
_fds_advance(fds); /* past the base type */
break;
case AIF_UNION:
case AIF_STRUCT:
_fds_skipid(fds);
for ( ;; ) {
if ( **fds == FDS_STRUCT_ACCESS_SEP )
{
(*fds)++;
continue;
}
if ( **fds == FDS_STRUCT_END )
break;
while ( *(*fds)++ != FDS_STRUCT_FIELD_NAME_END )
; /* past the field name */
_fds_advance(fds); /* past the field type */
if ( **fds == FDS_STRUCT_FIELD_SEP )
(*fds)++;
}
(*fds)++; /* past closing brace */
break;
case AIF_NAME:
*fds = _fds_skipnum(*fds);
(*fds)++; /* past closing '/' */
_fds_advance(fds); /* past the named type */
break;
case AIF_POINTER:
_fds_advance(fds); /* past the address */
_fds_advance(fds); /* past the pointed-to type */
break;
case AIF_CHAR_POINTER:
_fds_advance(fds); /* past the address */
break;
case AIF_REFERENCE:
*fds = _fds_skipnum(*fds);
(*fds)++; /* past closing '/' */
break;
case AIF_CHARACTER:
case AIF_STRING:
break; /* already skipped all we should */
default:
fprintf(stderr, "no way to advance ... \"%s\"\n", *fds);
break;
}
}
/*
* **fds is integer, float, or character. Return how many bytes it
* has and advance *fds to its end
*/
int
_fds_count_bytes(char **fds)
{
int bytes;
switch ( **fds )
{
case FDS_FLOATING:
(*fds)++; /* past f */
bytes = _fds_getnum(*fds);
*fds = _fds_skipnum(*fds); /* past size indicator */
break;
case FDS_ENUM_START:
*fds = _fds_skipto(++(*fds), _fds_enum_end);
(*fds)++;
/* fall through */
case FDS_INTEGER:
*fds += 2; /* past iu or is */
bytes = _fds_getnum(*fds);
*fds = _fds_skipnum(*fds); /* past size indicator */
break;
case FDS_CHARACTER:
(*fds)++; /* past c */
bytes = 1;
break;
case FDS_BOOLEAN:
case FDS_ADDRESS:
(*fds)++; /* past b or a */
bytes = _fds_getnum(*fds);
*fds = _fds_skipnum(*fds); /* past size indicator */
break;
case FDS_VOID:
(*fds)++; /* past v */
bytes = _fds_getnum(*fds);
*fds = _fds_skipnum(*fds); /* past size indicator */
break;
default:
bytes = -1; /* internal error */
}
return bytes;
}
/*
* Count bytes but don't advance pointer
*/
int
_fds_count_bytes_na(char **fds)
{
char * fmt = *fds;
return _fds_count_bytes(&fmt);
}
void
_fds_resolve(char **fmt)
{
int index;
while ( **fmt == FDS_NAME )
{
(*fmt)++;
index = (int)strtol(*fmt, NULL, 10);
*fmt = (char *)_fds_skipnum(*fmt)+1; /* past name, trailing slash */
_aif_types_seen[index+MAX_TYPES_SEEN/2] = *fmt;
}
}
char *
_fds_lookup(char **fmt)
{
int index;
(*fmt)++;
index = (int)strtol(*fmt, NULL, 10);
*fmt = (char *)_fds_skipnum(*fmt)+1; /* past name, trailing slash */
return _aif_types_seen[index+MAX_TYPES_SEEN/2];
}
/*
* Find the target data for a pointer.
*
* @param fds format descriptor for pointer (need to calculate address size). At the
* end of the call, fds will be advanced to the beginning of the target type
* @param data points to the data part of an AIF. At the end of the call, data
* will be advanced to the beggining of the target data
* @param index a unique index for saving/retrieving values in order
* to simultaneously maintain targets for multiple AIFs.
* @return a pointer to the data region where the target data actually
* starts, or 0 if null or invalid pointer
*
* Format of the data is:
* <type>[<name>][<address>[<target>]]
*
* Where:
*
* <type> is a single byte:
* 0: null pointer, no data
* 1: ordinary pointer, data contains <address> and <target>
* 2: named pointer, data contains <name>, <address> and <target>
* 3: pointer reference, data contains <name>
* 4: invalid pointer, data contains <address>
* <name> is an unsigned 4 byte integer
* <address> is the address of the pointer
* <target> is the target data
*/
char *
_find_target(char **fds, char **data, int index)
{
int name;
char code = **data;
char * res;
(*fds)++; /* past the ^ */
(*data)++; /* past the code */
switch ( code )
{
case AIF_PTR_NIL:
_fds_advance(fds); /* skip address type */
return (char *)0;
case AIF_PTR_INVALID: /* invalid pointer value */
_fds_skip_data(fds, data); /* skip address */
return (char *)0;
case AIF_PTR_NORMAL: /* normal pointer value */
_fds_skip_data(fds, data); /* skip address */
res = *data;
return res;
case AIF_PTR_NAME: /* named value */
_ptrname_to_int(data, &name);
_fds_skip_data(fds, data); /* skip address type */
_aif_values_seen[name+index*MAX_VALUES_SEEN/2] = *data;
return *data;
case AIF_PTR_REFERENCE: /* reference to named value */
_ptrname_to_int(data, &name);
_fds_advance(fds); /* skip address type */
return _aif_values_seen[name+index*MAX_VALUES_SEEN/2];
}
return 0; /* should never fall through */
}
/*
* Get the pointer type.
*/
int
_get_pointer_type(char *data)
{
return (int)(*data);
}
/*
* Get the pointer name.
*/
int
_get_pointer_name(char *data)
{
int name = 0;
int type = _get_pointer_type(data);
if (type == AIF_PTR_NAME || type == AIF_PTR_REFERENCE) {
data++; /* skip code */
_ptrname_to_int(&data, &name);
}
return name;
}
/*
* Skip over one full data unit, specified by the fds,
* At return, fds should be at its end, and data is advanced.
*/
void
_fds_skip_data(char **fds, char **data)
{
int i;
int bytes;
AIFIndex * ix;
char * fmt;
_fds_resolve(fds);
switch ( FDSType(*fds) )
{
case AIF_REFERENCE:
fmt = _fds_lookup(fds); // need a temporary copy
_fds_skip_data(&fmt, data);
return;
case AIF_POINTER:
if (_find_target(fds, data, 0) == 0)
_fds_advance(fds);
else
_fds_skip_data(fds, data);
return;
case AIF_VOID:
case AIF_CHARACTER:
case AIF_INTEGER:
case AIF_BOOLEAN:
case AIF_FLOATING:
case AIF_ADDRESS:
case AIF_ENUM:
(*data) += _fds_count_bytes(fds);
return;
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;
_fds_skip_data(&fmt, data);
}
AIFArrayIndexFree(ix);
return;
case AIF_STRUCT:
(*fds)++; /* past open brace */
_fds_skipid(fds);
while ( **fds != FDS_STRUCT_END )
{
if ( **fds == FDS_STRUCT_ACCESS_SEP )
{
(*fds)++;
continue;
}
*fds = strchr(*fds, FDS_STRUCT_FIELD_NAME_END) + 1;
/* to start of field */
_fds_skip_data(fds, data);
if ( **fds == FDS_STRUCT_FIELD_SEP )
(*fds)++;
}
(*fds)++; /* past close brace */
return;
case AIF_CHAR_POINTER:
(*fds)++; /* past p */
_fds_skip_data(fds, data); /* past address */
bytes = (*(*data)++ & 0xff) << 8;
bytes += *(*data)++ & 0xff;
*data += bytes;
return;
case AIF_STRING:
(*fds)++; /* past s */
bytes = (*(*data)++ & 0xff) << 8;
bytes += *(*data)++ & 0xff;
*data += bytes;
return;
case AIF_FUNCTION:
while ( **data != '\0' )
(*data)++;
(*data)++; /* past null */
return;
default:
SetAIFError(AIFERR_TYPE, NULL);
return;
}
}
void
_fds_skipid(char **fds)
{
if (**fds != FDS_ID)
*fds = strchr(*fds, FDS_ID);
*fds += 1;
}
char *
_fds_add_function_arg(char *fds, char *arg)
{
char * nfmt;
char * temp;
char * rest;
if ( FDSType(fds) != AIF_FUNCTION )
{
SetAIFError(AIFERR_BADARG, NULL);
return NULL;
}
nfmt = (char *)_aif_alloc(strlen(fds) + strlen(arg) + 2);
*nfmt = '\0';
strcpy(nfmt, fds);
if ( (temp = _fds_skipto(nfmt, _fds_function_arg_end)) == NULL )
{
SetAIFError(AIFERR_BADARG, NULL);
_aif_free(nfmt);
return NULL;
}
rest = _fds_skipto(fds, _fds_function_arg_end);
if ( temp != (nfmt + 1) )
*temp++ = FDS_FUNCTION_ARG_SEP;
sprintf(temp, "%s%s",
arg,
rest);
ResetAIFError();
return nfmt;
}