G:/ScriptBasic/source/confpile.c

Go to the documentation of this file.
00001 /* FILE: confpile.c
00002    HEADER: confpile.h
00003 
00004 TO_HEADER:
00005 
00006 */
00007 
00008 /*POD
00009 =H Compile Configuration Information Text File
00010 
00011 The functions in this file implement the features that let a program to
00012 read the configuration information from a text file.
00013 
00014 The text file reading is performed using the lexical analyzer of the module R<lsp/index>
00015 
00016 CUT*/
00017 
00018 #include <stdio.h>
00019 #include <string.h>
00020 #include <ctype.h>
00021 #include <stdlib.h>
00022 
00023 #include "conftree.h"
00024 #include "lsp.h"
00025 #include "confpile.h"
00026 
00027 #define ALLOC(X) (pCT->memory_allocating_function((X),pCT->pMemorySegment))
00028 #define FREE(X)  (pCT->memory_releasing_function((X),pCT->pMemorySegment))
00029 
00030 /*POD
00031 =section BuildSubTree
00032 =H Build a sub-tree from the lisp structure
00033 
00034 This function recursively builds up the subtrees.
00035 The arguments:
00036 
00037 =itemize
00038 =item T<pCT> is the configuration tree class object pointer
00039 =item T<pLSP> is the LISP structure handling functions class object pointer
00040 =item T<plNodeIndex> is the actual first free node id
00041 =item T<plSindex> is the actual string index (first free character location in the string table)
00042 =item T<q> is the root of the LISP structure to convert
00043 =noitemize
00044 
00045 =verbatim
00046 /**/
00047 static int BuildSubTree(ptConfigTree pCT,
00048                         tLspObject *pLSP,
00049                         CFT_NODE *plNindex, /* node index   */
00050                         long *plSindex, /* string index */
00051                         LVAL q){
00052 /*noverbatim
00053 B<This is a static internal function!>
00054 CUT*/
00055   LVAL r;
00056   long prev;
00057   CFT_NODE lThisNode;
00058 
00059   prev = 0; /* when we start there is no previous element where we have to fill the 'next' pointer */
00060   
00061   while( q ){/* go through the LISP list  */
00062 
00063     /* store the location where we will copy the key */
00064     pCT->Root[(*plNindex)-1].lKey = *plSindex;
00065     /* if there is a previous node then we are the next */
00066     if( prev )pCT->Root[prev-1].lNext = *plNindex;
00067     /* we dont have a next currently, the next iteration may overwrite this */
00068     pCT->Root[(*plNindex)-1].lNext = 0;
00069     /* and for the next iteration we are going to be the previous */
00070     prev = *plNindex;
00071 
00072     /* now copy the key to the string table at the location we remembered in the node */
00073     strcpy(pCT->StringTable+*plSindex,getsymbol(car(q)));
00074     /* and step the string index after the copied string */
00075     *plSindex += strlen(getsymbol(car(q))) +1;
00076 
00077     /* r becomes the atom that follows the key string. aka (keystring r) */
00078     r = cadr(q);
00079     if( consp(r) ){/* if this is a compound node with sub-keys */
00080       lThisNode = *plNindex;
00081       /* the first sub node will be placed on the first free node, that is :   */
00082       ++(*plNindex);
00083       pCT->Root[lThisNode-1].Val.lVal = (*plNindex);
00084       /* this is a compound node */
00085       pCT->Root[lThisNode-1].fFlag = CFT_NODE_BRANCH;
00086       /* call itself recursively to build up the node
00087          note that this may increase the node and string index */
00088       BuildSubTree(pCT,
00089                    pLSP,
00090                    plNindex,
00091                    plSindex,
00092                    r);
00093       }else{
00094       /* this is not a compound node */
00095       if( stringp(r) || symbolp(r) ){
00096         strcpy(pCT->StringTable+*plSindex,getstring(r));
00097         pCT->Root[(*plNindex)-1].Val.lVal = *plSindex;
00098         pCT->Root[(*plNindex)-1].fFlag = CFT_NODE_LEAF | CFT_TYPE_STRING;
00099         *plSindex += strlen(getstring(r)) +1;
00100         }else
00101       if( floatp(r) ){
00102         pCT->Root[(*plNindex)-1].Val.dVal = getfloat(r);
00103         pCT->Root[(*plNindex)-1].fFlag = CFT_NODE_LEAF | CFT_TYPE_REAL;
00104         }else
00105       if( integerp(r) ){
00106         pCT->Root[(*plNindex)-1].Val.lVal = getint(r);
00107         pCT->Root[(*plNindex)-1].fFlag = CFT_NODE_LEAF | CFT_TYPE_INTEGER;
00108         }
00109       /* step to the next node */
00110       (*plNindex)++;
00111       }
00112     /* step for the next node on the same level */
00113     q = cddr(q);
00114     }
00115   return 0;
00116   }
00117 
00118 extern int GlobalDebugDisplayFlag;
00119 
00120 /*POD
00121 =section RemoveNil
00122 =H Remove symbols that have empty value
00123 
00124 This function is used to remove the symbols and their values that have T<NIL> value. This
00125 is sometimes, like in cases:
00126 
00127 =verbatim
00128 run (
00129  ; start "runthis.bas"
00130  )
00131 =noverbatim
00132 
00133 is hard to debug.
00134 
00135 =verbatim
00136 /**/
00137 static void RemoveNil(ptConfigTree pCT,
00138                      tLspObject *pLSP,
00139                      LVAL *q){
00140 /*noverbatim
00141 B<This is a static internal function!>
00142 CUT*/
00143   LVAL r,*p;
00144 
00145   if( NULL == q )return;
00146 
00147   p = q;
00148   while( *q ){
00149     r = cadr(*q);
00150     if( NULL == r ){
00151       *q = cddr(*q);
00152       continue;
00153       }
00154     if( consp(r) ){
00155       RemoveNil(pCT,pLSP,&((*q)->n_value.n_cons._cdr->n_value.n_cons._car));
00156       }
00157     if( *q )
00158       q = & ( (*q)->n_value.n_cons._cdr);
00159     if( *q )
00160       q = & ( (*q)->n_value.n_cons._cdr);
00161     }
00162   return;
00163   }
00164 
00165 /*POD
00166 =section CountSubTree
00167 =H Count the size of the sub-tree
00168 
00169 This function is called to calculate the number of nodes and the size of the string table that is needed
00170 to store the configuration information.
00171 
00172 =verbatim
00173 /**/
00174 static int CountSubTree(ptConfigTree pCT,
00175                         tLspObject *pLSP,
00176                         long *plNodeCounter,
00177                         long *plStringCounter,
00178                         LVAL q){
00179 /*noverbatim
00180 B<This is a static internal function!>
00181 CUT*/
00182   LVAL r;
00183   int iError;
00184   while( q ){
00185     (*plNodeCounter)++;
00186     if( ! symbolp(car(q)) ){
00187       if( GlobalDebugDisplayFlag ){
00188         fprintf(stderr,"The node should have been a symbol.\n");
00189         pprint(q,stderr);
00190         }
00191       return CFT_ERROR_SYNTAX;
00192       }
00193     *plStringCounter += strlen(getsymbol(car(q))) + 1;
00194     r = cadr(q);
00195     if( consp(r) ){
00196       iError = CountSubTree(pCT,pLSP,plNodeCounter,plStringCounter,r);
00197       if( iError )
00198         return CFT_ERROR_SYNTAX;
00199       }else{
00200       if( stringp(r) || symbolp(r) ){
00201         *plStringCounter += strlen( getstring(r) ) + 1;
00202         }else{
00203         if( (!floatp(r)) && (!integerp(r)) ){
00204           if( GlobalDebugDisplayFlag ){
00205             fprintf(stderr,"The node should have been an integer, float or integer.\n");
00206             pprint(r,stderr);
00207             fprintf(stderr,"This is the value of the symbol ");
00208             pprint(q,stderr);
00209             }
00210           return CFT_ERROR_SYNTAX;
00211           }
00212         }
00213       }
00214     q = cddr(q);
00215     }
00216   return 0;
00217   }
00218 
00219 /*POD
00220 =section cft_ReadTextConfig
00221 =H Read configuration information from a text file
00222 
00223 This function opens and reads the configuration information from a text file. The argumentum
00224 T<pCT> should point to an intialized T<tConfigTree> structure. Initialization has to be done
00225 calling R<conftree/cft_init>.
00226 
00227 The built up structure is stored in the structure pointed by T<pCT> and values can be extracted
00228 from it calling the functions of R<conftree/index>
00229 /*FUNCTION*/
00230 int cft_ReadTextConfig(ptConfigTree pCT,
00231                        char *pszFileName
00232   ){
00233 /*noverbatim
00234 CUT*/
00235   FILE *fp;
00236   tLspObject MyLSP,*pLSP;
00237   LVAL q;
00238   int iError;
00239   long lNindex,lSindex;
00240 
00241   pLSP = &MyLSP;
00242   lsp_init(pLSP,-1,1,pCT->memory_allocating_function,
00243                     pCT->memory_releasing_function,
00244                     pCT->pMemorySegment);
00245   fp = fopen(pszFileName,"r");
00246   if( fp == NULL )return CFT_ERROR_FILE;
00247   q = readlist(fp);
00248   fclose(fp);
00249   pCT->cNode = 0;
00250   pCT->cbStringTable = 0;
00251   RemoveNil(pCT,pLSP,&q);
00252   if( iError = CountSubTree(pCT,
00253                             pLSP,
00254                             &(pCT->cNode),
00255                             &(pCT->cbStringTable),
00256                             q)                       )return iError;
00257   if( pCT->cNode == 0 )return CFT_ERROR_EMPTY;
00258   pCT->Root = ALLOC(pCT->cNode*sizeof(tConfigNode));
00259   if( pCT->Root == NULL )return CFT_ERROR_MEMORY;
00260   pCT->StringTable = ALLOC(pCT->cbStringTable);
00261   if( pCT->StringTable == NULL ){
00262     FREE(pCT->Root);
00263     return CFT_ERROR_MEMORY;
00264     }
00265   lNindex = 1;
00266   lSindex = 0;
00267   BuildSubTree(pCT,pLSP,&lNindex,&lSindex,q);
00268   freelist(q);
00269   return 0;
00270   }
00271 
00272 /*POD
00273 =section DumpTree
00274 =H Recursive function to dump a subtree
00275 
00276 This fucntion dumps a subtree of the configuration to the output file.
00277 The printing is formatted according to the LISP notation of the text
00278 version of the configuration. Thus a file dumped using this function
00279 (invokable using the option T<-D> with scriba) can later be compiled
00280 back to binary format.
00281 
00282 The printing is also indented and the basic indentation should be
00283 specified in the argument T<offset>. When a subtree is printed using
00284 recursive call this argument is increased by two and thus the branches
00285 are written each time two characters to the right as they are nested.
00286 
00287 Arguments:
00288 
00289 =itemize
00290 =item T<pCT> is the whole configuration information structure
00291 =item T<fp> the opened file where the information is to be sent
00292 =item T<hNode> is the first node of the subtree. This is not the BRANCH node
00293       but alread the first node in the subtree
00294 =item T<offset> the number of initial spaces to print in front of each line (except
00295       inside multi-line string literals)
00296 =noitemize
00297 
00298 /*FUNCTION*/
00299 static int DumpTree(ptConfigTree pCT,
00300                     FILE *fp,
00301                     CFT_NODE hNode,
00302                     int offset
00303   ){
00304 /*noverbatim
00305 Note that this function is T<static> and is not meant to be called from outside. The "head"
00306 function that initializes the recursive printing is R<cft_DumpConfig>.
00307 CUT*/
00308   CFT_NODE hNodeIter;
00309   char *s;
00310   char *t;
00311 
00312   hNodeIter = hNode;
00313   while( hNodeIter ){
00314     if( (pCT->Root[hNodeIter-1].fFlag&CFT_NODE_MASK) == CFT_NODE_BRANCH ){
00315       fprintf(fp,"%*s%s (\n",offset,"",pCT->StringTable+pCT->Root[hNodeIter-1].lKey);
00316       DumpTree(pCT,fp,cft_EnumFirst(pCT,hNodeIter),offset+2);
00317       fprintf(fp,"%*s )\n",offset,"");
00318       }else
00319     if( (pCT->Root[hNodeIter-1].fFlag&CFT_TYPE_MASK) == CFT_TYPE_STRING ){
00320       fprintf(fp,"%*s%s ",offset,"",pCT->StringTable+pCT->Root[hNodeIter-1].lKey);
00321       t = "\"";
00322       for( s = pCT->StringTable+pCT->Root[hNodeIter-1].Val.lVal ; *s ; s++ ){
00323          if( *s == '\n' || *s == '\r' ){
00324            t = "\"\"\"";
00325            break;
00326            }
00327          }
00328       fprintf(fp,t);
00329       for( s = pCT->StringTable+pCT->Root[hNodeIter-1].Val.lVal ; *s ; s++ ){
00330         if( *s == '"' ){
00331           fprintf(fp,"\\\"");
00332           continue;
00333           }
00334         if( *s == '\\' ){
00335           fprintf(fp,"\\\\");
00336           continue;
00337           }
00338         fprintf(fp,"%c",*s);
00339         }
00340       fprintf(fp,"%s\n",t);
00341       }else
00342     if( (pCT->Root[hNodeIter-1].fFlag&CFT_TYPE_MASK) == CFT_TYPE_INTEGER ){
00343       fprintf(fp,"%*s%s %d\n",offset,"",pCT->StringTable+pCT->Root[hNodeIter-1].lKey,
00344                                          pCT->Root[hNodeIter-1].Val.lVal);
00345       }else
00346     if( (pCT->Root[hNodeIter-1].fFlag&CFT_TYPE_MASK) == CFT_TYPE_REAL ){
00347       fprintf(fp,"%*s%s %f\n",offset,"",pCT->StringTable+pCT->Root[hNodeIter-1].lKey,
00348                                          pCT->Root[hNodeIter-1].Val.dVal);
00349       }
00350     hNodeIter = cft_EnumNext(pCT,hNodeIter);
00351     }
00352   return 0;
00353   }
00354 
00355 /*POD
00356 =section cft_DumpConfig
00357 =H Dump the configuration information into a text file
00358 
00359 /*FUNCTION*/
00360 int cft_DumpConfig(ptConfigTree pCT,
00361                    char *pszFileName
00362   ){
00363 /*noverbatim
00364 CUT*/
00365   FILE *fp;
00366   int iError;
00367   int iShouldClose = 0;
00368 
00369   if( !strcmp(pszFileName,"STDOUT") )
00370     fp = stdout;
00371   else
00372   if( !strcmp(pszFileName,"STDERR") )
00373     fp = stderr;
00374   else{
00375     fp = fopen(pszFileName,"w");
00376     iShouldClose = 1;
00377     }
00378   if( fp == NULL )return CFT_ERROR_FILE;
00379   iError = DumpTree(pCT,fp,CFT_ROOT_NODE,0);
00380   if( iShouldClose )fclose(fp);
00381   return iError;
00382   }
00383 
00384 
00385 /*POD
00386 =section cft_DumbConfig
00387 =H Dump the configuration information into a text file in dumb mode
00388 
00389 /*FUNCTION*/
00390 int cft_DumbConfig(ptConfigTree pCT,
00391                    char *pszFileName
00392   ){
00393 /*noverbatim
00394 CUT*/
00395   int i;
00396   FILE *fp;
00397   int iShouldClose = 0;
00398 
00399   if( !strcmp(pszFileName,"STDOUT") )
00400     fp = stdout;
00401   else
00402   if( !strcmp(pszFileName,"STDERR") )
00403     fp = stderr;
00404   else{
00405     fp = fopen(pszFileName,"w");
00406     iShouldClose = 1;
00407     }
00408   if( fp == NULL )return CFT_ERROR_FILE;
00409   for( i=0 ; i < pCT->cNode ; i++ ){
00410     fprintf(fp,"Node %d:",i+1);
00411     fprintf(fp,"(%s)",pCT->StringTable+pCT->Root[i].lKey);
00412     switch( pCT->Root[i].fFlag ){
00413       case CFT_NODE_BRANCH:  fprintf(fp," BRANCH %d",pCT->Root[i].Val.lVal); break;
00414       case CFT_TYPE_STRING:  fprintf(fp," \"%s\"",pCT->StringTable+pCT->Root[i].Val.lVal); break;
00415       case CFT_TYPE_INTEGER: fprintf(fp," %d",pCT->Root[i].Val.lVal); break;
00416       case CFT_TYPE_REAL:    fprintf(fp," %lf",pCT->Root[i].Val.dVal); break;
00417       default: fprintf(fp,"Unknown node type: %d",pCT->Root[i].fFlag);
00418       }
00419     fprintf(fp," NEXT->%d",pCT->Root[i].lNext);
00420     fprintf(fp,"\n");
00421     }
00422 
00423   if( iShouldClose )fclose(fp);
00424   return 0;
00425   }

Generated on Sun Mar 12 23:56:27 2006 for ScriptBasic by  doxygen 1.4.6-NO