Blob
2 #include <u.h>3 #include <libc.h>4 #include <bio.h>5 #include "libString.h"7 struct Sinstack{8 int depth;9 Biobuf *fp[32]; /* hard limit to avoid infinite recursion */10 };12 /* initialize */13 extern Sinstack *14 s_allocinstack(char *file)15 {16 Sinstack *sp;17 Biobuf *fp;19 fp = Bopen(file, OREAD);20 if(fp == nil)21 return nil;23 sp = malloc(sizeof *sp);24 sp->depth = 0;25 sp->fp[0] = fp;26 return sp;27 }29 extern void30 s_freeinstack(Sinstack *sp)31 {32 while(sp->depth >= 0)33 Bterm(sp->fp[sp->depth--]);34 free(sp);35 }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;47 c = Bgetc(fp);49 /* eat leading white */50 while(c==' ' || c=='\t' || c=='\n' || c=='\r')51 c = Bgetc(fp);53 if(c < 0)54 return 0;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 }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;99 s_terminate(to);100 fp = sp->fp[sp->depth];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 }112 if(strncmp(p, "#include", 8) == 0 && (p[8] == ' ' || p[8] == '\t')){113 to->ptr = p;114 p += 8;116 /* sanity (and looping) */117 if(sp->depth >= nelem(sp->fp))118 sysfatal("s_recgetline: includes too deep");120 /* skip white */121 while(*p == ' ' || *p == '\t')122 p++;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 }132 /* got milk? */133 if(*p != '#')134 break;136 /* take care of comments */137 to->ptr = p;138 s_terminate(to);139 }140 return p;141 }