s_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 }