input.c (3140B)
1 /* 2 * Read input files. 3 */ 4 #include "a.h" 5 6 typedef struct Istack Istack; 7 struct Istack 8 { 9 Rune unget[3]; 10 int nunget; 11 Biobuf *b; 12 Rune *p; 13 Rune *ep; 14 Rune *s; 15 int lineno; 16 Rune *name; 17 Istack *next; 18 void (*fn)(void); 19 }; 20 21 Istack *istack; 22 Istack *ibottom; 23 24 static void 25 setname(void) 26 { 27 Rune *r, *p; 28 29 if(istack == nil || istack->name == nil) 30 return; 31 _nr(L(".F"), istack->name); 32 r = erunestrdup(istack->name); 33 p = runestrchr(r, '.'); 34 if(p) 35 *p = 0; 36 _nr(L(".B"), r); 37 free(r); 38 } 39 40 static void 41 ipush(Istack *is) 42 { 43 if(istack == nil) 44 ibottom = is; 45 else 46 is->next = istack; 47 istack = is; 48 setname(); 49 } 50 51 static void 52 iqueue(Istack *is) 53 { 54 if(ibottom == nil){ 55 istack = is; 56 setname(); 57 }else 58 ibottom->next = is; 59 ibottom = is; 60 } 61 62 int 63 _inputfile(Rune *s, void (*push)(Istack*)) 64 { 65 Istack *is; 66 Biobuf *b; 67 char *t; 68 69 t = esmprint("%S", s); 70 if((b = Bopen(t, OREAD)) == nil){ 71 free(t); 72 fprint(2, "%s: open %S: %r\n", argv0, s); 73 return -1; 74 } 75 free(t); 76 is = emalloc(sizeof *is); 77 is->b = b; 78 is->name = erunestrdup(s); 79 is->lineno = 1; 80 push(is); 81 return 0; 82 } 83 84 int 85 pushinputfile(Rune *s) 86 { 87 return _inputfile(s, ipush); 88 } 89 90 int 91 queueinputfile(Rune *s) 92 { 93 return _inputfile(s, iqueue); 94 } 95 96 int 97 _inputstdin(void (*push)(Istack*)) 98 { 99 Biobuf *b; 100 Istack *is; 101 102 if((b = Bopen("/dev/null", OREAD)) == nil){ 103 fprint(2, "%s: open /dev/null: %r\n", argv0); 104 return -1; 105 } 106 dup(0, b->fid); 107 is = emalloc(sizeof *is); 108 is->b = b; 109 is->name = erunestrdup(L("stdin")); 110 is->lineno = 1; 111 push(is); 112 return 0; 113 } 114 115 int 116 pushstdin(void) 117 { 118 return _inputstdin(ipush); 119 } 120 121 int 122 queuestdin(void) 123 { 124 return _inputstdin(iqueue); 125 } 126 127 void 128 _inputstring(Rune *s, void (*push)(Istack*)) 129 { 130 Istack *is; 131 132 is = emalloc(sizeof *is); 133 is->s = erunestrdup(s); 134 is->p = is->s; 135 is->ep = is->p+runestrlen(is->p); 136 push(is); 137 } 138 139 void 140 pushinputstring(Rune *s) 141 { 142 _inputstring(s, ipush); 143 } 144 145 146 void 147 inputnotify(void (*fn)(void)) 148 { 149 if(istack) 150 istack->fn = fn; 151 } 152 153 int 154 popinput(void) 155 { 156 Istack *is; 157 158 is = istack; 159 if(is == nil) 160 return 0; 161 162 istack = istack->next; 163 if(is->b) 164 Bterm(is->b); 165 free(is->s); 166 free(is->name); 167 if(is->fn) 168 is->fn(); 169 free(is); 170 setname(); 171 return 1; 172 } 173 174 int 175 getrune(void) 176 { 177 Rune r; 178 int c; 179 180 top: 181 if(istack == nil) 182 return -1; 183 if(istack->nunget) 184 return istack->unget[--istack->nunget]; 185 else if(istack->p){ 186 if(istack->p >= istack->ep){ 187 popinput(); 188 goto top; 189 } 190 r = *istack->p++; 191 }else if(istack->b){ 192 if((c = Bgetrune(istack->b)) < 0){ 193 popinput(); 194 goto top; 195 } 196 r = c; 197 }else{ 198 r = 0; 199 sysfatal("getrune - can't happen"); 200 } 201 if(r == '\n') 202 istack->lineno++; 203 return r; 204 } 205 206 void 207 ungetrune(Rune r) 208 { 209 if(istack == nil || istack->nunget >= nelem(istack->unget)) 210 pushinputstring(L("")); 211 istack->unget[istack->nunget++] = r; 212 } 213 214 int 215 linefmt(Fmt *f) 216 { 217 Istack *is; 218 219 for(is=istack; is && !is->b; is=is->next) 220 ; 221 if(is) 222 return fmtprint(f, "%S:%d", is->name, is->lineno); 223 else 224 return fmtprint(f, "<no input>"); 225 } 226 227 void 228 setlinenumber(Rune *s, int n) 229 { 230 Istack *is; 231 232 for(is=istack; is && !is->name; is=is->next) 233 ; 234 if(is){ 235 if(s){ 236 free(is->name); 237 is->name = erunestrdup(s); 238 } 239 is->lineno = n; 240 } 241 }