home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 3 / BBS in a box - Trilogy III.iso / Files / Prog / U-Z / VideoToolBox Folder / VideoToolboxSources / ReadAssignments.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-04  |  20.3 KB  |  652 lines  |  [TEXT/KAHL]

  1. #if 0
  2. ReadAssignments.c
  3. This is a runtime C interpreter that only accepts assignments and comments, e.g.
  4.  
  5.     /* C comment */
  6.     // C++ comment
  7.     pupilMm=2.0;
  8.     logC=-INF;    
  9.     viewingDistance=57.0;
  10. //    result=0;    
  11.     result = NAN;
  12.     trials=40;                // short int, or char or long, signed or unsigned
  13.     // The next line is blank, separating "blocks" of assignments
  14.     
  15.     logC=-1;    
  16.     trials='E';
  17.     kindOfTrial="2IFC";        /* string */
  18.     message="I will beep\007 now.\n";
  19.     
  20. Whitespace and comments are ignored (except that you can break off processing at
  21. ends of lines, and blocks separated by blank lines). Both C style /* */ and C++
  22. style // comments are allowed. No expression evaluation is supported beyond
  23. simple reading of values. No casts, e.g. (unsigned long), number suffixes, e.g.
  24. UL, or preproprocessor directives, e.g. #if, are allowed. Adjacent strings are
  25. concatenated, as specified by ANSI C. Backslash escapes, e.g. \007, within
  26. single and double quotes are fully supported. Continuing a line by putting a
  27. backslash just before the newline character is not supported. Each string is
  28. allocated on the heap, by malloc(). You can recover the space assigned to a
  29. string by calling free().
  30.  
  31. This C interpreter is quite dumb and very strict. If it can't interpret your
  32. file it will PrintfExit an error message pinpointing the error.
  33. Assignment statements must be terminated by semicolons. Comments opened, /*,
  34. must be closed, */.
  35.  
  36. The main use of these routines will be to read parameter files that control
  37. experiments. Typical psychophysical and physiological experiments are VERY
  38. complicated and require lots of adjustable parameters. One needs an easy way to
  39. change them all that is self documenting and easily reproduced, possibly months
  40. later. The routines provided here come in various flavors allowing you to read a
  41. line at a time (with any number of assignments on the line), a block at a time
  42. (blocks are separated by blank lines), or a whole file at a time. In controlling
  43. psychophysical experiments I use a block at the beginning of the file to define
  44. the general experiment followed by a block for each psychophysical
  45. "block", with a line for each condition.
  46.  
  47. Since the interpreter will fail if the paramater file contains even a single
  48. error, it is strongly suggested that your experimental program begin by doing a
  49. dry run, reading the whole file through to check for errors, before initializing
  50. your variables and reading it again a bit at a time as the experiment
  51. progresses. It would obviously be very bad to have the interpreter quit near the
  52. end of a 3 hour experiment.
  53.  
  54. The interpreter uses a line buffer of BUFFER_SIZE bytes (currently 512), so keep
  55. your lines of text shorter than this to avoid breaking tokens at the end of the
  56. buffer.
  57.  
  58. Here is a sample program to read the assignments given above:
  59. #include "VideoToolbox.h"
  60. void main(void)
  61. {
  62.     double pupilMm,logC,viewingDistance,result;
  63.     short int trials,i;
  64.     char *kindOfTrial,*message;
  65.     Variable v[8];
  66.     FILE *file;
  67.     
  68.     i=0;
  69.     v[i++]=SetVariable(stringType,&kindOfTrial,"kindOfTrial");
  70.     v[i++]=SetVariable(stringType,&message,"message");
  71.     v[i++]=SetVariable(doubleType,&pupilMm,"pupilMm");
  72.     v[i++]=SetVariable(doubleType,&logC,"logC");
  73.     v[i++]=SetVariable(doubleType,&viewingDistance,"viewingDistance");
  74.     v[i++]=SetVariable(doubleType,&result,"result");
  75.     v[i++]=SetVariable(shortType,&trials,"trials");
  76.     v[i++]=SetVariable(0,NULL,NULL);        // mark end of array
  77.     ReadAssignmentFile("myFile",v,0);        // make sure file is ok!
  78.     file=fopen("myFile","r");
  79.     InitializeVariables(v);
  80.     do{
  81.         printf("********New block********\n");
  82.         ReadAssignmentBlock(file,v,echoAssignments);
  83.         // a real program would do something useful here
  84.     } while(!feof(file));
  85.     fclose(file);
  86. }
  87.  
  88. Here are the routines:
  89.  
  90.     v[i++]=SetVariable(doubleType,&x,"x");
  91.     v[i++]=SetVariable(0,NULL,NULL);        /* mark end of array */
  92. SetVariable merely returns a Variable with the field values that you supply. Use
  93. it to make your programs more readable. For example,
  94.     v[i++]=SetVariable(doubleType,&x,"x");
  95. is equivalent to
  96.     v[i].type=doubleType;
  97.     v[i].ptr=&x;
  98.     v[i++].name="x";
  99. The available types are: charType, shortType, longType, unsignedCharType,
  100. unsignedShortType, unsignedLongType, doubleType, and stringType. (They are
  101. defined by an enum statement in the VideoToolbox.h header file, which you'll
  102. #include in your source file.) Note that when you indicate stringType, you
  103. should supply the address of a char pointer variable. Later, calling
  104. InitializeVariables() will initialize your variable to point to a null string,
  105. "", and calling ReadAssignmentLine, if it finds a match, will allocate storage
  106. by calling malloc() and place the address of the string in your variable.
  107.  
  108.     n=InitializeVariables(variable);
  109.     InitializeAVariable(variable);
  110. These utilities use your Variable array or a single Variable to initialize. All
  111. char, short, and long variables are set to zero, all double variables are set to
  112. NAN, and all the strings are set to "". (All the string pointers are initialized
  113. to point to the same empty string.)
  114.  
  115.     n=ReadAssignmentLine(file,variables,echo);
  116. Interprets one line from the file, and continues to read further lines, if
  117. necessary, to reach the end of any incomplete comment or assignment.
  118. ReadAssignmentBlock() and ReadAssignmentFile() do all their reading by
  119. repeatedly calling ReadAssignmentLine().
  120.  
  121.     blank=AssignmentLineWasBlank();
  122. Returns true (i.e. 1) unless the most recent call to ReadAssignmentLine() read some
  123. non-blank text. 
  124.  
  125.     n=ReadAssignmentBlock(file,variables,echo);
  126. Interprets lines from the file until it reads an isolated blank line. (Blank
  127. lines within an assignment or comment /* */ are ignored.) So separate your
  128. blocks by a blank line. A blank line may contain spaces, tabs, returns,
  129. newlines, formfeeds, and vertical tabs. Implemented by repeatedly calling
  130. ReadAssignmentLine() until AssignmentLineWasBlank() is true.
  131.  
  132.     n=ReadAssignmentFile(filename,variables,echo);
  133. Use this to interpret a whole file at once. It even opens and closes the file for 
  134. you. Implemented by repeatedly calling ReadAssignmentLine().
  135.  
  136.     PrintAssignment(file,&variable);
  137. Prints out the name and value of the variable, as an assignment statement, suitable
  138. for reading by any of the ReadAssignment routines.
  139.  
  140.     n=ReadLuminanceRecord(filename,LP,echo)
  141. This uses ReadAssignmentFile() to interpret a LuminanceRecord?.h file. This
  142. routine is in ReadLuminanceRecord.c.
  143.  
  144. The returned value, n, is the number of assignments that were interpreted.
  145.  
  146. The second argument, "variables", is an array of "Variable" structs describing
  147. the names, addresses, and types of your variables. The number of array elements
  148. is not given. Instead you mark the end by an element with the "type" field set
  149. to zero. The "Variable" data structure is defined in VideoToolbox.h.
  150.  
  151. The third argument, "echo", was developed for debugging but it is so handy that it
  152. stayed in the final version. It allows you to request that the assignment and/or
  153. the comments and/or the original file be listed on the console by printf. "echo"
  154. should be an integer value formed by summing some or all of predefined
  155. constants: echoAssignments, echoComments, echoFile. 
  156.  
  157. echoFile prints each line from the file.
  158.  
  159. echoAssignments regenerates the assigment statement by printing the variable
  160. name, an equal sign, the stored value, a semicolon and a space. Uncommented
  161. newline characters in the source file are echoed as well.
  162.  
  163. echoComments prints both /*..*/ and //-style comments. Uncommented
  164. newline characters in the source file are echoed as well.
  165.  
  166. They are defined by an enum statement in the VideoToolbox.h header file, which
  167. you should #include in your source file. Set echo to zero for no printf's.
  168. Turning them all on allows you to monitor the operation of ReadAssignmentLine.
  169. Turning on just comments, for example, might be helpful in reminding you of
  170. what's in the file being interpreted.
  171.  
  172. IMPORTANT: Don't forget to mark the end of your variable array by setting the
  173. last element's type to zero.
  174.  
  175. ReadAssignments was inspired by an idea Beau Watson mentioned to me in the 1980's: 
  176. a routine to read free-form parameter values at run time.
  177.  
  178. HISTORY:
  179. 7/30/91 dgp    wrote it.
  180. 8/4/91    dgp added new routines and renamed the old ones. Everything
  181.             seems to work, but has not been thoroughly tested.
  182. 8/5/91    dgp    MPW C 3.2 now compiles it without error messages. The MPW C macro processor,
  183.             contrary to ANSI C, finds comment symbols inside strings and finds 
  184.             preprocessor directives even when # is not the first nonblank character.
  185. 8/24/91    dgp    Made compatible with THINK C 5.0.
  186.             Changed ReadAssignment file to return an error code instead of aborting
  187.             if it can't open the file.
  188. 8/26/91    dgp    Added SetVariable() and noted, above, that the Variable array
  189.             is terminated by an element with its "type" field set to zero. (Thanks
  190.             to Evan Relkin for pointing out the omission.)
  191. 4/1/92    dgp    Tidied up the documentation above.
  192. 4/2/92    dgp Introduced ReadAssignmentBlock() and AssignmentLineWasBlank(). 
  193.             Deleted ReadAssignments().
  194. 4/5/92    dgp    ReadAssignmentFile() now closes the file before returning.
  195. 4/17/92    dgp    Expanded the explanation of echo, as requested by Evan Relkin.
  196. 5/14/92    dgp    Expanded the explanation of stringType, "".
  197. 8/4/92    dgp    Added PrintAssignment(), which prints out the value of a variable,
  198.             as an assignment statement, suitable for reading by the ReadAssignment
  199.             routines.
  200. 10/24/92 dgp Eliminated double spacing that occurred after //-style comment when 
  201.             echoComment was requested.
  202. 3/4/93    dgp    changed the definition of emptyString slightly so that this file could be
  203.             compiled as a code resource.
  204. #endif
  205. #include "VideoToolbox.h"
  206.  
  207. /* the following are private, not intended for use outside this file */
  208. static Boolean lineWasBlank=1;    /* used in ReadAssignmentLine(),    */
  209.                                 /* GetToken1(), and AssignmentLineWasBlank().*/
  210. void ParsingError(char *s);
  211. char *GetToken(FILE *file,char *lineBuffer,char *s,int echo);
  212. char *GetToken0(FILE *file,char *lineBuffer,char *s,int echo);
  213. char *GetToken1(FILE *file,char *lineBuffer,char *s,int echo);
  214. double strtodN(char *s,char **sPtr);
  215. long strtolN(char *s,char **sPtr,short flag);
  216. unsigned long strtoulN(char *s,char **sPtr,short flag);
  217. char strtoc(char *s,char **sPtr);
  218. #define streq2(s1,s2) (strncmp(s1,s2,strlen(s2))==0)
  219.  
  220. #define ECHO_ASSIGNMENTS    (echo & echoAssignments)
  221. #define ECHO_COMMENTS        (echo & echoComments)
  222. #define ECHO_FILE            (echo & echoFile)
  223. #define BUFFER_SIZE 512
  224.  
  225. void PrintAssignment(FILE *file,Variable *v)
  226. {
  227.     fprintf(file,"%s=",v->name);
  228.     switch(v->type){
  229.     default:
  230.         PrintfExit("\nPrintVariable: %s has unknown type %d.\n\007",v->name,v->type);
  231.     case charType:
  232.         if(isalnum(*(unsigned char *)v->ptr))
  233.             fprintf(file,"'%c';\n",*(unsigned char *)v->ptr);
  234.         else
  235.             fprintf(file,"%d;\n",*(char *)v->ptr);
  236.         break;
  237.     case unsignedCharType:
  238.         if(isalnum(*(unsigned char *)v->ptr))
  239.             fprintf(file,"'%c';\n",*(unsigned char *)v->ptr);
  240.         else
  241.             fprintf(file,"%d;\n",*(unsigned char *)v->ptr);
  242.         break;
  243.     case shortType:
  244.         fprintf(file,"%d;\n",*(short *)v->ptr);
  245.         break;
  246.     case unsignedShortType:
  247.         fprintf(file,"%u;\n",*(unsigned short *)v->ptr);
  248.         break;
  249.     case longType:
  250.         fprintf(file,"%ld;\n",*(long *)v->ptr);
  251.         break;
  252.     case unsignedLongType:
  253.         fprintf(file,"%lu;\n",*(unsigned long *)v->ptr);
  254.         break;
  255.     case doubleType:
  256.         fprintf(file,"%f;\n",*(double *)v->ptr);
  257.         break;
  258.     case stringType:
  259.         fprintf(file,"\"%s\";\n",*(char **)v->ptr);
  260.         break;
  261.     }
  262. }
  263.  
  264. Variable SetVariable(int type,void *ptr,char *name)
  265. {
  266.     static Variable v;
  267.     
  268.     v.name=name;
  269.     v.ptr=ptr;
  270.     v.type=type;
  271.     return v;
  272. }
  273.  
  274. int InitializeVariables(Variable variable[])
  275. {
  276.     int i;
  277.     
  278.     for(i=0;variable[i].type!=0;i++)InitializeAVariable(&variable[i]);
  279.     return i;
  280. }
  281.  
  282. void InitializeAVariable(Variable *v)
  283. {
  284.     static const char emptyString[]="";
  285.     
  286.     switch(v->type){
  287.     default:
  288.         PrintfExit("\nInitializeAVariable: %s has unknown type %d.\n\007"
  289.             ,v->name,v->type);
  290.     case charType:
  291.     case unsignedCharType:
  292.         *(char *)v->ptr=0;
  293.         break;
  294.     case shortType:
  295.     case unsignedShortType:
  296.         *(short *)v->ptr=0;
  297.         break;
  298.     case longType:
  299.     case unsignedLongType:
  300.         *(long *)v->ptr=0;
  301.         break;
  302.     case doubleType:
  303.         *(double *)v->ptr=NAN;
  304.         break;
  305.     case stringType:
  306.         *(const char **)v->ptr=emptyString;
  307.         break;
  308.     }
  309. }
  310.  
  311. Boolean AssignmentLineWasBlank(void)
  312. {
  313.     extern Boolean lineWasBlank;
  314.  
  315.     return lineWasBlank;
  316. }
  317.  
  318. int ReadAssignmentBlock(FILE *file,Variable variable[],int echo)
  319. {
  320.     int n;
  321.     
  322.     n=0;
  323.     do{
  324.         n+=ReadAssignmentLine(file,variable,echo);
  325.     }while(!AssignmentLineWasBlank());
  326.     return n;
  327. }
  328.  
  329. int ReadAssignmentFile(char *filename,Variable variable[],int echo)
  330. {
  331.     int n;
  332.     FILE *file;
  333.     
  334.     file=fopen(filename,"r");
  335.     if(file==NULL)return -1;    /* error */
  336.     n=0;
  337.     do{
  338.         n+=ReadAssignmentLine(file,variable,echo);
  339.     }while(!feof(file));
  340.     fclose(file);
  341.     return n;
  342. }
  343.  
  344. static char *lineBuffer;    /* global because it would be messy to pass this address to
  345.                             all the routines below that need to call ParsingError */
  346.  
  347. int ReadAssignmentLine(FILE *file,Variable variable[],int echo)
  348. {
  349.     register Variable *v;
  350.     Variable *vLast,*w;
  351.     int j,n;
  352.     char *s,*s2,*stringBuffer;
  353.     extern Boolean lineWasBlank;
  354.     
  355.     lineWasBlank=TRUE;
  356.     lineBuffer=(char *)malloc(BUFFER_SIZE);
  357.     stringBuffer=(char *)malloc(BUFFER_SIZE);
  358.     if(lineBuffer==NULL||stringBuffer==NULL){
  359.         PrintfExit("ReadAssignmentLine: couldn't malloc %d bytes for buffers.\007\n"
  360.             ,2*BUFFER_SIZE);
  361.     }
  362.     if(file==NULL)return 0;
  363.     for(vLast=&variable[0];vLast->type>0;vLast++);
  364.     vLast->name="";
  365.     vLast->ptr=NULL;
  366.     s=NULL;
  367.     n=0;
  368.     do{
  369.         /* parse a parameter name */
  370.         if(s==NULL) s=GetToken1(file,lineBuffer,s,echo);/* read in a new line */
  371.         else s=GetToken0(file,lineBuffer,s,echo);        /* don't read in a new line */
  372.         if(s==NULL){
  373.             free(lineBuffer);
  374.             free(stringBuffer);
  375.             return n;
  376.         }
  377.         v=vLast;
  378.         for(w=&variable[0];w!=vLast;w++)                /* find longest match */
  379.             if(streq2(s,w->name)&&strlen(w->name)>strlen(v->name))v=w;
  380.         if(v==vLast)ParsingError(s);
  381.         s+=strlen(v->name);
  382.         if(ECHO_ASSIGNMENTS)printf("%s",v->name);
  383.         
  384.         /* parse the equal sign */
  385.         s=GetToken(file,lineBuffer,s,echo);
  386.         if(s==NULL)ParsingError(s);
  387.         if(s[0] != '=')ParsingError(s);
  388.         s++;
  389.         if(ECHO_ASSIGNMENTS)printf("=");
  390.         
  391.         /* parse the value */
  392.         s=GetToken(file,lineBuffer,s,echo);
  393.         if(s==NULL)ParsingError(s);
  394.         switch(v->type){
  395.         default:
  396.             PrintfExit("\nReadAssignmentLine: %s has unknown type %d.\n\007"
  397.                 ,v->name,v->type);
  398.         case charType:
  399.             *(char *)v->ptr=strtolN(s,&s,0);
  400.             if(ECHO_ASSIGNMENTS)printf("%d",*(char *)v->ptr);
  401.             break;
  402.         case shortType:
  403.             *(short *)v->ptr=strtolN(s,&s,0);
  404.             if(ECHO_ASSIGNMENTS)printf("%d",*(short *)v->ptr);
  405.             break;
  406.         case longType:
  407.             *(long *)v->ptr=strtolN(s,&s,0);
  408.             if(ECHO_ASSIGNMENTS)printf("%ld",*(long *)v->ptr);
  409.             break;
  410.         case unsignedCharType:
  411.             *(unsigned char *)v->ptr=strtoulN(s,&s,0);
  412.             if(ECHO_ASSIGNMENTS)printf("%u",*(unsigned char *)v->ptr);
  413.             break;
  414.         case unsignedShortType:
  415.             *(unsigned short *)v->ptr=strtoulN(s,&s,0);
  416.             if(ECHO_ASSIGNMENTS)printf("%u",*(unsigned short *)v->ptr);
  417.             break;
  418.         case unsignedLongType:
  419.             *(unsigned long *)v->ptr=strtoulN(s,&s,0);
  420.             if(ECHO_ASSIGNMENTS)printf("%lu",*(unsigned long *)v->ptr);
  421.             break;
  422.         case doubleType:
  423.             *(double *)v->ptr=strtodN(s,&s);
  424.             if(ECHO_ASSIGNMENTS)printf("%g",*(double *)v->ptr);
  425.             break;
  426.         case stringType:
  427.             /* parse the opening quote mark */
  428.             if(s[0]!='"')ParsingError(s);
  429.             s++;
  430.             s2=stringBuffer;
  431.             do{
  432.                 /* copy string but translate backslash escape sequences */
  433.                 do{
  434.                     j=strcspn(s,"\\\"");
  435.                     strncpy(s2,s,j);
  436.                     s+=j;
  437.                     s2+=j;
  438.                     s2[0]=0;
  439.                     if(s[0]=='\\'){
  440.                         s2++[0]=strtoc(s,&s);
  441.                         s2[0]=0;
  442.                     }
  443.                     else break;
  444.                 } while (1);
  445.                 
  446.                 /* parse the closing quote mark */
  447.                 if(s[0]!='"')ParsingError(s);
  448.                 s++;
  449.                 
  450.                 /* look for another opening quote mark. Concatenate adjacent strings */
  451.                 s=GetToken(file,lineBuffer,s,echo);
  452.                 if(s==NULL)ParsingError(s);
  453.                 if(s[0]!='"')break;
  454.                 s++;
  455.             }while(1);
  456.             /* allocate the new string */
  457.             *(char **)v->ptr=malloc(1+strlen(stringBuffer));
  458.             if(v->ptr==NULL){
  459.                 PrintfExit("\nReadAssignmentLine: couldn't allocate %ld bytes for string.\007\n",1L+strlen(stringBuffer));
  460.             }
  461.             strcpy(*(char **)v->ptr,stringBuffer);
  462.             if(ECHO_ASSIGNMENTS)printf("\"%s\"",*(char **)v->ptr);
  463.             break;
  464.         }
  465.  
  466.         /* parse the semicolon */
  467.         s=GetToken(file,lineBuffer,s,echo);
  468.         if(s==NULL)ParsingError(s);
  469.         if(s[0]!=';')ParsingError(s);
  470.         s++;
  471.         if(ECHO_ASSIGNMENTS)printf(";    ");
  472.         
  473.         n++;
  474.     } while(1);
  475. }
  476.  
  477. void ParsingError(char *s)
  478. {
  479.     int i;
  480.     
  481.     if(s==NULL)PrintfExit("\nReadAssignmentLine: premature end of file.\007\n");
  482.     printf("\nReadAssignmentLine: error location indicated by the caret ^.\007\n");
  483.     printf("%s",lineBuffer);
  484.     s[0]='^';
  485.     s[1]=0;
  486.     s=lineBuffer;
  487.     for(i=0;i<strlen(s)-1;i++)if(isprint(s[i]))s[i]=' ';
  488.     PrintfExit("%s\n",lineBuffer);
  489. }
  490.  
  491. /*
  492. Skip past white space and comments to the beginning of the next token,
  493. reading as many lines as necessary.
  494. */
  495. char *GetToken(FILE *file,char *lineBuffer,char *s,int echo)
  496. {
  497.     do{
  498.         s=GetToken1(file,lineBuffer,s,echo);
  499.         if(s!=NULL || feof(file))return s;
  500.     }while(1);
  501. }
  502.  
  503. /*
  504. Skip past white space and comments to the beginning of the next token,
  505. reading one line if necessary. The lineWasBlank Boolean global is only used
  506. here, ReadAssignmentLine(), and in AssignmentLineWasBlank().
  507. */
  508. char *GetToken1(FILE *file,char *lineBuffer,char *s,int echo)
  509. {
  510.     static char whiteSpace[]=" \t\n\r\v\f";
  511.     extern Boolean lineWasBlank;
  512.  
  513.     s=GetToken0(file,lineBuffer,s,echo);
  514.     if(s!=NULL)return s;
  515.     s=fgets(lineBuffer,BUFFER_SIZE,file);
  516.     if(s==NULL)return NULL;
  517.     if(ECHO_FILE)printf("%s",s);
  518.     if(strlen(s)!=strspn(s,whiteSpace))lineWasBlank=FALSE;
  519.     s=GetToken0(file,lineBuffer,s,echo);
  520.     return s;
  521. }
  522.  
  523. /*
  524. Skip past white space and comments to the beginning of the next token.
  525. GetToken0 will read in new lines only if needed to find the end of an
  526. unfinished comment. Input from file is buffered one line at a time in lineBuffer,
  527. and s points to the next unparsed character in that buffer.
  528. */
  529. char *GetToken0(FILE *file,char *lineBuffer,char *s,int echo)
  530. {
  531.     static char whiteSpace[]=" \t\n\r\v\f";
  532.     char *sTemp;
  533.  
  534.     if(s==NULL)goto endOfLine;
  535.     do{
  536.         /* skip white space and comments */
  537.         do {
  538.             if(strlen(s)==0)goto endOfLine;
  539.             s+=strspn(s,whiteSpace);
  540.             if(strlen(s)==0)goto endOfLine;
  541.             if(streq2(s,"/\*")){
  542.                 do{
  543.                     sTemp=s;
  544.                     s=strstr(s,"*\/");
  545.                     if(s!=NULL)break;
  546.                     if(ECHO_COMMENTS)printf("%s",sTemp);
  547.                     s=fgets(lineBuffer,BUFFER_SIZE,file);
  548.                     if(s==NULL)ParsingError(s);
  549.                     if(ECHO_FILE)printf("%s",s);
  550.                 } while(1);
  551.                 s+=2;
  552.                 if(ECHO_COMMENTS){
  553.                     s[-1]=0;
  554.                     printf("%s/",sTemp);
  555.                 }
  556.                 continue;
  557.             }
  558.             if(streq2(s,"/\/")){
  559.                 if(ECHO_COMMENTS){
  560.                     if(s[strlen(s)-1]=='\n')s[strlen(s)-1]=0;
  561.                     printf("    %s",s);
  562.                 }
  563.                 goto endOfLine;
  564.             }
  565.             break;
  566.         } while(1);
  567.         return s;    /* normal return */
  568.     }while(1);
  569. endOfLine:
  570.     if((ECHO_ASSIGNMENTS || ECHO_COMMENTS) && s!=NULL)printf("\n");
  571.     return NULL;
  572. }
  573.  
  574. double strtodN(char *s,char **sPtr)
  575. /* Supplement standard C routine strtod() by handling NAN and INF */
  576. /* The NAN type, if any, is skipped, whether in THINK C style, e.g. NANFF, or in
  577. MPW C style, e.g. Nan[255]. */
  578. {
  579.     if(streq2(s,"NAN")||streq2(s,"NaN")||streq2(s,"Nan")||streq2(s,"nan")){
  580.         s+=3;
  581.         s+=strspn(s,"0123456789abcdefABCDEF[]");
  582.         *sPtr=s;
  583.         return NAN;
  584.     }
  585.     if(strncmp(s,"INF",3)==0||strncmp(s,"Inf",3)==0||strncmp(s,"inf",3)==0){
  586.         s+=3;
  587.         *sPtr=s;
  588.         return INF;
  589.     }
  590.     if(strncmp(s,"-INF",4)==0||strncmp(s,"-Inf",4)==0||strncmp(s,"-inf",4)==0){
  591.         s+=4;
  592.         *sPtr=s;
  593.         return -INF;
  594.     }
  595.     return strtod(s,sPtr);
  596. }
  597.  
  598. long strtolN(char *s,char **sPtr,short flag)
  599. /* Supplement standard C routine strtol() by handling quoted char, e.g. 'e' */
  600. {
  601.     long j;
  602.     
  603.     if(s[0]!='\'') return strtol(s,sPtr,flag);
  604.     s++;
  605.     j=strtoc(s,&s);
  606.     if(s[0]!='\'')ParsingError(s);
  607.     *sPtr=s+1;
  608.     return j;
  609. }    
  610.  
  611. unsigned long strtoulN(char *s,char **sPtr,short flag)
  612. /* Supplement standard C routine by handling quoted char, e.g. 'e' */
  613. {
  614.     unsigned long j;
  615.     
  616.     if(s[0]!='\'') return strtoul(s,sPtr,flag);
  617.     s++;
  618.     j=strtoc(s,&s);
  619.     j &= 255L;        /* strip off any sign extension, since char was signed */
  620.     if(s[0]!='\'')ParsingError(s);
  621.     *sPtr=s+1;
  622.     return j;
  623. }    
  624.  
  625. char strtoc(char *s,char **sPtr)
  626. /* Extract a character from a string, translating backslash escapes */
  627. {
  628.     char c;
  629.     
  630.     if(s[0]!='\\'){
  631.         *sPtr=s+1;
  632.         if(s[0]=='"')return 0;
  633.         else return s[0];
  634.     }
  635.     s++;
  636.     switch(s++[0]){
  637.     case 'n': c='\n'; break;
  638.     case 'r': c='\r'; break;
  639.     case 't': c='\t'; break;
  640.     case 'b': c='\b'; break;
  641.     case 'v': c='\v'; break;
  642.     case 'f': c='\f'; break;
  643.     case 'a': c='\a'; break;
  644.     case 'x': c=strtol(s,&s,16); break;
  645.     case '0': case '1':case '2': case '3':case '4': case '5':case '6': case '7':
  646.         c=strtol(s-1,&s,8); break;
  647.     default: c=s[-1]; break;
  648.     }
  649.     *sPtr=s;
  650.     return c;
  651. }
  652.