URI:
       ts_rdinstack.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       ts_rdinstack.c (2260B)
       ---
            1 
            2 #include <u.h>
            3 #include <libc.h>
            4 #include <bio.h>
            5 #include "libString.h"
            6 
            7 struct Sinstack{
            8         int        depth;
            9         Biobuf        *fp[32];        /* hard limit to avoid infinite recursion */
           10 };
           11 
           12 /* initialize */
           13 extern Sinstack *
           14 s_allocinstack(char *file)
           15 {
           16         Sinstack *sp;
           17         Biobuf *fp;
           18 
           19         fp = Bopen(file, OREAD);
           20         if(fp == nil)
           21                 return nil;
           22 
           23         sp = malloc(sizeof *sp);
           24         sp->depth = 0;
           25         sp->fp[0] = fp;
           26         return sp;
           27 }
           28 
           29 extern void
           30 s_freeinstack(Sinstack *sp)
           31 {
           32         while(sp->depth >= 0)
           33                 Bterm(sp->fp[sp->depth--]);
           34         free(sp);
           35 }
           36 
           37 /*  Append an input line to a String.
           38  *
           39  *  Empty lines and leading whitespace are removed.
           40  */
           41 static char *
           42 rdline(Biobuf *fp, String *to)
           43 {
           44         int c;
           45         int len = 0;
           46 
           47         c = Bgetc(fp);
           48 
           49         /* eat leading white */
           50         while(c==' ' || c=='\t' || c=='\n' || c=='\r')
           51                 c = Bgetc(fp);
           52 
           53         if(c < 0)
           54                 return 0;
           55 
           56         for(;;){
           57                 switch(c) {
           58                 case -1:
           59                         goto out;
           60                 case '\\':
           61                         c = Bgetc(fp);
           62                         if (c != '\n') {
           63                                 s_putc(to, '\\');
           64                                 s_putc(to, c);
           65                                 len += 2;
           66                         }
           67                         break;
           68                 case '\r':
           69                         break;
           70                 case '\n':
           71                         if(len != 0)
           72                                 goto out;
           73                         break;
           74                 default:
           75                         s_putc(to, c);
           76                         len++;
           77                         break;
           78                 }
           79                 c = Bgetc(fp);
           80         }
           81 out:
           82         s_terminate(to);
           83         return to->ptr - len;
           84 }
           85 
           86 /* Append an input line to a String.
           87  *
           88  * Returns a pointer to the character string (or 0).
           89  * Leading whitespace and newlines are removed.
           90  * Lines starting with #include cause us to descend into the new file.
           91  * Empty lines and other lines starting with '#' are ignored.
           92  */
           93 extern char *
           94 s_rdinstack(Sinstack *sp, String *to)
           95 {
           96         char *p;
           97         Biobuf *fp, *nfp;
           98 
           99         s_terminate(to);
          100         fp = sp->fp[sp->depth];
          101 
          102         for(;;){
          103                 p = rdline(fp, to);
          104                 if(p == nil){
          105                         if(sp->depth == 0)
          106                                 break;
          107                         Bterm(fp);
          108                         sp->depth--;
          109                         return s_rdinstack(sp, to);
          110                 }
          111 
          112                 if(strncmp(p, "#include", 8) == 0 && (p[8] == ' ' || p[8] == '\t')){
          113                         to->ptr = p;
          114                         p += 8;
          115 
          116                         /* sanity (and looping) */
          117                         if(sp->depth >= nelem(sp->fp))
          118                                 sysfatal("s_rdinstack: includes too deep");
          119 
          120                         /* skip white */
          121                         while(*p == ' ' || *p == '\t')
          122                                 p++;
          123 
          124                         nfp = Bopen(p, OREAD);
          125                         if(nfp == nil)
          126                                 continue;
          127                         sp->depth++;
          128                         sp->fp[sp->depth] = nfp;
          129                         return s_rdinstack(sp, to);
          130                 }
          131 
          132                 /* got milk? */
          133                 if(*p != '#')
          134                         break;
          135 
          136                 /* take care of comments */
          137                 to->ptr = p;
          138                 s_terminate(to);
          139         }
          140         return p;
          141 }