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_header.c

Go to the documentation of this file.
00001 #include "niml_private.h"
00002 
00003 /****************************************************************************/
00004 /****************** Functions to process a NIML header **********************/
00005 /****************************************************************************/
00006 
00007 /*! Macro to define skippable characters. */
00008 
00009 #define SKIPABL(c) ((c)=='#' || isspace(c))
00010 
00011 /*--------------------------------------------------------------------------*/
00012 /*! Find an attribute in a header_stuff struct.  Returns the RHS or NULL.
00013 ----------------------------------------------------------------------------*/
00014 
00015 char * get_header_attribute( header_stuff *hs , char *attname )
00016 {
00017    int nn ;
00018    static char *zorkon = "\0" ;
00019 
00020    if( hs == NULL ) return NULL ;
00021 
00022    for( nn=0 ; nn < hs->nattr ; nn++ )
00023      if( strcmp(hs->lhs[nn],attname) == 0 ) break ;
00024 
00025    if( nn == hs->nattr ) return NULL ;
00026 
00027    if( hs->rhs[nn] == NULL ) return zorkon ;
00028 
00029    return hs->rhs[nn] ;
00030 }
00031 
00032 /*--------------------------------------------------------------------------*/
00033 /*! Deallocate a header_stuff struct.
00034 ----------------------------------------------------------------------------*/
00035 
00036 void destroy_header_stuff( header_stuff *hs )
00037 {
00038    int ii ;
00039    if( hs == NULL ) return ;
00040    NI_free(hs->name) ;
00041    for( ii=0 ; ii < hs->nattr ; ii++ ){
00042       if( hs->lhs != NULL ) NI_free( hs->lhs[ii] ) ;
00043       if( hs->rhs != NULL ) NI_free( hs->rhs[ii] ) ;
00044    }
00045    NI_free( hs ) ;
00046 }
00047 
00048 /*-------------------------------------------------------------------------*/
00049 /*! Find an isolated string in the input array of char.
00050 
00051     - nst = start position
00052     - nch = total number of data bytes
00053     - ch  = array of data bytes
00054 
00055     Return value is an intpair with the .i component indicating the
00056     start position of the string in the data and the .j indicating
00057     the byte AFTER the end of the string.  If the .i component is
00058     negative, then no string was found.
00059 ---------------------------------------------------------------------------*/
00060 
00061 intpair find_string( int nst, int nch, char *ch )
00062 {
00063    intpair ans = {-1,-1} ;  /* default answer ==> nothing found */
00064    int ii,jj ;
00065    char quot ;
00066 
00067 #ifdef NIML_DEBUG
00068 NI_dpr("  ENTER find_string: nst=%d nch=%d\n",nst,nch) ;
00069 #endif
00070 
00071    if( nst >= nch || nch < 2 || ch == NULL ) return ans;        /* bad input */
00072 
00073    for( ii=nst; ii<nch && !IS_STRING_CHAR(ch[ii]); ii++ ) ; /* skip to start */
00074 
00075    if( ii >= nch ) return ans ;                                 /* bad input */
00076 
00077    if( IS_QUOTE_CHAR(ch[ii]) ){                             /* quoted string */
00078       if( ii == nch-1 ) return ans ;                            /* bad input */
00079       quot = ch[ii] ; ii++ ;
00080       for( jj=ii ; jj<nch && ch[jj] != quot ; jj++ ) ;      /* skip to close */
00081    } else {
00082       for( jj=ii+1 ; jj<nch && IS_STRING_CHAR(ch[jj]) ; jj++ ) ; /* to blank */
00083    }
00084 
00085    ans.i = ii ; ans.j = jj ; /* answer starts at ch[ii] and goes to ch[jj-1] */
00086    return ans ;
00087 }
00088 
00089 /*--------------------------------------------------------------------------*/
00090 /*! Parse into strings a <header and=its attributes="stuff">.
00091 
00092     - ndat   = number of data bytes input
00093     - dat    = data bytes input
00094     - *nused = output number of bytes consumed (=index of byte AFTER the closing '>').
00095 
00096     Return value is a pointer to a header_stuff struct;
00097     if NULL is returned, something real bad happened (and *nused won't
00098     be assigned).
00099 ----------------------------------------------------------------------------*/
00100 
00101 header_stuff * parse_header_stuff( int ndat, char *dat, int *nused )
00102 {
00103    header_stuff *hs ; /* return value */
00104    int id,jd , nn ;
00105    intpair ss ;
00106 
00107    if( ndat < 2 || dat == NULL ) return NULL ;        /* bad input */
00108 
00109 #ifdef NIML_DEBUG
00110 NI_dpr("ENTER parse_header_stuff: %.*s\n",ndat,dat) ;
00111 #endif
00112 
00113    for( id=0 ; id < ndat && dat[id] != '<' ; id++ ) ; /* skip to opening '<' */
00114 
00115    if( id >= ndat-1 ) return NULL ;                   /* bad input */
00116 
00117    hs = NI_malloc(header_stuff,sizeof(header_stuff)); /* make output struct */
00118    hs->nattr = hs->empty = 0 ;
00119    hs->name  = NULL ;
00120    hs->lhs   = hs->rhs = NULL ;
00121 
00122    /* find and assign name string (immediately after '<') */
00123 
00124    ss = find_string( id+1 , ndat , dat ) ;
00125 
00126    if( ss.i < 0 || ss.j <= ss.i ){
00127      destroy_header_stuff( hs ) ; return NULL ;   /* no name string */
00128    }
00129 
00130    nn = ss.j - ss.i ;                              /* string length */
00131    hs->name = NI_malloc(char, nn+1) ;
00132    NI_strncpy( hs->name , dat+ss.i , nn+1 ) ;
00133 
00134 #ifdef NIML_DEBUG
00135 NI_dpr("   parse_header_stuff: name = %s\n",hs->name) ;
00136 #endif
00137 
00138    /* start scanning for next string at location id */
00139 
00140    id = ss.j ; if( IS_QUOTE_CHAR(dat[id]) ) id++ ;
00141 
00142    /* find and assign attribute strings */
00143 
00144    while(1){
00145 
00146 #ifdef NIML_DEBUG
00147 NI_dpr("   parse_header_stuff: scan start at id=%d\n",id) ;
00148 #endif
00149 
00150       for( ; id < ndat && SKIPABL(dat[id]) ; id++ ) ; /* skip blanks */
00151 
00152       if( id >= ndat ) break ;                 /* end of input found */
00153 
00154       if( dat[id] == '>' ) break ;                  /* ">" end found */
00155 
00156       if( dat[id] == '/' ){                        /* "/>" end found */
00157          if( id < ndat-1 ) id++ ;                  /* skip the '>'   */
00158          hs->empty = 1 ;                   /* mark header as 'empty' */
00159          break ;                /* done with scanning for attributes */
00160       }
00161 
00162       if( dat[id] == '?' ){                            /* "?>" found */
00163         if( id < ndat-1 ) id++ ;           /* ==> this is a procins! */
00164         hs->empty = 1 ;
00165         break ;
00166       }
00167 
00168       /* find next string */
00169 
00170       ss = find_string( id , ndat , dat ) ;
00171 
00172       if( ss.i < 0 || ss.j <= ss.i ) break ; /* didn't find a string */
00173 
00174 #ifdef NIML_DEBUG
00175 NI_dpr("   parse_header_stuff: next string = %.*s\n",ss.j-ss.i,dat+ss.i) ;
00176 #endif
00177 
00178       /* extend size of attribute arrays */
00179 
00180       hs->lhs = NI_realloc( hs->lhs , char*, sizeof(char *)*(hs->nattr+1) ) ;
00181       hs->rhs = NI_realloc( hs->rhs , char*, sizeof(char *)*(hs->nattr+1) ) ;
00182 
00183       /* this is the LHS string */
00184 
00185       nn = ss.j - ss.i ;                      /* length of string */
00186       hs->lhs[hs->nattr] = NI_malloc(char, nn+1) ;
00187       NI_strncpy( hs->lhs[hs->nattr] , dat+ss.i , nn+1 ) ;
00188       unescape_inplace( hs->lhs[hs->nattr] ) ;
00189 
00190       hs->rhs[hs->nattr] = NULL ;             /* in case there is no RHS */
00191 
00192       id = ss.j ;
00193       if( id >= ndat ) break ;                      /* end of input ? */
00194       if( IS_QUOTE_CHAR(dat[id]) ) id++ ;           /* skip close quote */
00195       while( id < ndat && SKIPABL(dat[id]) ) id++ ; /* skip blanks */
00196       if( id >= ndat ) break ;                      /* end of input ? */
00197 
00198       if( dat[id] != '=' ){                   /* no '=' means no RHS */
00199          (hs->nattr)++ ;                      /* count the LHS and */
00200          continue ;                           /* go get next attribute */
00201       }
00202 
00203       id++ ;                                        /* skip the '=' */
00204       while( id < ndat && SKIPABL(dat[id]) ) id++ ; /* skip blanks */
00205       if( id >= ndat ) break ;                      /* end of input ? */
00206 
00207       /* find next string (the RHS) */
00208 
00209       ss = find_string( id , ndat , dat ) ;
00210 
00211       if( ss.i < 0 || ss.j <= ss.i ) break ; /* didn't find a string */
00212 
00213 #ifdef NIML_DEBUG
00214 NI_dpr("   parse_header_stuff: next string = %.*s\n",ss.j-ss.i,dat+ss.i) ;
00215 #endif
00216 
00217       /* this is the RHS string */
00218 
00219       nn = ss.j - ss.i ;                      /* length of string */
00220       hs->rhs[hs->nattr] = NI_malloc(char, nn+1) ;
00221       NI_strncpy( hs->rhs[hs->nattr] , dat+ss.i , nn+1 ) ;
00222       unescape_inplace( hs->rhs[hs->nattr] ) ;
00223 
00224       (hs->nattr)++ ;                  /* increment attribute count */
00225 
00226       /* start scanning for next string at location id */
00227 
00228       id = ss.j ;
00229       if( IS_QUOTE_CHAR(dat[id]) ) id++ ;  /* skip closing quote */
00230 
00231    } /* end of loop over input */
00232 
00233    if( nused != NULL ){
00234       if( id >= ndat ) id = ndat-1 ;
00235       *nused = id+1 ;              /* number of bytes used from dat */
00236    }
00237 
00238    return hs ;                         /* the goal of all that work */
00239 }
00240 
00241 /*--------------------------------------------------------------------*/
00242 /*! Decode a single type field.  Return value is an intpair with
00243     the .i component being the type code and the .j component being
00244     the number of characters consumed.  If the .i component is -1,
00245     then no legal type was found (.j is still the number of chars
00246     used in the scan).
00247 ----------------------------------------------------------------------*/
00248 
00249 intpair decode_type_field( char *tf )
00250 {
00251    intpair ans = {-1,1} ;  /* default answer */
00252    char tname[256] ;
00253    int jj ;
00254 
00255    /* check input for goodness */
00256 
00257    if( tf == NULL || !isalpha(*tf) ) return ans ;  /* prima facie bad */
00258 
00259 #if 1    /*** The new way! Look for full names, not initials - RWCcox ***/
00260 
00261    /* copy input into local string,
00262       as long as 'name' characters are found,
00263       then get the integer code for this type name */
00264 
00265    for( jj=0 ; jj < 255 && IS_NAME_CHAR(tf[jj]) ; jj++ ) tname[jj] = tf[jj];
00266    tname[jj] = '\0' ;
00267    ans.i = NI_rowtype_name_to_code( tname ) ;  /* where the names are stored */
00268    ans.j = jj ;
00269 
00270 #else    /*** This is the old way! Replaced on 12 Feb 2003 - RWCox ***/
00271 
00272    /* check if tf[0] starts a full datum name,
00273       or if it is just an initial              */
00274 
00275    switch( tf[0] ){
00276 
00277       default: break ;  /* not a legal datum character */
00278 
00279       case 'b':
00280         ans.i = NI_BYTE ;
00281         if( strncmp(tf,"byte"   ,4) == 0 ) ans.j = 4 ;
00282       break ;
00283 
00284       case 's':
00285         ans.i = NI_SHORT ;
00286         if( strncmp(tf,"short"  ,5) == 0 ) ans.j = 5 ;
00287       break ;
00288 
00289       case 'i':
00290         ans.i = NI_INT ;
00291         if( strncmp(tf,"int"    ,3) == 0 ) ans.j = 3 ;
00292       break ;
00293 
00294       case 'f':
00295         ans.i = NI_FLOAT ;
00296         if( strncmp(tf,"float"  ,5) == 0 ) ans.j = 5 ;
00297       break ;
00298 
00299       case 'c':
00300         ans.i = NI_COMPLEX ;
00301         if( strncmp(tf,"complex",7) == 0 ) ans.j = 7 ;
00302       break ;
00303 
00304       case 'd':
00305         ans.i = NI_DOUBLE ;
00306         if( strncmp(tf,"double" ,6) == 0 ) ans.j = 6 ;
00307       break ;
00308 
00309       case 'r':
00310         ans.i = NI_RGB ;
00311         if( strncmp(tf,"rgb"    ,3) == 0 ) ans.j = 3 ;
00312       break ;
00313 
00314       case 'R':
00315         ans.i = NI_RGBA ;
00316         if( strncmp(tf,"RGBA"   ,4) == 0 ) ans.j = 4 ;
00317       break ;
00318 
00319       case 'S':
00320         ans.i = NI_STRING ;
00321         if( strncmp(tf,"STRING" ,6) == 0 ) ans.j = 6 ;
00322       break ;
00323    }
00324 #endif
00325 
00326    return ans ;
00327 }
00328 
00329 /*--------------------------------------------------------------------*/
00330 /*! Decode a single string into a bunch of strings, separated
00331     by characters from the list in sep.
00332     - Passing sep in as NULL means to use "," as the separator.
00333     - In each sub-string, leading and trailing blanks will be excised.
00334     - This can result in 0 length strings (e.g., "1,,2," will result
00335       in the second and fourth output strings having 0 length).
00336 ----------------------------------------------------------------------*/
00337 
00338 NI_str_array * NI_decode_string_list( char *ss , char *sep )
00339 {
00340    NI_str_array *sar ;
00341    int num , nn,id,jd , lss ;
00342 
00343    if( ss == NULL || ss[0] == '\0' ) return NULL ; /* bad input */
00344 
00345    if( sep == NULL || sep[0] == '\0' ) sep = "," ;  /* default sep */
00346 
00347    sar = NI_malloc(NI_str_array, sizeof(NI_str_array)) ;  /* create output */
00348    sar->num = 0 ; sar->str = NULL ;
00349 
00350    /* scan for sub-strings */
00351 
00352    lss = NI_strlen(ss) ;
00353    num = id = 0 ;
00354    while( id < lss ){
00355 
00356       /* skip current position ahead over whitespace */
00357 
00358       while( id < lss && isspace(ss[id]) ) id++ ;
00359       if( id == lss ) break ;                           /* ran out of string */
00360 
00361       jd = id ;               /* save current position (start of new string) */
00362 
00363       /* skip ahead until ss[id] is a separator [or a space - 10 Dec 2002] */
00364 
00365       while( id < lss && strchr(sep,ss[id]) == NULL && !isspace(ss[id]) ) id++;
00366       if( id == jd ){ id++; continue; }    /* is only a separator? */
00367 
00368       /* new sub-string runs from ss[jd] to ss[id-1] */
00369 
00370       sar->str = NI_realloc( sar->str , char*, sizeof(char *)*(num+1) ) ;
00371 
00372       nn = id-jd ;                                   /* length of sub-string */
00373 #if 0
00374       while( nn > 0 && isspace(ss[jd+nn-1]) ) nn-- ; /* clip trailing blanks */
00375 #endif
00376       sar->str[num] = NI_malloc(char, nn+1) ;              /* make output string  */
00377       if( nn > 0 ) memcpy(sar->str[num],ss+jd,nn) ;  /* copy sub-string    */
00378       sar->str[num++][nn] = '\0' ;                   /* terminate output  */
00379 
00380       id++ ;                                         /* skip separator  */
00381    }
00382 
00383    sar->num = num ; return sar ;
00384 }
00385 
00386 /*--------------------------------------------------------------------*/
00387 /*! Decode a ni_dimen string into an array of integers.
00388   Returns NULL if the input is bad bad bad.
00389 ----------------------------------------------------------------------*/
00390 
00391 int_array * decode_dimen_string( char *ds )
00392 {
00393    int num , dd,nn,id,jd , lds ;
00394    int_array *iar ;
00395 
00396    if( ds == NULL || ds[0] == '\0' ) return NULL ;
00397 
00398    iar = NI_malloc(int_array, sizeof(int_array)) ;  /* create output */
00399    iar->num = 0 ; iar->ar = NULL ;
00400 
00401    /* scan string for integers */
00402 
00403    num = id = 0 ;
00404    lds = NI_strlen(ds) ;
00405    do{
00406       /* skip ahead until ds[id] is a digit */
00407 
00408       while( id < lds && !isdigit(ds[id]) ) id++ ;
00409       if( id == lds ) break ;                      /* end of input */
00410 
00411       /* decode integer starting here */
00412 
00413       nn = jd = 0 ;
00414       sscanf( ds+id , "%d%n" , &jd , &nn ) ;       /* get the count */
00415       if( jd < 0 || nn <= 0 ) break ;              /* something bad */
00416       id += nn ;                                   /* skip these chars */
00417 
00418       /* extend output array, store new dimension in it */
00419 
00420       iar->ar = NI_realloc( iar->ar , int, sizeof(int)*(num+1) ) ;
00421       iar->ar[num++] = jd ;
00422    } while(1) ;
00423 
00424    if( num == 0 ){ NI_free(iar); return NULL; }    /* bad */
00425 
00426    iar->num = num ; return iar ;
00427 }
00428 
00429 /*--------------------------------------------------------------------*/
00430 /*! Decode a data type string into an array of integer codes.
00431   Returns NULL if the input is bad bad bad.
00432 ----------------------------------------------------------------------*/
00433 
00434 int_array * decode_type_string( char *ts )
00435 {
00436    int num, typ, lts, id,jd, nn,kk ;
00437    int_array *iar ;
00438    intpair dc ;
00439 
00440    if( ts == NULL || ts[0] == '\0' ) return NULL ;
00441 
00442    iar = NI_malloc(int_array, sizeof(int_array)) ;  /* create output */
00443    iar->num = 0 ; iar->ar = NULL ;
00444 
00445    /* scan type string to find counts/fields and add to output */
00446 
00447    lts = NI_strlen(ts) ;
00448    num = 0 ;            /* will be count of fields */
00449 
00450    for( id=kk=0 ; id < lts ; ){  /* loop over input string */
00451 
00452       if( isdigit(ts[id]) ){   /* a count prefix */
00453          jd = nn = 0 ;
00454          sscanf( ts+id , "%d%n" , &jd , &nn ) ;   /* get the count */
00455          if( jd <= 0 || nn <= 0 ){                /* shouldn't happen */
00456             NI_free(iar->ar) ; NI_free(iar) ; return NULL ;
00457          }
00458          id += nn ;                  /* skip count prefix characters */
00459          if( ts[id] == '*' ) id++ ;  /* allow for "3*float" */
00460 
00461       } else if( isalpha(ts[id]) ){   /* start of a type name */
00462          jd = 1 ;                    /* default count of 1 */
00463 
00464       } else {
00465          id++ ; continue ;           /* skip this character */
00466       }
00467 
00468       dc = decode_type_field( ts+id ) ;
00469 
00470       /* dc.i = type code; dc.j = character count used to get type code */
00471 
00472       id += dc.j ;              /* skip these characters */
00473       if( dc.i < 0 ) continue ; /* bad type code */
00474 
00475       num += jd ;               /* this many fields so far */
00476 
00477       /* extend output array length */
00478 
00479       iar->ar = NI_realloc( iar->ar , int, sizeof(int)*num ) ;
00480 
00481       /* put values into output array */
00482 
00483       for( nn=0 ; nn < jd ; nn++ ) iar->ar[kk++] = dc.i ;
00484 
00485    } /* end of loop over input string */
00486 
00487    /* nothing found? */
00488 
00489    if( num <= 0 ){
00490       NI_free(iar->ar) ; NI_free(iar) ; return NULL ; /* bad */
00491    }
00492 
00493    iar->num = num ; return iar ;
00494 }
 

Powered by Plone

This site conforms to the following standards: