Skip to content

AFNI/NIfTI Server

Sections
Personal tools
You are here: Home » AFNI » Documentation

Doxygen Source Code Documentation


Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Search  

niml_rowtype.c

Go to the documentation of this file.
00001 #include "niml_private.h"
00002 
00003 /***************************************************************************/
00004 /***** Stuff for defining rowtypes from strings.  RWCox - 09 Dec 2002. *****/
00005 /***************************************************************************/
00006 
00007 /*-------------------------------------------------------------------------*/
00008 
00009 /* These typedefs are used to find the byte alignment
00010    the compiler imposes on the 'basic' types supported by NIML. */
00011 
00012 typedef struct { char a; byte    b; } Qadgop_byte    ;  /* not a Mercotan */
00013 typedef struct { char a; short   b; } Qadgop_short   ;
00014 typedef struct { char a; int     b; } Qadgop_int     ;
00015 typedef struct { char a; float   b; } Qadgop_float   ;
00016 typedef struct { char a; double  b; } Qadgop_double  ;
00017 typedef struct { char a; complex b; } Qadgop_complex ;
00018 typedef struct { char a; rgb     b; } Qadgop_rgb     ;
00019 typedef struct { char a; rgba    b; } Qadgop_rgba    ;
00020 
00021 /* Arrays to hold the alignments, sizes, and names of the basic types. */
00022 
00023 static int   type_alignment[NI_NUM_BASIC_TYPES+1] ;
00024 static int   type_size     [NI_NUM_BASIC_TYPES+1] ;
00025 static char *type_name     [NI_NUM_BASIC_TYPES+1] = {
00026   "byte"  , "short"  , "int"     ,
00027   "float" , "double" , "complex" ,
00028   "rgb"   , "rgba"   , "String"
00029 } ;
00030 
00031 static char *type_alias[NI_NUM_BASIC_TYPES+1] = {   /* aliases */
00032   "uint8"   , "int16"   , "int32"     ,
00033   "float32" , "float64" , "complex64" ,
00034   "rgb8"    , "rgba8"   , "CString"
00035 } ;
00036 
00037 /* these are used to find/save the alignment and size of pointers */
00038 
00039 typedef struct { char a; void *b; } Qadgop_pointer ;
00040 static int pointer_alignment ;
00041 static int pointer_size ;
00042 
00043 /*---------------------------------------------------------------*/
00044 /*! The Htable of user-defined rowtypes, indexed by type name.   */
00045 
00046 static Htable *rowtype_table = NULL ;
00047 
00048 /*! The array of user-defined rowtypes, indexed by type code.
00049     Note that rowtypes are never deleted - they just accumulate. */
00050 
00051 static NI_rowtype **rowtype_array = NULL ;
00052 static int         rowtype_num    = 0    ;
00053 /*---------------------------------------------------------------*/
00054 
00055 /*! Rowtype code for first user-defined type. */
00056 
00057 #define ROWTYPE_OFFSET     1001
00058 
00059 /*! Used to set the code for each new user-defined type.
00060     (The '-1' is to allow for the String type, which isn't
00061      a basic type but is a builtin type.) */
00062 
00063 #define ROWTYPE_BASE_CODE (ROWTYPE_OFFSET-NI_NUM_BASIC_TYPES-1)
00064 
00065 /*! Check if a rowtype code is a derived type or a builtin type */
00066 
00067 #define ROWTYPE_is_builtin_code(cc) ((cc) >= 0 && (cc) < ROWTYPE_OFFSET)
00068 
00069 /*! Register a rowtype into the table and array. */
00070 
00071 #define ROWTYPE_register(rr)                               \
00072  do{ int nn ;                                              \
00073      if( rowtype_table == NULL ) setup_basic_types() ;     \
00074      addto_Htable( (rr)->name , (rr) , rowtype_table ) ;   \
00075      nn = rowtype_num + 1 ;                                \
00076      rowtype_array = NI_realloc( rowtype_array ,           \
00077                                  NI_rowtype*,              \
00078                                 sizeof(NI_rowtype *)*nn ); \
00079      rowtype_array[nn-1] = rr ;  rowtype_num = nn ;        \
00080  } while(0)
00081 
00082 /*--------------------------------*/
00083 /*! Debug flag for rowtype stuff. */
00084 
00085 static int ROWTYPE_debug = 0 ;
00086 
00087 /*! Set debug flag for rowtype stuff. */
00088 
00089 void NI_rowtype_debug( int n ){ ROWTYPE_debug = n ; }
00090 
00091 /*--------------------------------------------------------------------------*/
00092 /*! Setup the alignment of basic NI types inside a struct (depends on CPU). */
00093 
00094 static void setup_basic_types(void)
00095 {
00096    NI_rowtype *rt ;
00097    int ii ;
00098 
00099    if( rowtype_table != NULL ) return ;  /* don't run this twice */
00100 
00101    /* get alignments and sizes of the basic types */
00102 
00103    type_alignment[NI_BYTE   ] = offsetof(Qadgop_byte   ,b) ;
00104    type_alignment[NI_SHORT  ] = offsetof(Qadgop_short  ,b) ;
00105    type_alignment[NI_INT    ] = offsetof(Qadgop_int    ,b) ;
00106    type_alignment[NI_FLOAT  ] = offsetof(Qadgop_float  ,b) ;
00107    type_alignment[NI_DOUBLE ] = offsetof(Qadgop_double ,b) ;
00108    type_alignment[NI_COMPLEX] = offsetof(Qadgop_complex,b) ;
00109    type_alignment[NI_RGB    ] = offsetof(Qadgop_rgb    ,b) ;
00110    type_alignment[NI_RGBA   ] = offsetof(Qadgop_rgba   ,b) ;
00111 
00112    type_size[NI_BYTE   ] = sizeof(byte   ) ;
00113    type_size[NI_SHORT  ] = sizeof(short  ) ;
00114    type_size[NI_INT    ] = sizeof(int    ) ;
00115    type_size[NI_FLOAT  ] = sizeof(float  ) ;
00116    type_size[NI_DOUBLE ] = sizeof(double ) ;
00117    type_size[NI_COMPLEX] = sizeof(complex) ;
00118    type_size[NI_RGB    ] = sizeof(rgb    ) ;
00119    type_size[NI_RGBA   ] = sizeof(rgba   ) ;
00120 
00121    /* initialize the rowtype table with the basic types */
00122 
00123    rowtype_table = new_Htable(19) ;
00124 
00125    for( ii=0 ; ii < NI_NUM_BASIC_TYPES ; ii++ ){
00126 
00127      rt              = NI_new( NI_rowtype ) ;
00128      rt->code        = ii ;
00129      rt->size        = type_size[ii] ;          /* size of "struct" */
00130      rt->psiz        = rt->size ;               /* size of all parts */
00131      rt->algn        = type_alignment[ii] ;     /* byte alignment */
00132      rt->name        = NI_strdup(type_name[ii]);
00133      rt->userdef     = NI_strdup(type_name[ii]);
00134      rt->flag        = 0 ;
00135 
00136      rt->comp_num    = 1 ;                      /* basic types have */
00137      rt->comp_typ    = NI_malloc(int, sizeof(int)) ; /* only one component */
00138      rt->comp_typ[0] = ii ;
00139      rt->comp_dim    = NI_malloc(int, sizeof(int)) ;
00140      rt->comp_dim[0] = -1 ;                     /* fixed dim component */
00141 
00142      rt->part_num    = 1 ;                      /* basic types have */
00143      rt->part_typ    = NI_malloc(int, sizeof(int)) ; /* only one part */
00144      rt->part_typ[0] = ii ;
00145      rt->part_off    = NI_malloc(int, sizeof(int)) ;
00146      rt->part_off[0] = 0 ;
00147      rt->part_siz    = NI_malloc(int, sizeof(int)) ;
00148      rt->part_siz[0] = type_size[ii] ;
00149      rt->part_dim    = NI_malloc(int, sizeof(int)) ;
00150      rt->part_dim[0] = -1 ;                     /* fixed dim part */
00151      rt->part_rtp    = NI_malloc(NI_rowtype*, sizeof(NI_rowtype *)) ;
00152      rt->part_rtp[0] = rt ;
00153 
00154      ROWTYPE_register( rt ) ;                   /* put in the Htable */
00155    }
00156 
00157    /* alignment and size of pointers */
00158 
00159    pointer_alignment = offsetof(Qadgop_pointer,b) ;
00160    pointer_size      = sizeof(void *) ;
00161 
00162    /* insert a special rowtype for String (really a pointer) */
00163 
00164    type_alignment[NI_STRING] = pointer_alignment ;
00165    type_size     [NI_STRING] = pointer_size ;
00166 
00167    rt              = NI_new( NI_rowtype ) ;
00168    rt->code        = NI_STRING ;
00169    rt->size        = pointer_size ;
00170    rt->psiz        = 0 ;                       /* variable dim */
00171    rt->algn        = pointer_alignment ;
00172    rt->name        = NI_strdup("String") ;
00173    rt->userdef     = NI_strdup("String") ;
00174    rt->flag        = ROWTYPE_VARSIZE_MASK ;    /* variable dim */
00175 
00176    rt->comp_num    = 1 ;
00177    rt->comp_typ    = NI_malloc(int, sizeof(int)) ;
00178    rt->comp_typ[0] = NI_STRING ;
00179    rt->comp_dim    = NI_malloc(int, sizeof(int)) ;
00180    rt->comp_dim[0] = -1 ;
00181 
00182    rt->part_num    = 1 ;
00183    rt->part_typ    = NI_malloc(int, sizeof(int)) ;
00184    rt->part_typ[0] = NI_STRING ;
00185    rt->part_off    = NI_malloc(int, sizeof(int)) ;
00186    rt->part_off[0] = 0 ;
00187    rt->part_siz    = NI_malloc(int, sizeof(int)) ;
00188    rt->part_siz[0] = pointer_size ;
00189    rt->part_dim    = NI_malloc(int, sizeof(int)) ;
00190    rt->part_dim[0] = -1 ;
00191 
00192    rt->part_rtp    = NI_malloc(NI_rowtype*, sizeof(NI_rowtype *)) ;
00193    rt->part_rtp[0] = rt ;
00194 
00195    ROWTYPE_register( rt ) ;
00196 
00197    if( ROWTYPE_debug )
00198      profile_Htable( "rowtype_table" , rowtype_table ) ;
00199 }
00200 
00201 /*-------------------------------------*/
00202 /*! Error exit macro for next function */
00203 
00204 #undef  ERREX
00205 #define ERREX(str)                                                            \
00206  do { fprintf(stderr,"** NI_rowtype_define('%s','%s'): %s\n",tname,tdef,str); \
00207       return -1 ; } while(0)
00208 
00209 /*--------------------------------------------------------------------------*/
00210 /* Define a NI_rowtype, which is an expression of a C struct type (with
00211    some restrictions).
00212     - tname = Name to call this thing (must be unique and can't be one
00213               of the builtin types listed below).
00214     - tdef = Definition of the type:
00215        - A list of type names ('components') separated by commas.
00216        - A type name is one of the NIML basic types
00217          ("byte", "short", "int", "float", "double", "complex", "rgb", "rgba"),
00218          or is "String",
00219          or is a previously defined tname from a another NI_rowtype.
00220        - Recursive types cannot be defined; that is, no component of
00221          tdef can refer to the same tname that is being defined now.
00222        - A type name may be preceded/appended by an integer count,
00223          as in "int,4*float" or "int,float[4]".  These are equivalent
00224          to "int,float,float,float,float" (just shorter).
00225        - Variable dimension arrays may be defined, IF the size of the
00226          array is an int component of this new rowtype which occurs before
00227          the array definition:
00228            - "int,float[#1]" defines the second component to be
00229              a float array whose length is given by the value of
00230              the first component
00231            - This example is analogous to this C fragment:
00232               - typedef struct { int n; float *x; } far ;
00233               - far xfar ;
00234               - xfar.n = 373 ;
00235               - xfar.x = malloc(sizeof(float)*xfar.n) ;
00236            - You can't do something like "int,3*float[#1]" - only one
00237              repeat count per component is allowed!  The right way to
00238              do this would be "int,float[#1],float[#1],float[#1]".
00239            - All variable components in instances of these arrays
00240              will be allocated with NI_malloc() and should be released
00241              with NI_free().
00242            - The type of a variable dim array must be fixed in size;
00243              that is, that type itself cannot contain any var dim
00244              array or String components.
00245        - String components are also variable dimension arrays,
00246          but whose size is given by the usual strlen().
00247 
00248    The intention is that a C struct type is mapped to a NI_rowtype.  Some
00249    examples:
00250        - typedef struct { int i; float x,y,z; } ifvec ;
00251        - NI_rowtype_define( "ifvec" , "int,3*float" ) ;
00252        - typedef struct { byte a,b; ifvec c; } abvec ;
00253        - NI_rowtype_define( "abvec" , "2*byte,ifvec" ) ;
00254 
00255    The return value is a positive integer code which can be used to
00256    identify this NI_rowtype (the tname string can also be used for
00257    this purpose).  If -1 is returned, something bad transpired.
00258 
00259    Also see
00260     - NI_rowtype_find_name()
00261     - NI_rowtype_find_code()
00262     - NI_rowtype_name_to_code()
00263     - NI_rowtype_code_to_name()
00264 ----------------------------------------------------------------------------*/
00265 
00266 int NI_rowtype_define( char *tname , char *tdef )
00267 {
00268    NI_rowtype *rt , *qt ;
00269    int ii,jj , id,jd,kd,isdim,nn , almax,cbase,np,pb , last_size ;
00270    NI_str_array *sar ;
00271    char *tp,*sp,*bp , str[256] ;
00272 
00273    /*-- check inputs --*/
00274 
00275    if( !NI_is_name(tname) )              ERREX("bad typename") ;
00276    if( strlen(tname) > 255 )             ERREX("toolong typename") ;
00277    if( tdef  == NULL || *tdef  == '\0' ) ERREX("empty type definition") ;
00278 
00279    /*-- create Htable of basic types, if not already defined --*/
00280 
00281    if( rowtype_table == NULL ) setup_basic_types() ;
00282 
00283    /*-- see if type name already defined --*/
00284    /*-- 25 Mar 2003: if it is, return the old code --*/
00285 
00286    rt = NI_rowtype_find_name( tname ) ;
00287    if( rt != NULL ){
00288      if( strcmp(rt->userdef,tdef) != 0 ){
00289        fprintf(stderr,
00290                 "++ NI_rowtype_define: illegal attempt to redefine type '%s'\n"
00291                 "++          old definition: %s\n"
00292                 "++ (failed) new definition: %s\n" ,
00293                tname , rt->userdef , tdef ) ;
00294      }
00295      return rt->code ;
00296    }
00297 
00298    /*-- break defining string into components --*/
00299 
00300    sar = NI_decode_string_list( tdef , ",;" ) ;
00301 
00302    if( sar == NULL || sar->num < 1 ){
00303      NI_free(sar) ; ERREX("illegal definition") ;
00304    }
00305 
00306    /*-- initialize the new rowtype --*/
00307 
00308    rt          = NI_new( NI_rowtype ) ;
00309    rt->name    = NI_strdup( tname ) ;
00310    rt->userdef = NI_strdup( tdef ) ;
00311    rt->flag    = 0 ;
00312 
00313    /*-- loop over components in tdef, loading the new rt with their info --*/
00314 
00315    rt->part_num = rt->comp_num = 0 ;
00316 
00317    for( ii=0 ; ii < sar->num ; ii++ ){
00318 
00319      tp = sar->str[ii] ;
00320      id = 0 ; kd = strlen(tp) ; /* type name of part will be in tp[id..kd-1] */
00321      if( kd == 0 ){
00322       delete_rowtype(rt); NI_delete_str_array(sar); ERREX("empty component name?");
00323      }
00324 
00325      /* get count, if present, into jd */
00326 
00327      sp = strchr(tp,'*') ;   /* format of component string: count*type  */
00328      bp = strchr(tp,'[') ;   /* format of component string: type[count] */
00329 
00330      if( sp != NULL || bp != NULL ){            /*** a count is present ***/
00331 
00332        if( sp != NULL && bp != NULL ){          /* can't have both forms! */
00333         delete_rowtype(rt); NI_delete_str_array(sar); ERREX("two repeat counts?");
00334        }
00335 
00336        if( sp != NULL ){                        /* format: count*type */
00337          nn = 0 ;                               /*  - count starts at nn */
00338          id = (sp-tp)+1 ;                       /*  - type name starts at id */
00339        } else {                                 /* format: type[count] */
00340          kd = (bp-tp) ;                         /*  - type name ends at kd-1 */
00341          nn = kd+1 ;                            /*  - count starts at nn */
00342        }
00343 
00344        jd = -1 ;
00345        if( tp[nn] != '#' ){                     /* count is a plain number */
00346          isdim = 0 ;
00347          sscanf( tp+nn , "%d" , &jd ) ;
00348          if( jd <= 0 ){
00349           delete_rowtype(rt); NI_delete_str_array(sar); ERREX("bad repeat number");
00350          }
00351        } else {                                 /* count is a #reference */
00352          isdim = 1 ;
00353          sscanf( tp+nn+1 , "%d" , &jd ) ;       /* ref must be to index */
00354          if( jd <= 0 || jd > ii ){              /* before this component */
00355            delete_rowtype(rt); NI_delete_str_array(sar); ERREX("bad #index");
00356          }
00357          if( rt->comp_typ[jd-1] != NI_INT ||    /* ref must be to an int */
00358              rt->comp_dim[jd-1] >= 0        ){  /* of fixed dim (1 int) */
00359            delete_rowtype(rt); NI_delete_str_array(sar); ERREX("non-int #index");
00360          }
00361        }
00362      } else {
00363        isdim = 0 ; jd = 1 ;                     /* default count of 1 */
00364      }
00365 
00366      /* get the type of this component from its name */
00367 
00368      if( kd-id < 1 || kd-id > 255 ){
00369       delete_rowtype(rt); NI_delete_str_array(sar); ERREX("toolong component name");
00370      }
00371 
00372      NI_strncpy( str , tp+id , kd-id+1 ) ;  /* copy component name into str */
00373      qt = NI_rowtype_find_name( str ) ;     /* look it up in the table */
00374      if( qt == NULL ){
00375        delete_rowtype(rt); NI_delete_str_array(sar); ERREX("bad component type");
00376      }
00377 
00378      if( !isdim ){  /*** fixed count: add jd copies of this component type ***/
00379 
00380        rt->comp_typ = NI_realloc( rt->comp_typ, int, sizeof(int)*(rt->comp_num+jd) );
00381        rt->comp_dim = NI_realloc( rt->comp_dim, int, sizeof(int)*(rt->comp_num+jd) );
00382 
00383        for( jj=0 ; jj < jd ; jj++ ){
00384          rt->comp_typ[rt->comp_num + jj] = qt->code ;
00385          rt->comp_dim[rt->comp_num + jj] = -1 ;        /* fixed dim part */
00386        }
00387 
00388        rt->comp_num += jd ;                 /* have more components now */
00389        rt->part_num += jd * qt->part_num ;  /* have more parts now */
00390 
00391        if( ROWTYPE_is_varsize(qt) )         /* if component is variable dim, */
00392          rt->flag |= ROWTYPE_VARSIZE_MASK ; /* mark rowtype as variable dim  */
00393 
00394      } else {       /*** variable count: add 1 component that is a pointer   */
00395                     /***                 to an array of fixed dim elements,  */
00396                     /***                 dimension given in component #jd    */
00397 
00398        /* but can't have a var dim array of var dim arrays! */
00399 
00400        if( ROWTYPE_is_varsize(qt) ){
00401          delete_rowtype(rt); NI_delete_str_array(sar);
00402          ERREX("variable dim array must have fixed dim type");
00403        }
00404 
00405        rt->comp_typ = NI_realloc( rt->comp_typ, int, sizeof(int)*(rt->comp_num+1) );
00406        rt->comp_dim = NI_realloc( rt->comp_dim, int, sizeof(int)*(rt->comp_num+1) );
00407 
00408        rt->comp_typ[rt->comp_num] = qt->code ;  /* type this points to */
00409        rt->comp_dim[rt->comp_num] = jd-1 ;      /* which component has */
00410                                                 /* array dimension count */
00411        rt->comp_num ++ ;  /* 1 more component */
00412        rt->part_num ++ ;  /* and 1 more part */
00413 
00414        rt->flag |= ROWTYPE_VARSIZE_MASK ;   /* mark rowtype as variable dim */
00415 
00416      }
00417 
00418    } /* end of loop over components */
00419 
00420    NI_delete_str_array(sar) ;                  /* done with this string array */
00421 
00422    if( rt->part_num == 0 ){ delete_rowtype(rt); ERREX("no components?"); }
00423 
00424    /*** now loop over components, breaking them down into their parts,
00425         storing the part types and their offsets into the C struct    ***/
00426 
00427    rt->part_off = NI_malloc(int, sizeof(int)          * rt->part_num ) ;
00428    rt->part_typ = NI_malloc(int, sizeof(int)          * rt->part_num ) ;
00429    rt->part_dim = NI_malloc(int, sizeof(int)          * rt->part_num ) ;
00430    rt->part_siz = NI_malloc(int, sizeof(int)          * rt->part_num ) ;
00431    rt->part_rtp = NI_malloc(NI_rowtype*, sizeof(NI_rowtype *) * rt->part_num ) ;
00432 
00433    almax = 1 ;  /* will be largest type_alignment of any part */
00434    cbase = 0 ;  /* base offset into struct for next component */
00435    id    = 0 ;  /* part number we are about to work on */
00436 
00437    for( ii=0 ; ii < rt->comp_num ; ii++ ){
00438 
00439                                     /*** component is a      ***/
00440      if( rt->comp_dim[ii] >= 0 ){   /*** variable dim array  ***/
00441                                     /*** ==> store 1 pointer ***/
00442 
00443        if( pointer_alignment > 1 ){            /* make sure cbase */
00444          jd = cbase % pointer_alignment ;      /* is aligned OK  */
00445          if( jd > 0 ) cbase += (pointer_alignment-jd) ;
00446        }
00447 
00448        /* Note that this is the only case where a part_typ
00449           might end up as a derived type - normally, part_typ
00450           will be a builtin type code (NI_BYTE .. NI_STRING).
00451           Note the limitation that the type of variable dim
00452           arrays be a fixed dim type.                        */
00453 
00454        rt->part_typ[id] = rt->comp_typ[ii] ;
00455        rt->part_off[id] = cbase ;
00456        rt->part_siz[id] = pointer_size ;
00457        rt->part_rtp[id] = NI_rowtype_find_code( rt->part_typ[id] ) ;
00458 
00459        /* count number of parts before the dimension component into kd */
00460        /* so we can store the part index of this dimension component   */
00461 
00462        for( jd=kd=0 ; jd < rt->comp_dim[ii] ; jd++ ){
00463          if( rt->comp_dim[jd] >= 0 ){   /* this component is a pointer itself */
00464            kd++ ;
00465          } else {                      /* this component has fixed dim parts */
00466            qt = NI_rowtype_find_code( rt->comp_typ[jd] ) ;
00467            kd += qt->part_num ;
00468          }
00469        }
00470        rt->part_dim[id] = kd ;    /* which part is the dimension of this part */
00471 
00472        kd = pointer_alignment ;
00473        if( kd > almax ) almax = kd ;
00474 
00475        id++ ; cbase += pointer_size ;
00476 
00477      } else {      /*** fixed dim type, possibly with multiple parts ***/
00478 
00479        qt = NI_rowtype_find_code( rt->comp_typ[ii] ) ;  /* component type */
00480 
00481        /* adjust cbase upward if this component isn't properly aligned */
00482 
00483        if( qt->algn > 1 ){
00484          jd = cbase % qt->algn ;
00485          if( jd > 0 ) cbase += (qt->algn-jd) ;
00486        }
00487 
00488        pb = id ;                    /* part base index for this component */
00489        np = qt->part_num ;                 /* number of parts to add here */
00490 
00491        rt->part_typ[id] = qt->part_typ[0] ;  /* first part from component */
00492        rt->part_off[id] = cbase ;             /* goes at the current base */
00493        rt->part_dim[id] = -1 ;   /* 1st part cannot be variable dim array */
00494        rt->part_rtp[id] = NI_rowtype_find_code( rt->part_typ[id] ) ;
00495 
00496        kd = rt->part_rtp[id]->algn ;                 /* alignment of part */
00497        if( kd > almax ) almax = kd ;   /* keep track of largest alignment */
00498 
00499        last_size = rt->part_rtp[id]->size ;           /* size of 1st part */
00500        rt->part_siz[id] = last_size ;
00501 
00502        id++ ;  /* prepare to add next part */
00503 
00504        /* loop over rest of parts from this component */
00505 
00506        for( jj=1 ; jj < np ; jj++,id++ ){
00507 
00508          rt->part_typ[id] = qt->part_typ[jj] ;     /* type of new part      */
00509          rt->part_rtp[id] = NI_rowtype_find_code( rt->part_typ[id] ) ;
00510 
00511          if( qt->part_dim[jj] < 0 ){        /******* fixed dim part        **/
00512 
00513            nn = last_size ;                        /* # bytes in last part  */
00514            jd = rt->part_off[id-1] ;               /* offset of last part   */
00515            kd = rt->part_rtp[id]->algn ;           /* how to align new part */
00516            if( kd > almax ) almax = kd ; /* keep track of largest alignment */
00517 
00518            nn += jd ;  /* next available byte = sum of last offset and size */
00519            if( kd > 1 ){                           /* must move nn up if    */
00520              jd = nn % kd ;                        /* not on exact multiple */
00521              if( jd > 0 ) nn += (kd-jd) ;          /* of jj bytes alignment */
00522            }
00523            rt->part_off[id] = nn ;
00524            rt->part_dim[id] = -1 ;                /* mark as fixed dim part */
00525 
00526            last_size = rt->part_rtp[id]->size ;        /* size of this part */
00527            rt->part_siz[id] = last_size ;
00528 
00529          } else {                           /***** variable dim array part **/
00530 
00531            nn = last_size ;
00532            jd = rt->part_off[id-1] ;
00533            kd = pointer_alignment ;        /* we are storing a pointer here */
00534            if( kd > almax ) almax = kd ;
00535            nn += jd ;
00536            if( kd > 1 ){
00537              jd = nn % kd ;
00538              if( jd > 0 ) nn += (kd-jd) ;
00539            }
00540            rt->part_off[id] = nn ;
00541            last_size = pointer_size ;
00542            rt->part_siz[id] = last_size ;
00543 
00544            /* qt->part_dim[jj] is the part index in qt
00545               of the dimension for this variable dim array part;
00546               we must convert that to a part index in the new rowtype */
00547 
00548            rt->part_dim[id] = pb + qt->part_dim[jj] ;
00549 
00550          }
00551 
00552        } /* end of loop over parts within this component */
00553 
00554        /* now move the base offset up by the size of the current
00555           component (which may be bigger than the sum of its parts) */
00556 
00557        cbase += qt->size ;
00558 
00559      } /* end of fixed dim component part-izing */
00560 
00561    } /* end of loop over components */
00562 
00563    /* now compute the overall size of this new rowtype:
00564       at this point,
00565       cbase = next byte offset available after last part;
00566       this would be the size, but may have to be pushed
00567       up to allow for byte alignment of this rowtype     */
00568 
00569    rt->algn = almax ;
00570    if( rt->algn > 1 ){
00571      jd = cbase % rt->algn ;
00572      if( jd > 0 ) cbase += (rt->algn-jd) ;
00573    }
00574    rt->size = cbase ;  /* this size is the sizeof(struct),
00575                           and doesn't include var dim arrays or
00576                           Strings, just the pointers to those things */
00577 
00578    /* 26 Dec 2002: Compute the sum of the part sizes
00579                    (zero if this has variable dim arrays).
00580                    If rt->psiz == rt->size, then
00581                    struct is stored without padding bytes. */
00582 
00583    rt->psiz = 0 ;
00584    if( !ROWTYPE_is_varsize(rt) ){
00585      for( ii=0 ; ii < rt->part_num ; ii++ )
00586        rt->psiz += rt->part_siz[ii] ;
00587    }
00588 
00589    /* 28 Oct 2004: Move assignment of the new rowtype code to the end,
00590                    since a recursive call via NI_rowtype_find_name()
00591                    might have created a new rowtype before this one.
00592                    An example definition: "int,VECTOR_float_32,int".  */
00593 
00594    rt->code = ROWTYPE_BASE_CODE + rowtype_num ;
00595 
00596    /** debugging printouts **/
00597 
00598    if( ROWTYPE_debug ){
00599      fprintf(stderr,"\n") ;
00600      fprintf(stderr,"NI_rowtype_define: '%s' = '%s'\n",tname,tdef) ;
00601      fprintf(stderr,"  code     = %d\n",rt->code) ;
00602      fprintf(stderr,"  size     = %d\n",rt->size) ;
00603      fprintf(stderr,"  psiz     = %d\n",rt->psiz) ;
00604      fprintf(stderr,"  algn     = %d\n",rt->algn) ;
00605      fprintf(stderr,"  flag     = %d\n",rt->flag) ;
00606 
00607      fprintf(stderr,"  comp_num = %d\n",rt->part_num) ;
00608 
00609      fprintf(stderr,"  comp_typ = " ) ;
00610      for( ii=0 ; ii < rt->comp_num ; ii++ ) fprintf(stderr,"%4d ",rt->comp_typ[ii]) ;
00611      fprintf(stderr,"\n") ;
00612 
00613      fprintf(stderr,"  comp_dim = " ) ;
00614      for( ii=0 ; ii < rt->comp_num ; ii++ ) fprintf(stderr,"%4d ",rt->comp_dim[ii]) ;
00615      fprintf(stderr,"\n") ;
00616 
00617      fprintf(stderr,"  part_num = %d\n",rt->part_num) ;
00618 
00619      fprintf(stderr,"  part_typ = " ) ;
00620      for( ii=0 ; ii < rt->part_num ; ii++ ) fprintf(stderr,"%4d ",rt->part_typ[ii]) ;
00621      fprintf(stderr,"\n") ;
00622 
00623      fprintf(stderr,"  part_off = " ) ;
00624      for( ii=0 ; ii < rt->part_num ; ii++ ) fprintf(stderr,"%4d ",rt->part_off[ii]) ;
00625      fprintf(stderr,"\n") ;
00626 
00627      fprintf(stderr,"  part_siz = " ) ;
00628      for( ii=0 ; ii < rt->part_num ; ii++ ) fprintf(stderr,"%4d ",rt->part_siz[ii]) ;
00629      fprintf(stderr,"\n") ;
00630 
00631      fprintf(stderr,"  part_dim = " ) ;
00632      for( ii=0 ; ii < rt->part_num ; ii++ ) fprintf(stderr,"%4d ",rt->part_dim[ii]) ;
00633      fprintf(stderr,"\n") ;
00634    }
00635 
00636    /* save this in the table of rowtypes,
00637       and return the numerical code for this new type */
00638 
00639    ROWTYPE_register(rt) ;
00640    return rt->code ;
00641 }
00642 
00643 /*--------------------------------------------------------------------*/
00644 /*! Make an 'ni_do' element that defines a given rowtype. */
00645 
00646 NI_procins * NI_rowtype_procins( NI_rowtype *rt )  /* 19 Apr 2005 */
00647 {
00648    NI_procins *npi ;
00649    char *rhs ;
00650 
00651    if( rt == NULL ) return NULL ;
00652 
00653    npi = NI_new_processing_instruction( "ni_do" ) ;
00654    NI_set_attribute( npi , "ni_verb" , "typedef" ) ;
00655 
00656    rhs = NI_malloc(char,strlen(rt->name)+strlen(rt->userdef)+4) ;
00657    sprintf( rhs , "%s %s" , rt->name , rt->userdef ) ;
00658    NI_set_attribute( npi , "ni_object" , rhs ) ;
00659    NI_free( rhs ) ;
00660    return npi ;
00661 }
00662 
00663 /*--------------------------------------------------------------------*/
00664 /*! Find a rowtype by its name.
00665     19 Feb 2003: or its alias.
00666     28 Oct 2004: If name is of form VECTOR_basictype_length,
00667                  then a new rowtype is created on the spot;
00668                  e.g., "VECTOR_float_32" is like "float[32]". */
00669 
00670 NI_rowtype * NI_rowtype_find_name( char *nn )
00671 {
00672    NI_rowtype *rt ; int ii ;
00673    static int busy=0 ;       /* 28 Oct 2004: prevent recursion */
00674 
00675    if( nn == NULL || *nn == '\0' ) return NULL ;
00676    if( rowtype_table == NULL ) setup_basic_types() ;
00677    rt = (NI_rowtype *) findin_Htable(nn,rowtype_table) ;
00678    if( rt != NULL ) return rt ;
00679 
00680    /* 19 Feb 2003: linear search for basic type alias */
00681 
00682    for( ii=0 ; ii <= NI_NUM_BASIC_TYPES ; ii++ )
00683      if( strcmp(type_alias[ii],nn) == 0 ) return rowtype_array[ii] ;
00684 
00685    /*-- 28 Oct 2004: Define fixed size vector types here and now:
00686                      format of nn must be VECTOR_basictype_length --*/
00687 
00688    if( busy ) return NULL ;   /* cannot allow re-entry below here! */
00689 
00690    ii = strlen(nn) ;
00691    if( ii < 12 || strncmp(nn,"VECTOR_",7) != 0 || strchr(nn+7,'_') == NULL )
00692      return NULL ;
00693 
00694    { char bt[32] , rt[64] ; int tt , dd ;
00695 
00696      /* extract basic type name (after "VECTOR_") into bt array */
00697 
00698      for( ii=7 ; ii < 32 && nn[ii] != '\0' && nn[ii] != '_' ; ii++ )
00699        bt[ii-7] = nn[ii] ;
00700      if( nn[ii] != '_' ) return NULL ;   /* bad end of basic type name */
00701      bt[ii-7] = '\0' ;                   /* terminate with NUL byte */
00702 
00703      /* find bt name in basic type name list (or alias list) */
00704 
00705      for( tt=0 ; tt <= NI_NUM_BASIC_TYPES ; tt++ )
00706        if( strcmp(type_name[tt],bt) == 0 ) break ;
00707 
00708      if( tt > NI_NUM_BASIC_TYPES ){
00709        for( tt=0 ; tt <= NI_NUM_BASIC_TYPES ; tt++ )
00710          if( strcmp(type_alias[tt],bt) == 0 ) break ;
00711        if( tt > NI_NUM_BASIC_TYPES ) return NULL ;
00712      }
00713 
00714      /* find dimension after the nn[ii] character, which is '_' */
00715 
00716      dd = 0 ; sscanf( nn+ii+1 , "%d" , &dd ) ;
00717      if( dd <= 0 ) return NULL ;
00718 
00719      /* ready to create a new rowtype now */
00720 
00721      sprintf(rt,"%s[%d]",type_name[tt],dd) ;
00722 
00723      busy = 1 ;                        /* prevent recursion!!! */
00724      tt = NI_rowtype_define( nn , rt ) ;
00725      busy = 0 ;
00726      if( tt >= ROWTYPE_OFFSET ) return rowtype_array[tt-ROWTYPE_BASE_CODE] ;
00727    }
00728 
00729    return NULL ;
00730 }
00731 
00732 /*--------------------------------------------------------------------*/
00733 /*! Find a rowtype by its integer code. */
00734 
00735 NI_rowtype * NI_rowtype_find_code( int nn )
00736 {
00737    if( nn < 0 ) return NULL ;
00738    if( rowtype_table == NULL ) setup_basic_types() ;
00739    if( nn >= ROWTYPE_OFFSET ) nn = nn - ROWTYPE_BASE_CODE ;
00740    if( nn < 0 || nn >= rowtype_num ) return NULL ;
00741    return rowtype_array[nn] ;
00742 }
00743 
00744 /*--------------------------------------------------------------------*/
00745 /*! Given a rowtype name, find its integer code.
00746     Returns -1 if the name isn't found in the rowtype table.
00747 ----------------------------------------------------------------------*/
00748 
00749 int NI_rowtype_name_to_code( char *nn )
00750 {
00751    NI_rowtype *rt = NI_rowtype_find_name( nn ) ;
00752    if( rt != NULL ) return rt->code ;
00753    return -1 ;
00754 }
00755 
00756 /*--------------------------------------------------------------------*/
00757 /*! Given a rowtype code, find its string name.
00758     Returns NULL if the code isn't found in the rowtype table,
00759     otherwise returns the pointer to the name inside the table
00760     (i.e., don't free this string!).
00761 ----------------------------------------------------------------------*/
00762 
00763 char * NI_rowtype_code_to_name( int nn )
00764 {
00765    NI_rowtype *rt = NI_rowtype_find_code( nn ) ;
00766    if( rt != NULL ) return rt->name ;
00767    return NULL ;
00768 }
00769 
00770 /*--------------------------------------------------------------------*/
00771 /*! Given a rowtype code, find its alias name.  This is only valid
00772     for builtin types; for user-defined types, the return value is
00773     the user-supplied type name string.  Don't free this string!
00774 ----------------------------------------------------------------------*/
00775 
00776 char * NI_rowtype_code_to_alias( int nn )   /* 19 Feb 2003 */
00777 {
00778    if( rowtype_table == NULL ) setup_basic_types() ;
00779    if( nn <= NI_NUM_BASIC_TYPES ) return type_alias[nn] ;
00780    return NI_rowtype_code_to_name( nn ) ;
00781 }
00782 
00783 /*--------------------------------------------------------------------*/
00784 /*! Given a rowtype name, find its struct size in bytes.
00785     - Returns -1 if rowtype not found.
00786     - Note that if the rowtype contains variable dim arrays, this
00787       size returned here is just the size of the storage for
00788       the basic struct with pointers, not including the variable
00789       arrays.
00790     - See NI_rowtype_vsize() to get the size of a rowtype instance
00791       including its variable dim arrays.
00792 ----------------------------------------------------------------------*/
00793 
00794 int NI_rowtype_name_to_size( char *nn )
00795 {
00796    NI_rowtype *rt = NI_rowtype_find_name( nn ) ;
00797    if( rt != NULL ) return rt->size ;
00798    return -1 ;
00799 }
00800 
00801 /*-----------------------------------------------------------*/
00802 /*! Given a rowtype code, find its struct size in bytes.
00803     See also NI_rowtype_name_to_size().
00804 -------------------------------------------------------------*/
00805 
00806 int NI_rowtype_code_to_size( int dtyp )
00807 {
00808    static int last_dtyp=-1 , last_size=-1 ;         /* 12 Dec 2002 */
00809    NI_rowtype *rt ;
00810 
00811    if( rowtype_table == NULL )  setup_basic_types() ;
00812    if( dtyp <  0              ) return -1 ;
00813    if( dtyp <  ROWTYPE_OFFSET ) return type_size[dtyp] ;
00814    if( dtyp == last_dtyp      ) return last_size ;
00815 
00816    rt = NI_rowtype_find_code(dtyp) ;
00817    if( rt != NULL ){
00818      last_dtyp = dtyp; last_size = rt->size; return last_size;
00819    }
00820    return -1 ;  /* bad */
00821 }
00822 
00823 /*-----------------------------------------------------------------------*/
00824 /*! Compute the size of all the data in a struct defined in a NI_rowtype
00825     (not including padding), for this instance of the struct,
00826     allowing for variable array parts.  Zero is returned if something
00827     bad happens.
00828 -------------------------------------------------------------------------*/
00829 
00830 int NI_rowtype_vsize( NI_rowtype *rt , void *dpt )
00831 {
00832    int ii,jj , ss ;
00833    char *dat = (char *)dpt ;
00834 
00835    if( rt == NULL              ) return 0;        /* nonsense input */
00836    if( !ROWTYPE_is_varsize(rt) ) return rt->psiz; /* fixed dim struct */
00837    if( dat == NULL             ) return 0;        /* var size with no data? */
00838 
00839    /* loop over parts, adding up part sizes,
00840       including var dim arrays and String parts */
00841 
00842    for( ii=ss=0 ; ii < rt->part_num ; ii++ ){
00843      if( rt->part_typ[ii] == NI_STRING ){      /* String is special */
00844        char *str = *((char **)((dat) + (rt)->part_off[ii])) ;
00845        ss += NI_strlen(str) ;
00846      } else if( rt->part_dim[ii] < 0 ){        /* 1 fixed dim type */
00847        ss += rt->part_siz[ii] ;
00848      } else {                                  /* var dim array */
00849        jj = ROWTYPE_part_dimen(rt,dat,ii) ;    /* array size */
00850        ss += jj * rt->part_rtp[ii]->psiz ;     /* size of all parts */
00851      }                                         /* in var dim array */
00852    }
00853 
00854    return ss ;
00855 }
00856 
00857 /*-------------------------------------------------------------------------*/
00858 /*! Encode 1 type value at the end of the text string wbuf (which is
00859     assumed to be plenty long).  typ must be a fixed dim type code,
00860     or NI_STRING.  Structs with var dim arrays must be handled separately.
00861 ---------------------------------------------------------------------------*/
00862 
00863 void NI_val_to_text( NI_rowtype *rt , char *dpt , char *wbuf )
00864 {
00865    int jj = strlen(wbuf) ;
00866 
00867    switch( rt->code ){
00868 
00869      /*-- a derived type (will not contain var dim arrays) --*/
00870 
00871      default:{
00872        if( rt != NULL ){
00873          int ii ;
00874          for( ii=0 ; ii < rt->part_num ; ii++ )   /* recursion */
00875            NI_val_to_text( rt->part_rtp[ii] , dpt + rt->part_off[ii] , wbuf ) ;
00876        }
00877      }
00878      break ;
00879 
00880      /*-- integer types --*/
00881 
00882      case NI_BYTE:{
00883        byte *vpt = (byte *)dpt ;
00884        sprintf(wbuf+jj," %u",(unsigned int)vpt[0]) ;
00885      }
00886      break ;
00887 
00888      case NI_SHORT:{
00889        short *vpt = (short *)dpt ;
00890        sprintf(wbuf+jj," %d",(int)vpt[0]) ;
00891      }
00892      break ;
00893 
00894      case NI_INT:{
00895        int *vpt = (int *)dpt ;
00896        sprintf(wbuf+jj," %d",vpt[0]) ;
00897      }
00898      break ;
00899 
00900      /* multiple byte structs */
00901 
00902      case NI_RGB:{
00903        rgb *vpt = (rgb *)dpt ;
00904        sprintf(wbuf+jj,"  %u %u %u",vpt[0].r,vpt[0].g,vpt[0].b) ;
00905      }
00906      break ;
00907 
00908      case NI_RGBA:{
00909        rgba *vpt = (rgba *)dpt ;
00910        sprintf(wbuf+jj,"  %u %u %u %u",
00911                vpt[0].r,vpt[0].g,vpt[0].b,vpt[0].a) ;
00912      }
00913      break ;
00914 
00915      /* for floating point outputs,
00916         first print to a temp string, then clip trailing and leading blanks */
00917 
00918      case NI_FLOAT:{
00919        float *vpt = (float *)dpt ;
00920        char fbuf[32] ; int ff ;
00921        sprintf(fbuf,"%12.6g",vpt[0]) ;
00922        for( ff=strlen(fbuf) ; fbuf[ff]==' ' ; ff-- ) fbuf[ff] = '\0' ;
00923        for( ff=0 ; fbuf[ff] == ' ' ; ff++ ) ;
00924        sprintf(wbuf+jj," %s",fbuf+ff) ;
00925      }
00926      break ;
00927 
00928      case NI_DOUBLE:{
00929        double *vpt = (double *)dpt ;
00930        char fbuf[32] ; int ff ;
00931        sprintf(fbuf,"%18.12g",vpt[0]) ;
00932        for( ff=strlen(fbuf) ; fbuf[ff]==' ' ; ff-- ) fbuf[ff] = '\0' ;
00933        for( ff=0 ; fbuf[ff] == ' ' ; ff++ ) ;
00934        sprintf(wbuf+jj," %s",fbuf+ff) ;
00935      }
00936      break ;
00937 
00938      case NI_COMPLEX:{
00939        complex *vpt = (complex *)dpt ;
00940        char fbuf[32],gbuf[32] ; int ff,gg ;
00941        sprintf(fbuf,"%12.6g",vpt[0].r) ;
00942        for( ff=strlen(fbuf) ; fbuf[ff]==' ' ; ff-- ) fbuf[ff] = '\0' ;
00943        for( ff=0 ; fbuf[ff] == ' ' ; ff++ ) ;
00944        sprintf(gbuf,"%12.6g",vpt[0].i) ;
00945        for( gg=strlen(gbuf) ; gbuf[gg]==' ' ; gg-- ) gbuf[gg] = '\0' ;
00946        for( gg=0 ; gbuf[gg] == ' ' ; gg++ ) ;
00947        sprintf(wbuf+jj,"  %s %s",fbuf+ff,gbuf+gg) ;
00948      }
00949      break ;
00950 
00951      case NI_STRING:{                         /* 30 Dec 2002 */
00952        char **vpt = (char **)dpt , *str ;
00953        str = quotize_string( *vpt ) ;
00954        sprintf(wbuf+jj," %s",str) ;
00955        NI_free(str) ;
00956      }
00957      break ;
00958 
00959    } /* end of switch on part type */
00960 }
00961 
00962 /*-------------------------------------------------------------------------*/
00963 /*! Encode nv type values at the end of the text string wbuf.
00964     typ must be a fixed dim type code, or NI_STRING.
00965 ---------------------------------------------------------------------------*/
00966 
00967 void NI_multival_to_text( NI_rowtype *rt , int nv , char *dpt , char *wbuf )
00968 {
00969    int ii , jj=rt->size ;
00970 
00971    for( ii=0 ; ii < nv ; ii++ )
00972      NI_val_to_text( rt , dpt+ii*jj , wbuf ) ;
00973 }
00974 
00975 /*-------------------------------------------------------------------------*/
00976 /*! Copy 1 fixed dim type (no String or var dim array parts here) value
00977     in binary format to the wbuf.
00978     - Return value is number of bytes written.
00979     - Note that only data bytes are written, not any padding between parts.
00980 ---------------------------------------------------------------------------*/
00981 
00982 int NI_val_to_binary( NI_rowtype *rt , char *dpt , char *wbuf )
00983 {
00984    int jj=0 ;  /* will be return value */
00985 
00986    if( rt->size == rt->psiz ){        /* fixed dim, unpadded struct */
00987 
00988      jj = rt->size ;
00989      memcpy(wbuf,dpt,jj) ;
00990 
00991    } else if( !ROWTYPE_is_varsize(rt) ){  /* derived fixed dim type */
00992                                   /* ==> write each part separately */
00993      int ii ;
00994      for( ii=0 ; ii < rt->part_num ; ii++ ){
00995        memcpy(wbuf+jj,dpt+rt->part_off[ii],rt->part_siz[ii]) ;
00996        jj += rt->part_siz[ii] ;
00997      }
00998 
00999    }
01000 
01001    return jj ;
01002 }
01003 
01004 /*-------------------------------------------------------------------------*/
01005 /*! Copy nv fixed dim type values in binary format to the wbuf.
01006      - Return value is number of bytes written.
01007      - wbuf is assumed big enough to take the load
01008 ---------------------------------------------------------------------------*/
01009 
01010 int NI_multival_to_binary( NI_rowtype *rt , int nv , char *dpt , char *wbuf )
01011 {
01012    int jj=0 ;
01013 
01014    if( rt->size == rt->psiz ){         /* fixed dim, unpadded structs  */
01015                                        /* ==> Write all data at once   */
01016      jj = nv * rt->size ;
01017      memcpy(wbuf,dpt,jj);
01018 
01019    } else if( rt->psiz > 0 ){          /* Derived type is harder:      */
01020                                        /* Write each struct separately */
01021      int ii ;
01022      for( ii=0 ; ii < nv ; ii++ )
01023       jj += NI_val_to_binary( rt , dpt+(ii*rt->size) , wbuf+jj ) ;
01024 
01025    }
01026    return jj ;
01027 }
01028 
01029 /*------------------------------------------------------------------------*/
01030 /*! Return 1 if the type contains a String part, 0 if not.
01031 --------------------------------------------------------------------------*/
01032 
01033 int NI_has_String( NI_rowtype *rt )
01034 {
01035    int ii , jj ;
01036 
01037    if( rt == NULL ) return 0 ;
01038 
01039    /* test #1: if a NIML builtin type, test if it is String */
01040 
01041    if( ROWTYPE_is_builtin_code(rt->code) ) return (rt->code == NI_STRING) ;
01042 
01043    /* test the parts */
01044 
01045    for( ii=0 ; ii < rt->part_num ; ii++ ){
01046      if( ROWTYPE_is_builtin_code(rt->part_rtp[ii]->code) ){ /* builtin part */
01047        if( rt->part_rtp[ii]->code == NI_STRING ) return 1;
01048      } else {                                              /* derived part */
01049        if( NI_has_String( rt->part_rtp[ii] )   ) return 1; /* recursion */
01050      }
01051    }
01052    return 0 ;
01053 }
01054 
01055 /*------------------------------------------------------------------------*/
01056 /*! Write one column of structs to the output stream.  Now superseded
01057     by NI_write_columns().
01058 --------------------------------------------------------------------------*/
01059 
01060 int NI_write_rowtype( NI_stream_type *ns , NI_rowtype *rt ,
01061                       int ndat , void *dat , int tmode )
01062 {
01063    void *dpt = dat ;
01064    if( rt == NULL ) return -1 ;
01065    return NI_write_columns( ns , 1 , &(rt->code) , ndat , &dpt , tmode ) ;
01066 }
01067 
01068 /*------------------------------------------------------------------------*/
01069 /*! Write "columns" of data to a NI_stream.  Each column is an array of
01070     structs of some NI_rowtype (including the builtin types):
01071       - ns         = stream to write to
01072       - col_num    = number of columns to write (1,2,...)
01073       - col_typ[i] = type code for column #i (i=0..col_num-1)
01074       - col_len    = number of elements in each column
01075       - col_dpt[i] = pointer to data in column #i
01076       - tmode is one of
01077          - NI_TEXT_MODE   ==> ASCII output
01078            - text mode is required if any data component is a String
01079            - text mode is required to "str:" streams
01080          - NI_BINARY_MODE ==> binary output (endian-ness of this CPU)
01081          - NI_BASE64_MODE ==> binary/base64 output (ditto)
01082       - return value is number of bytes written to stream
01083         (-1 if something bad happened, 0 if can't write to stream yet)
01084 
01085    Only the data is written to the stream - no header or footer.
01086    This function is adapted from the 1st edition of NI_write_element().
01087 --------------------------------------------------------------------------*/
01088 
01089 int NI_write_columns( NI_stream_type *ns,
01090                       int col_num , int   *col_typ ,
01091                       int col_len , void **col_dpt , int tmode )
01092 {
01093    int ii,jj , row , dim , ntot,nout , col ;
01094    char *ptr , **col_dat=(char **)col_dpt ;
01095    int  nwbuf,bb=0,cc=0;
01096    char *wbuf=NULL ; /* write buffer */
01097    char *bbuf=NULL ; /* copy of write buffer */
01098    char *cbuf=NULL ; /* Base64 buffer */
01099 
01100    NI_rowtype **rt=NULL ;  /* array of NI_rowtype, 1 per column */
01101    int *vsiz=NULL , vsiz_tot=0 ;
01102    int *fsiz=NULL , fsiz_tot=0 ;
01103 
01104 # undef  FREEUP
01105 # define FREEUP do{ NI_free(wbuf); NI_free(bbuf); NI_free(cbuf); \
01106                     NI_free(rt)  ; NI_free(vsiz); NI_free(fsiz); \
01107                 } while(0)
01108 
01109    /*-- check inputs --*/
01110 
01111    if( col_num <= 0    || col_len <= 0    ) return  0 ;
01112    if( col_typ == NULL || col_dat == NULL ) return -1 ;
01113    if( !NI_stream_writeable(ns)           ) return -1 ;
01114 
01115 #if 0
01116 fprintf(stderr,"NI_write_columns: col_num=%d col_len=%d tmode=%d\n",col_num,col_len,tmode) ;
01117 #endif
01118 
01119    /*-- check stream --*/
01120 
01121    if( ns->bad ){                        /* not connected yet? */
01122      jj = NI_stream_goodcheck(ns,666) ;  /* try to connect it */
01123      if( jj < 1 ) return jj ;            /* 0 is nothing yet, -1 is death */
01124    }
01125 #if 1
01126    jj = NI_stream_writecheck(ns,666) ;
01127    if( jj < 0 ) return jj ;              /* only exit if stream is actually bad */
01128 #endif
01129 
01130    if( ns->type == NI_STRING_TYPE )  /* output to string buffer ==> text mode */
01131      tmode = NI_TEXT_MODE ;
01132 
01133    /* create array of NI_rowtype for columns, etc. */
01134 
01135    rt   = NI_malloc(NI_rowtype*, sizeof(NI_rowtype *) * col_num ) ;
01136    vsiz = NI_malloc(int,  sizeof(int)          * col_num ) ;
01137    fsiz = NI_malloc(int,  sizeof(int)          * col_num ) ;
01138    for( col=0 ; col < col_num ; col++ ){
01139 
01140      /* convert column type code to rowtype pointer */
01141 
01142      rt[col] = NI_rowtype_find_code( col_typ[col] ) ;
01143 
01144      /* can't find type, or no data in column?  take this job and shove it */
01145 
01146      if( rt[col] == NULL || col_dat[col] == NULL ){ FREEUP; return -1; }
01147 
01148      vsiz[col] = ROWTYPE_is_varsize(rt[col]) ;         /* variable dim type? */
01149      fsiz[col] = rt[col]->size ;         /* fixed size of struct (w/padding) */
01150      vsiz_tot += vsiz[col] ;
01151      fsiz_tot += fsiz[col] ;
01152 
01153      /* can only write String parts in text mode */
01154 
01155      if( tmode != NI_TEXT_MODE && NI_has_String(rt[col]) ) tmode = NI_TEXT_MODE;
01156    }
01157 
01158    /*-- Special (and fast) case:
01159         one compact (no padding) fixed-size rowtype,
01160         and binary output ==> can write all data direct to stream at once --*/
01161 
01162    if( col_num == 1 && tmode == NI_BINARY_MODE && fsiz[0] == rt[0]->psiz ){
01163 #if 0
01164 int ct = NI_clock_time() ;
01165 #endif
01166      nout = NI_stream_write( ns , col_dat[0] , fsiz[0]*col_len ) ;
01167 #if 0
01168 ct = NI_clock_time()-ct ;
01169 fprintf(stderr,"NI_write_columns FAST case: %d bytes in %d ms\n",fsiz[0]*col_len,ct) ;
01170 #endif
01171      FREEUP ; return nout ;
01172    }
01173 
01174    /*-- allocate space for the write buffer (1 row at a time) --*/
01175 
01176    switch( tmode ){
01177      default:             tmode = NI_TEXT_MODE ; /* fall through */
01178      case NI_TEXT_MODE:   nwbuf = 6*fsiz_tot ; break ;
01179 
01180      case NI_BASE64_MODE:
01181      case NI_BINARY_MODE: nwbuf =   fsiz_tot ; break ;
01182    }
01183    wbuf = NI_malloc(char, nwbuf+128) ;  /* 128 for the hell of it */
01184 
01185    /* create buffers for Base64 output, if needed */
01186 
01187    if( tmode == NI_BASE64_MODE ){
01188      bbuf = NI_malloc(char,   nwbuf+128) ; bb = 0 ;  /* binary buffer */
01189      cbuf = NI_malloc(char, 2*nwbuf+128) ; cc = 0 ;  /* base64 buffer */
01190      load_encode_table() ;
01191    }
01192 
01193    /* this macro take the 'nout' number of output bytes
01194       and adds into the running total ntot if all was well;
01195       if all was not well with the write, then it aborts the output */
01196 
01197 # undef  ADDOUT
01198 # define ADDOUT                              \
01199   if( nout < 0 ){                            \
01200     fprintf(stderr,"NIML:: write abort!\n"); \
01201     FREEUP ; return -1 ;                     \
01202   } else ntot+=nout
01203 
01204    /*-- loop over output rows,
01205         format for output into wbuf, and then send to output stream --*/
01206 
01207    ntot = 0 ;  /* total number of bytes output to stream */
01208 
01209    for( row=0 ; row < col_len ; row++ ){
01210 
01211      /* expand write buffer if any type contains variable dim array(s) */
01212 
01213      if( vsiz_tot ){
01214        for( jj=col=0 ; col < col_num ; col++ ){
01215         ptr = col_dat[col] + fsiz[col]*row ;     /* ptr to row-th element */
01216         jj += NI_rowtype_vsize( rt[col] , ptr ); /* size of data, w/var arrays */
01217        }
01218        if( tmode == NI_TEXT_MODE ) jj *= 6 ;
01219        if( jj > nwbuf ){                     /* did it get bigger? */
01220          nwbuf = jj ;
01221          wbuf  = NI_realloc(wbuf, char,nwbuf+128) ;
01222          if( tmode == NI_BASE64_MODE ){          /* expand Base64 stuff, too */
01223            bbuf = NI_realloc(bbuf, char,  nwbuf+128) ;
01224            cbuf = NI_realloc(cbuf, char,2*nwbuf+128) ;
01225          }
01226        }
01227      }
01228 
01229      /* initialize write buffer for this row */
01230 
01231      switch( tmode ){
01232        case NI_TEXT_MODE:    wbuf[0] = '\0'; break; /* clear buffer */
01233        case NI_BASE64_MODE:
01234        case NI_BINARY_MODE:  jj = 0 ;        break; /* clear byte count */
01235      }
01236 
01237      /* loop over columns, write each into the buffer */
01238 
01239      for( col=0 ; col < col_num ; col++ ){
01240       ptr = col_dat[col] + fsiz[col]*row ; /* ptr to row-th struct */
01241                                            /* in this columns      */
01242 
01243       /* write each part of this struct into the buffer */
01244 
01245       /* in text mode, strlen(wbuf) keeps track of number of bytes;
01246          in binary mode, jj keeps track of number of bytes written */
01247 
01248       for( ii=0 ; ii < rt[col]->part_num ; ii++ ){ /*-- loop over parts --*/
01249 
01250        if( rt[col]->part_dim[ii] < 0 ){             /*-- a single value --*/
01251          switch( tmode ){           /*-- output method (text or binary) --*/
01252 
01253            case NI_TEXT_MODE:              /*-- sprintf value to output --*/
01254              NI_val_to_text( rt[col]->part_rtp[ii],
01255                              ptr+rt[col]->part_off[ii], wbuf ) ;
01256            break ;
01257 
01258            case NI_BASE64_MODE:            /*-- memcpy values to output --*/
01259            case NI_BINARY_MODE:
01260              jj += NI_val_to_binary( rt[col]->part_rtp[ii],
01261                                      ptr+rt[col]->part_off[ii], wbuf+jj ) ;
01262            break ;
01263          }
01264 
01265        } else {                           /*-- variable dimension array --*/
01266 
01267          char **apt = (char **)(ptr+rt[col]->part_off[ii]); /* data in struct */
01268                                                            /* is ptr to array */
01269 
01270          dim = ROWTYPE_part_dimen(rt[col],ptr,ii) ;      /* dimension of part */
01271          if( dim > 0 && *apt != NULL ){
01272            switch( tmode ){
01273              case NI_TEXT_MODE:
01274                NI_multival_to_text( rt[col]->part_rtp[ii] , dim ,
01275                                     *apt , wbuf ) ;
01276              break ;
01277              case NI_BASE64_MODE:
01278              case NI_BINARY_MODE:
01279                jj += NI_multival_to_binary( rt[col]->part_rtp[ii] , dim ,
01280                                             *apt , wbuf+jj ) ;
01281              break ;
01282            }
01283          }
01284        }
01285 
01286       } /* end of loop over parts in this column struct */
01287      } /* end of loop over columns */
01288 
01289      /*- actually write the row data in wbuf out -*/
01290 
01291      switch( tmode ){
01292 
01293        case NI_TEXT_MODE:     /* each row is on a separate line */
01294          strcat(wbuf,"\n") ;
01295          nout = NI_stream_writestring( ns , wbuf ) ;
01296          ADDOUT ;
01297        break ;
01298 
01299        case NI_BINARY_MODE:   /* jj bytes of binary in wbuf */
01300          nout = NI_stream_write( ns , wbuf , jj ) ;
01301 #ifdef NIML_DEBUG
01302 if( nout != jj ) NI_dpr("NI_write_columns: col#%d sends %d bytes; nout=%d\n",col,jj,nout) ;
01303 #endif
01304          ADDOUT ;
01305        break ;
01306 
01307        case NI_BASE64_MODE:{  /* convert binary triples into base64 quads */
01308          int nb , nb3 , nb64 , pp,qq ;
01309          byte a,b,c,w,x,y,z ;
01310 
01311          /* bbuf = bb bytes of unprocessed data from last struct
01312                    plus jj bytes of data from new struct
01313                    (bb will be 0 or 1 or 2)                     */
01314 
01315          memcpy(bbuf+bb,wbuf,jj) ;       /* add wbuf to tail of bbuf */
01316          nb = jj+bb ;                    /* number of bytes in bb */
01317          if( nb < 3 ){ bb = nb; break; } /* need at least 3 bytes */
01318          nb3 = 3*(nb/3) ;                /* will encode nb3 bytes */
01319 
01320          /* cbuf = base64 output buffer */
01321          /* cc   = # bytes written since last EOL */
01322 
01323          for( qq=pp=0 ; pp < nb3 ; ){
01324            a = bbuf[pp++] ; b = bbuf[pp++] ; c = bbuf[pp++] ;
01325            B64_encode3(a,b,c,w,x,y,z) ;
01326            cbuf[qq++] = w ; cbuf[qq++] = x ;
01327            cbuf[qq++] = y ; cbuf[qq++] = z ;
01328            cc += 4; if( cc > 64 ){ cbuf[qq++]=B64_EOL2; cc=0; }
01329          }
01330 
01331          /* write base64 bytes to output */
01332 
01333          nout = NI_stream_write( ns , cbuf , qq ) ;
01334          ADDOUT ;
01335 
01336          /* deal with leftover bytes in bbuf */
01337 
01338          bb = nb - nb3 ;  /* num leftover bytes = 0, 1, or 2 */
01339          if( bb > 0 ){
01340            bbuf[0] = bbuf[nb3] ;                /* copy leftovers   */
01341            if( bb > 1 ) bbuf[1] = bbuf[nb3+1] ; /* to front of bbuf */
01342          }
01343        }
01344        break ;
01345      }
01346 
01347    } /* end of loop over output structs (row) */
01348 
01349    /* in Base64 mode, we might have to clean
01350       up if there are any leftover bytes in bbuf,
01351       or at least write an end of line           */
01352 
01353    if( tmode == NI_BASE64_MODE ){
01354      if( bb > 0 ){                  /* num leftover bytes of data */
01355        byte w,x,y,z , a=bbuf[0],b=bbuf[1] ;
01356        if( bb == 2 ) B64_encode2(a,b,w,x,y,z) ;
01357        else          B64_encode1(a,w,x,y,z) ;
01358        cbuf[0] = w ; cbuf[1] = x ;
01359        cbuf[2] = y ; cbuf[3] = z ; cbuf[4] = B64_EOL2 ;
01360        nout = NI_stream_write( ns , cbuf , 5 ) ;
01361        ADDOUT ;
01362      } else if( cc > 0 ){           /* just write an end of line */
01363        cbuf[0] = B64_EOL2 ;
01364        nout = NI_stream_write( ns , cbuf , 1 ) ;
01365        ADDOUT ;
01366      }
01367    }
01368 
01369    /*-- cleanup and return --*/
01370 
01371    FREEUP ;
01372    return ntot ;
01373 }
01374 
01375 /*------------------------------------------------------------------------*/
01376 /*! Read "columns" of data from a NI_stream.  Each column is an array of
01377     structs of some NI_rowtype (including the builtin types):
01378       - ns         = stream to read from
01379       - col_num    = number of columns to read (1,2,...)
01380       - col_typ[i] = type code for column #i (i=0..col_num-1)
01381       - col_len    = number of elements in each column
01382          - col_len can be 0, which means read data until the end-of-input
01383          - end-of-input is end-of-stream, or '<' in NI_TEXT_MODE
01384       - col_dpt[i] = pointer to data in column #i
01385          - col_dpt can't be NULL
01386          - but if col_dpt[i] is NULL, it will be NI_malloc()-ed
01387          - if col_dpt[i] isn't NULL, it must point to space big
01388            enough to hold the input (col_num * fixed size of rowtype #i)
01389          - if col_len==0 on input:
01390             - then col_dpt[i] should be NULL for i=0..col_num-1
01391             - this function will NI_malloc() to fit the amount of data scanned
01392             - if col_dpt[i]!=NULL with col_len==0, then function returns -1
01393       - tmode is one of
01394          - NI_TEXT_MODE   ==> ASCII input
01395             - text mode is required if any rowtype component is a String
01396             - text mode is required from "str:" streams
01397          - NI_BINARY_MODE ==> binary input
01398          - NI_BASE64_MODE ==> binary/base64 input
01399       - flags is the OR of various bit masks
01400          - NI_SWAP_MASK  ==> binary input must be byte-swapped after input
01401          - NI_LTEND_MASK ==> text input stops at a '<' in the input
01402       - return value is:
01403          - number of complete rows actually read (<= col_len)
01404          - zero if stream isn't ready to read
01405          - -1 if something bad happened
01406 
01407    Only the data is read from the stream - no header or footer.
01408    This function is adapted from the 1st edition of NI_read_element().
01409 --------------------------------------------------------------------------*/
01410 
01411 int NI_read_columns( NI_stream_type *ns,
01412                      int col_num, int   *col_typ,
01413                      int col_len, void **col_dpt, int tmode, int flags )
01414 {
01415    int ii,jj , row , dim , nin , col , nn ;
01416    char *ptr , **col_dat=(char **)col_dpt ;
01417 
01418    NI_rowtype **rt=NULL ;  /* array of NI_rowtype, 1 per column */
01419    int *vsiz=NULL , vsiz_tot=0 ;
01420    int *fsiz=NULL , fsiz_tot=0 ;
01421 
01422    int (*ReadFun)( NI_stream_type *, NI_rowtype *, void *, int ) ;
01423    int ltend = (flags & NI_LTEND_MASK) != 0 ;
01424    int swap  = (flags & NI_SWAP_MASK)  != 0 ;
01425    int ReadFlag ;
01426    int open_ended = (col_len==0) , row_top ;  /* 27 Mar 2003 */
01427 
01428 # undef  FREEUP
01429 # define FREEUP do{ NI_free(rt); NI_free(vsiz); NI_free(fsiz); } while(0)
01430 
01431    /*-- check inputs --*/
01432 
01433    if( col_num <= 0    || col_len <  0    ) return  0 ;
01434    if( col_typ == NULL || col_dat == NULL ) return -1 ;
01435    if( !NI_stream_readable(ns)            ) return -1 ;
01436 
01437 #ifdef NIML_DEBUG
01438 NI_dpr("ENTER NI_read_columns\n") ;
01439 #endif
01440 
01441    /*-- check stream --*/
01442 
01443    if( ns->bad ){                        /* not connected yet? */
01444      jj = NI_stream_goodcheck(ns,666) ;  /* try to connect it */
01445      if( jj < 1 ) return jj ;            /* 0 is nothing yet, -1 is death */
01446    }
01447    jj = NI_stream_hasinput(ns,666) ;     /* any data to be had? */
01448    if( jj < 0 ) return jj ;              /* only exit if stream is actually bad */
01449 
01450    /* create array of NI_rowtype for columns, etc. */
01451 
01452    rt   = NI_malloc(NI_rowtype*,  sizeof(NI_rowtype *) * col_num ) ;
01453    vsiz = NI_malloc(int,  sizeof(int)          * col_num ) ;
01454    fsiz = NI_malloc(int,  sizeof(int)          * col_num ) ;
01455    if( open_ended ) col_len = 1 ;
01456    for( col=0 ; col < col_num ; col++ ){
01457 
01458      rt[col] = NI_rowtype_find_code( col_typ[col] ) ;
01459      if( rt[col] == NULL ){ FREEUP; return -1; }
01460      if( tmode != NI_TEXT_MODE && NI_has_String(rt[col]) ){ FREEUP; return -1; }
01461 
01462      vsiz[col] = ROWTYPE_is_varsize(rt[col]) ;     /*  variable dim type? */
01463      fsiz[col] = rt[col]->size ;      /* fixed size of struct (w/padding) */
01464      vsiz_tot += vsiz[col] ;
01465      fsiz_tot += fsiz[col] ;
01466 
01467      /* setup data array for this column */
01468 
01469      if( col_dat[col] == NULL ){
01470        col_dat[col] = NI_malloc(char,  fsiz[col]*col_len ) ; /* make space */
01471      } else {
01472        if( open_ended ){ FREEUP; return -1; }
01473        memset( col_dat[col], 0 , fsiz[col]*col_len ) ; /* set space to 0 */
01474      }
01475    }
01476 
01477    /*-- Special (and fast) case:
01478         one compact (no padding) fixed-size rowtype,
01479         and binary input ==> can read all data direct from stream at once --*/
01480 
01481    if( col_num == 1              &&
01482        fsiz[0] == rt[0]->psiz    &&    /* struct size == data size */
01483        tmode   == NI_BINARY_MODE &&
01484        !open_ended                 ){
01485 
01486      nin = NI_stream_readbuf( ns , col_dat[0] , fsiz[0]*col_len ) ;
01487      if( nin < fsiz[0] ){ FREEUP; return (nin >= 0) ? 0 : -1 ; }  /* bad */
01488      nin = nin / fsiz[0] ;  /* number of rows finished */
01489      goto ReadFinality ;    /* post-process input down below */
01490    }
01491 
01492    /*-- 21 Apr 2005: repeat above for Base64 input --*/
01493 
01494    if( col_num == 1              &&
01495        fsiz[0] == rt[0]->psiz    &&    /* struct size == data size */
01496        tmode   == NI_BASE64_MODE &&
01497        !open_ended                 ){
01498 
01499      nin = NI_stream_readbuf64( ns , col_dat[0] , fsiz[0]*col_len ) ;
01500      if( nin < fsiz[0] ){ FREEUP; return (nin >= 0) ? 0 : -1 ; }  /* bad */
01501      nin = nin / fsiz[0] ;  /* number of rows finished */
01502      goto ReadFinality ;    /* post-process input down below */
01503    }
01504 
01505    /*-- Choose function to read from stream and fill one struct --*/
01506 
01507    switch( tmode ){
01508      case NI_TEXT_MODE:   ReadFun = NI_text_to_val  ; ReadFlag = ltend; break;
01509      case NI_BINARY_MODE: ReadFun = NI_binary_to_val; ReadFlag = swap ; break;
01510      case NI_BASE64_MODE: ReadFun = NI_base64_to_val; ReadFlag = swap ; break;
01511      default:
01512        fprintf(stderr,"\n** NI_read_columns: unknown input tmode=%d\n",tmode);
01513        FREEUP ; return -1 ;
01514    }
01515 
01516    /*-- OK, have to read the hard ways --*/
01517 
01518    row_top = (open_ended) ? 1999999999 : col_len ; /* 28 Mar 2003 */
01519 
01520    for( row=0 ; row < row_top ; row++ ){                  /* loop over rows */
01521                                                           /* until all done */
01522 
01523 #ifdef NIML_DEBUG
01524 NI_dpr(" Starting row #%d\n",row) ;
01525 #endif
01526 
01527      /* 27 Mar 2003: maybe need to extend length of columns */
01528 
01529      if( open_ended && row >= col_len ){
01530 #ifdef NIML_DEBUG
01531 NI_dpr("  Extending column lengths!\n") ;
01532 #endif
01533        jj = (int)(1.2*col_len+32) ;
01534        for( col=0 ; col < col_num ; col++ ){
01535          col_dat[col] = NI_realloc( col_dat[col] , char, fsiz[col]*jj ) ;
01536          memset( col_dat[col]+fsiz[col]*col_len, 0 , fsiz[col]*(jj-col_len) ) ;
01537        }
01538        col_len = jj ;
01539      }
01540 
01541      /* loop over columns, read into struct */
01542 
01543      for( col=0 ; col < col_num ; col++ ){
01544        ptr = col_dat[col] + fsiz[col]*row ;         /* ptr to row-th struct */
01545        nn  = ReadFun( ns, rt[col], ptr, ReadFlag ) ; /* read data to struct */
01546        if( !nn ) break ;
01547      }
01548      if( !nn ) break ;                             /* some ReadFun() failed */
01549    }
01550 
01551    if( row == 0 ){                                /* didn't finish any rows */
01552      if( open_ended ){
01553        for( col=0 ; col < col_num ; col++ ) NI_free(col_dat[col]) ;
01554      }
01555      FREEUP; return -1;
01556    }
01557 
01558    nin = row ;                                   /* number of rows finished */
01559 
01560    if( open_ended && nin < col_len ){                   /* truncate columns */
01561      for( col=0 ; col < col_num ; col++ )
01562        col_dat[col] = NI_realloc( col_dat[col] , char, fsiz[col]*nin ) ;
01563    }
01564 
01565    /*-- Have read all data; byte swap if needed, then get outta here --*/
01566 
01567 ReadFinality:
01568 
01569    if( tmode != NI_TEXT_MODE && swap ){
01570      for( col=0 ; col < col_num ; col++ )
01571        NI_swap_column( rt[col] , nin , col_dat[col] ) ;
01572    }
01573 
01574 #ifdef NIML_DEBUG
01575 NI_dpr("Leaving NI_read_columns\n") ;
01576 #endif
01577 
01578    FREEUP ; return nin ;
01579 }
01580 
01581 /*-------------------------------------------------------------------------*/
01582 /*! Decode binary data from the NI_stream ns into a rowtype struct *dpt.
01583     - Note that String (aka NI_STRING) parts are illegal here.
01584     - Return value is 1 if all was OK, 0 if something bad happened.
01585     - Parameter swap indicates that the data coming in needs to be
01586       byte-swapped.
01587       - This is ONLY used to byte-swap the dimension for var-dimen arrays.
01588       - Actual byte-swapping of the data is done in NI_swap_column().
01589 ---------------------------------------------------------------------------*/
01590 
01591 int NI_binary_to_val( NI_stream_type *ns, NI_rowtype *rt, void *dpt, int swap )
01592 {
01593    int nn , jj ;
01594 
01595    if( rt->code == NI_STRING ) return 0 ;            /* shouldn't happen */
01596 
01597    if( rt->size == rt->psiz ){        /* fixed-size type with no padding */
01598                                /* ==> can read directly into data struct */
01599 
01600      jj = NI_stream_readbuf( ns , (char *)dpt , rt->size ) ;
01601      return (jj == rt->size) ;
01602 
01603    } else {                                              /* derived type */
01604 
01605      char *dat = (char *)dpt , **aaa = NULL ;
01606      int ii                  ,  naaa = 0 , iaaa = 0 ;
01607 
01608      if( ROWTYPE_is_varsize(rt) ){         /* variable dim arrays inside */
01609        for( naaa=ii=0 ; ii < rt->part_num ; ii++ )
01610          if( rt->part_dim[ii] >= 0 ) naaa++ ;    /* count var dim arrays */
01611        if( naaa > 0 )
01612          aaa = NI_malloc(char*, sizeof(char *)*naaa) ;  /* save their addresses */
01613      }                                    /* for possible deletion later */
01614 
01615      /* loop over parts and load them;
01616         set nn=0 if read fails at any part (and break out of read loop) */
01617 
01618      for( nn=1,ii=0 ; ii < rt->part_num ; ii++ ){
01619 
01620        if( rt->part_dim[ii] < 0 ){            /* read one fixed dim part */
01621 
01622          nn = NI_binary_to_val( ns, rt->part_rtp[ii], dat+rt->part_off[ii], 0 );
01623 
01624        } else {                                    /* read var dim array */
01625 
01626          char **apt = (char **)(dat+rt->part_off[ii]); /* data in struct */
01627                                                  /* will be ptr to array */
01628          int dim = ROWTYPE_part_dimen(rt,dat,ii) ;  /* dimension of part */
01629          int siz = rt->part_rtp[ii]->size ;          /* size of one part */
01630 
01631          if( swap ) NI_swap4( 1 , &dim ) ;   /* byte-swap dim, which was */
01632                                             /* just read in a moment ago */
01633 
01634          if( dim > 0 ){                         /* need to get some data */
01635            *apt = NI_malloc(char,  siz * dim );            /* make array */
01636 
01637            if( siz != rt->part_rtp[ii]->psiz ){     /* padded values ==> */
01638             for( jj=0 ; jj < dim ; jj++ ){       /* read 1 val at a time */
01639               nn = NI_binary_to_val( ns, rt->part_rtp[ii],
01640                                      *apt + siz * jj , 0  ) ;
01641               if( !nn ) break ;                              /* bad read */
01642             }
01643 
01644            } else {              /* unpadded values ==> read all at once */
01645              jj = NI_stream_readbuf( ns , *apt , siz*dim ) ;
01646              nn = ( jj == siz*dim ) ;
01647            }
01648 
01649          } else {
01650            *apt = NULL ;                    /* dim=0 ==> no array needed */
01651          }
01652          aaa[iaaa++] = *apt ;              /* save for possible deletion */
01653                                           /* if read fails later in loop */
01654        }
01655 
01656        if( !nn ) break ;                            /* some read was bad */
01657      } /* end of loop over parts */
01658 
01659      /* bad news ==> delete any allocated var dim arrays */
01660 
01661      if( !nn ){
01662        for( ii=0 ; ii < iaaa ; ii++ ) NI_free( aaa[ii] ) ;
01663      }
01664      NI_free( aaa ) ;  /* don't need list of var dim arrays no more */
01665    }
01666 
01667    return nn ;
01668 }
01669 
01670 /*-------------------------------------------------------------------------*/
01671 /*! Decode Base64 data from the NI_stream ns into a rowtype struct *dpt.
01672     - Note that String (aka NI_STRING) parts are illegal here.
01673     - Return value is 1 if all was OK, 0 if something bad happened.
01674     - Parameter swap indicates that the data coming in needs to be
01675       byte-swapped.
01676       - This is ONLY used to byte-swap the dimension for var-dimen arrays.
01677       - Actual byte-swapping of the data is done in NI_swap_column().
01678 ---------------------------------------------------------------------------*/
01679 
01680 int NI_base64_to_val( NI_stream_type *ns, NI_rowtype *rt, void *dpt, int swap )
01681 {
01682    int nn , jj ;
01683 
01684    if( rt->code == NI_STRING ) return 0 ;            /* shouldn't happen */
01685 
01686    if( rt->size == rt->psiz ){        /* fixed-size type with no padding */
01687                                /* ==> can read directly into data struct */
01688 
01689      jj = NI_stream_readbuf64( ns , (char *)dpt , rt->size ) ;
01690      return (jj == rt->size) ;
01691 
01692    } else {                                              /* derived type */
01693 
01694      char *dat = (char *)dpt , **aaa = NULL ;
01695      int ii                  ,  naaa = 0 , iaaa = 0 ;
01696 
01697      if( ROWTYPE_is_varsize(rt) ){         /* variable dim arrays inside */
01698        for( naaa=ii=0 ; ii < rt->part_num ; ii++ )
01699          if( rt->part_dim[ii] >= 0 ) naaa++ ;    /* count var dim arrays */
01700        if( naaa > 0 )
01701          aaa = NI_malloc(char*, sizeof(char *)*naaa) ;  /* save their addresses */
01702      }                                    /* for possible deletion later */
01703 
01704      /* loop over parts and load them;
01705         set nn=0 if read fails at any part (and break out of read loop) */
01706 
01707      for( nn=1,ii=0 ; ii < rt->part_num ; ii++ ){
01708 
01709        if( rt->part_dim[ii] < 0 ){            /* read one fixed dim part */
01710 
01711          nn = NI_base64_to_val( ns, rt->part_rtp[ii], dat+rt->part_off[ii], 0 );
01712 
01713        } else {                                    /* read var dim array */
01714 
01715          char **apt = (char **)(dat+rt->part_off[ii]); /* data in struct */
01716                                                  /* will be ptr to array */
01717          int dim = ROWTYPE_part_dimen(rt,dat,ii) ;  /* dimension of part */
01718          int siz = rt->part_rtp[ii]->size ;          /* size of one part */
01719 
01720          if( swap ) NI_swap4( 1 , &dim ) ;   /* byte-swap dim, which was */
01721                                             /* just read in a moment ago */
01722 
01723          if( dim > 0 ){                         /* need to get some data */
01724            *apt = NI_malloc(char,  siz * dim );            /* make array */
01725 
01726            if( siz != rt->part_rtp[ii]->psiz ){     /* padded values ==> */
01727             for( jj=0 ; jj < dim ; jj++ ){       /* read 1 val at a time */
01728               nn = NI_base64_to_val( ns, rt->part_rtp[ii],
01729                                      *apt + siz * jj , 0  ) ;
01730               if( !nn ) break ;                              /* bad read */
01731             }
01732 
01733            } else {              /* unpadded values ==> read all at once */
01734              jj = NI_stream_readbuf64( ns , *apt , siz*dim ) ;
01735              nn = ( jj == siz*dim ) ;
01736            }
01737 
01738          } else {
01739            *apt = NULL ;                    /* dim=0 ==> no array needed */
01740          }
01741          aaa[iaaa++] = *apt ;              /* save for possible deletion */
01742                                           /* if read fails later in loop */
01743        }
01744 
01745        if( !nn ) break ;                            /* some read was bad */
01746      } /* end of loop over parts */
01747 
01748      /* bad news ==> delete any allocated var dim arrays */
01749 
01750      if( !nn ){
01751        for( ii=0 ; ii < iaaa ; ii++ ) NI_free( aaa[ii] ) ;
01752      }
01753      NI_free( aaa ) ;  /* don't need list of var dim arrays no more */
01754    }
01755 
01756    return nn ;
01757 }
01758 
01759 /*-------------------------------------------------------------------------*/
01760 /*! Decode text from the NI_stream into a rowtype struct.
01761     - Parameter ltend != 0 means stop at '<' character.
01762     - Return value is 1 if it works, 0 if it fails.
01763     - If it works, *dpt will be filled with values.
01764     - Note that dpt must be pre-allocated rt->size bytes long.
01765 ---------------------------------------------------------------------------*/
01766 
01767 int NI_text_to_val( NI_stream_type *ns, NI_rowtype *rt, void *dpt, int ltend )
01768 {
01769    int nn ;
01770 
01771    switch( rt->code ){
01772 
01773      /*-- a derived type: fill the parts by recursion --*/
01774 
01775      default:{
01776        char *dat = (char *)dpt , **aaa = NULL ;
01777        int ii , jj ,              naaa = 0 , iaaa = 0 ;
01778 
01779        if( ROWTYPE_is_varsize(rt) ){         /* variable dim arrays inside */
01780          for( naaa=ii=0 ; ii < rt->part_num ; ii++ )
01781            if( rt->part_dim[ii] >= 0 ) naaa++ ;    /* count var dim arrays */
01782          if( naaa > 0 )
01783            aaa = NI_malloc(char*, sizeof(char *)*naaa) ;  /* save their addresses */
01784        }                                    /* for possible deletion later */
01785 
01786        /* loop over parts and load them */
01787 
01788        for( nn=1,ii=0 ; ii < rt->part_num ; ii++ ){
01789 
01790          if( rt->part_dim[ii] < 0 ){                 /* one fixed dim part */
01791 
01792            nn = NI_text_to_val( ns, rt->part_rtp[ii],
01793                                 dat+rt->part_off[ii], ltend );
01794 
01795          } else {                                         /* var dim array */
01796 
01797            char **apt = (char **)(dat+rt->part_off[ii]); /* data in struct */
01798                                                    /* will be ptr to array */
01799            int dim = ROWTYPE_part_dimen(rt,dat,ii) ;  /* dimension of part */
01800            int siz = rt->part_rtp[ii]->size ;   /* size of one part struct */
01801            if( dim > 0 ){
01802              *apt = NI_malloc(char, siz * dim );                  /* make array */
01803              for( jj=0 ; jj < dim ; jj++ ){        /* get values for array */
01804                nn = NI_text_to_val( ns, rt->part_rtp[ii],
01805                                     *apt + siz * jj , ltend ) ;
01806                if( !nn ) break ;
01807              }
01808            } else {
01809              *apt = NULL ;                    /* dim=0 ==> no array needed */
01810            }
01811            aaa[iaaa++] = *apt ;              /* save for possible deletion */
01812 
01813          }
01814 
01815          if( !nn ) break ;                            /* some read was bad */
01816        } /* end of loop over parts */
01817 
01818        /* bad news ==> delete any allocated var dim arrays */
01819 
01820        if( !nn ){
01821          for( ii=0 ; ii < iaaa ; ii++ ) NI_free( aaa[ii] ) ;
01822          NI_free( aaa ) ;
01823          return 0 ;
01824        }
01825        NI_free( aaa ) ;  /* in any case, dump this */
01826      }
01827      break ;
01828 
01829      /*-- the 9 builtin types below here; first up: String! --*/
01830 
01831      case NI_STRING:{
01832         char *val=NULL ;
01833         char **vpt = (char **) dpt ;
01834         nn = NI_decode_one_string( ns , &val , ltend ) ;
01835         if( !nn || val == NULL ) return 0 ;
01836         unescape_inplace(val) ;
01837         *vpt = val ;
01838      }
01839      break ;
01840 
01841      /*-- numeric types below here --*/
01842 
01843      case NI_BYTE:{
01844         double val ;
01845         byte *vpt = (byte *) dpt ;
01846         nn = NI_decode_one_double( ns , &val , ltend ) ;
01847         if( !nn ) return 0 ;
01848         *vpt = (byte) val ;
01849      }
01850      break ;
01851 
01852      case NI_SHORT:{
01853         double val ;
01854         short *vpt = (short *) dpt ;
01855         nn = NI_decode_one_double( ns , &val , ltend ) ;
01856         if( !nn ) return 0 ;
01857         *vpt = (short) val ;
01858      }
01859      break ;
01860 
01861      case NI_INT:{
01862         double val ;
01863         int *vpt = (int *) dpt ;
01864         nn = NI_decode_one_double( ns , &val , ltend ) ;
01865         if( !nn ) return 0 ;
01866         *vpt = (int) val ;
01867      }
01868      break ;
01869 
01870      case NI_FLOAT:{
01871         double val ;
01872         float *vpt = (float *) dpt ;
01873         nn = NI_decode_one_double( ns , &val , ltend ) ;
01874         if( !nn ) return 0 ;
01875         *vpt = (float) val ;
01876      }
01877      break ;
01878 
01879      case NI_DOUBLE:{
01880         double val ;
01881         double *vpt = (double *) dpt ;
01882         nn = NI_decode_one_double( ns , &val , ltend ) ;
01883         if( !nn ) return 0 ;
01884         *vpt = (double) val ;
01885      }
01886      break ;
01887 
01888      case NI_COMPLEX:{
01889         double v1,v2 ;
01890         complex *vpt = (complex *) dpt ;
01891         nn = NI_decode_one_double( ns , &v1 , ltend ) ;
01892         if( !nn ) return 0 ;
01893         nn = NI_decode_one_double( ns , &v2 , ltend ) ;
01894         if( !nn ) return 0 ;
01895         vpt->r = (float) v1 ;
01896         vpt->i = (float) v2 ;
01897      }
01898      break ;
01899 
01900      case NI_RGB:{
01901         double v1,v2,v3 ;
01902         rgb *vpt = (rgb *) dpt ;
01903         nn = NI_decode_one_double( ns , &v1 , ltend ) ;
01904         if( !nn ) return 0 ;
01905         nn = NI_decode_one_double( ns , &v2 , ltend ) ;
01906         if( !nn ) return 0 ;
01907         nn = NI_decode_one_double( ns , &v3 , ltend ) ;
01908         if( !nn ) return 0 ;
01909         vpt->r = (byte) v1 ;
01910         vpt->g = (byte) v2 ;
01911         vpt->b = (byte) v3 ;
01912      }
01913      break ;
01914 
01915      case NI_RGBA:{
01916         double v1,v2,v3,v4 ;
01917         rgba *vpt = (rgba *) dpt ;
01918         nn = NI_decode_one_double( ns , &v1 , ltend ) ;
01919         if( !nn ) return 0 ;
01920         nn = NI_decode_one_double( ns , &v2 , ltend ) ;
01921         if( !nn ) return 0 ;
01922         nn = NI_decode_one_double( ns , &v3 , ltend ) ;
01923         if( !nn ) return 0 ;
01924         nn = NI_decode_one_double( ns , &v4 , ltend ) ;
01925         if( !nn ) return 0 ;
01926         vpt->r = (byte) v1 ;
01927         vpt->g = (byte) v2 ;
01928         vpt->b = (byte) v3 ;
01929         vpt->a = (byte) v4 ;
01930      }
01931      break ;
01932 
01933    } /* end of switch on type */
01934 
01935    return 1 ;  /* good */
01936 }
01937 
01938 /*-------------------------------------------------------------------------*/
01939 /*! Swap bytes in a bunch of rowtype structs.
01940 ---------------------------------------------------------------------------*/
01941 
01942 void NI_swap_column( NI_rowtype *rt , int nrow , char *dat )
01943 {
01944    if( rt == NULL || nrow <= 0 || dat == NULL ) return ;  /* stupid inputs */
01945 
01946    switch( rt->code ){
01947 
01948      case NI_RGB:
01949      case NI_RGBA:
01950      case NI_STRING:
01951      case NI_BYTE:    return ;   /* nothing to do */
01952 
01953      /*-- basic types --*/
01954 
01955      case NI_SHORT:
01956        NI_swap2( nrow , dat ) ;
01957      return ;
01958 
01959      case NI_INT:
01960      case NI_FLOAT:
01961        NI_swap4( nrow , dat ) ;
01962      return ;
01963 
01964      case NI_DOUBLE:
01965        NI_swap8( nrow , dat ) ;
01966      return ;
01967 
01968      case NI_COMPLEX:
01969        NI_swap4( 2*nrow , dat ) ;
01970      return ;
01971 
01972      /* a derived type (use recursion) */
01973 
01974      default:{
01975        int ii , row , fsiz = rt->size ;
01976        char *ptr ;
01977 
01978        for( row=0 ; row < nrow ; row++ ){
01979          ptr = dat + fsiz*row ;     /* ptr to row-th element */
01980 
01981          /* loop over parts and swap them, 1 at a time */
01982 
01983          for( ii=0 ; ii < rt->part_num ; ii++ ){
01984 
01985            if( rt->part_dim[ii] < 0 ){                     /* fixed dim part */
01986 
01987              NI_swap_column( rt->part_rtp[ii] , 1 , ptr+rt->part_off[ii] ) ;
01988 
01989            } else {                                         /* var dim array */
01990 
01991              char **apt = (char **)(ptr+rt->part_off[ii]); /* data in struct */
01992                                                           /* is ptr to array */
01993              int dim = ROWTYPE_part_dimen(rt,dat,ii) ;  /* dimension of part */
01994              NI_swap_column( rt->part_rtp[ii] , dim , *apt ) ;
01995 
01996            }
01997          } /* end of loop over parts */
01998        } /* end of loop over rows */
01999      }
02000      return ;
02001    }
02002 }
02003 
02004 /*--------------------------------------------------------------------------*/
02005 /*! Delete a column of rowtype structs, including any var dim arrays.
02006     Assumes everything was allocated with NI_malloc().
02007     After this is called, the cpt argument should be set to NULL.
02008 ----------------------------------------------------------------------------*/
02009 
02010 void NI_free_column( NI_rowtype *rt , int col_len , void *cpt )
02011 {
02012    char *dat=(char *)cpt , *ptr ;
02013    int ii , jj ;
02014 
02015    if( rt == NULL || dat == NULL || col_len < 1 ) return ; /* nothing to do */
02016 
02017    /* if has variable dim arrays inside, free them */
02018 
02019    if( ROWTYPE_is_varsize(rt) ){
02020      for( ii=0 ; ii < col_len ; ii++ ){            /* loop over structs */
02021        ptr = dat + rt->size * ii ;            /* pointer to this struct */
02022        for( jj=0 ; jj < rt->part_num ; jj++ ){       /* loop over parts */
02023          if( rt->part_typ[jj] == NI_STRING ||
02024              rt->part_dim[jj] >= 0           ){
02025            char **apt = (char **)(ptr+rt->part_off[jj]) ;
02026            NI_free(*apt) ; *apt = NULL ;
02027          }
02028        }
02029      }
02030    }
02031 
02032    /* free the column array itself */
02033 
02034    NI_free(cpt) ; return ;
02035 }
02036 
02037 /*----------------------------------------------------------------------------*/
02038 /*! Copy a column of rowtype structs, including var dim arrays.  Return
02039     is the pointer to the copy.
02040 ------------------------------------------------------------------------------*/
02041 
02042 void * NI_copy_column( NI_rowtype *rt , int col_len , void *cpt )
02043 {
02044    char *dat=(char *)cpt , *ndat , *nptr , *qpt ;
02045    int ii , jj , kk ;
02046 
02047    if( rt == NULL || dat == NULL || col_len < 1 ) return NULL ;
02048 
02049    /* make a quick (surface) copy */
02050 
02051    ndat = NI_malloc(char,  rt->size * col_len ) ;  /* new data column */
02052    memcpy( ndat , dat , rt->size * col_len ) ;     /* the quick copying */
02053 
02054    /* copy any var dim arrays inside, since the pointers
02055       in ndat right now still point to data in dat,
02056       but we want ndat to be entirely self-contained!  */
02057 
02058    if( ROWTYPE_is_varsize(rt) ){
02059      for( ii=0 ; ii < col_len ; ii++ ){                 /* loop over structs */
02060        nptr = ndat + rt->size * ii ;                   /* ptr to this struct */
02061        for( jj=0 ; jj < rt->part_num ; jj++ ){            /* loop over parts */
02062 
02063          if( rt->part_typ[jj] == NI_STRING ){               /* a string part */
02064            char **apt = (char **)(nptr+rt->part_off[jj]) ;   /* *apt => data */
02065            qpt = NI_strdup(*apt) ; *apt = qpt ;
02066          } else if( rt->part_dim[jj] >= 0 ){
02067            char **apt = (char **)(nptr+rt->part_off[jj]) ;   /* *apt => data */
02068            if( *apt != NULL ){
02069              kk  = ROWTYPE_part_dimen(rt,nptr,jj) * rt->part_rtp[jj]->size ;
02070              qpt = NI_malloc(char, kk) ; memcpy(qpt,*apt,kk) ; *apt = qpt ;
02071            }
02072          }
02073        }
02074      }
02075    }
02076 
02077    return ndat ;
02078 }
02079 
02080 /*--------------------------------------------------------------------------*/
02081 /*! Return the length in bytes of a column of data (not counting padding).
02082     The pointer to the data is needed since it might contain variable
02083     size data (String or vardim arrays).
02084 ----------------------------------------------------------------------------*/
02085 
02086 int NI_size_column( NI_rowtype *rt , int col_len , void *cpt )
02087 {
02088    char *dat = (char *)cpt ;
02089    int ii , ndat ;
02090 
02091    if( rt == NULL || col_len <= 0 )
02092      return 0;                                    /* nonsense input */
02093    if( !ROWTYPE_is_varsize(rt) || dat == NULL )
02094      return (col_len*rt->psiz);                   /* fixed dim struct */
02095 
02096    /* must loop through elements and add up their variable sizes */
02097 
02098    ndat = 0 ;
02099    for( ii=0 ; ii < col_len ; ii++ )
02100      ndat += NI_rowtype_vsize( rt , dat + ii*rt->size ) ;
02101 
02102    return ndat ;
02103 }
 

Powered by Plone

This site conforms to the following standards: