input.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. /* $Header$ */
  2. /* INPUT AND BUFFER HANDLING MODULE */
  3. /*
  4. [input.c input.h]
  5. Input buffering module: this module contains the routines that
  6. offers an input buffering mechanism to the user.
  7. This module exports the following objects:
  8. InsertFile() : suspend input from current buffer and obtain the
  9. next input characters from the specified file
  10. InsertText() : suspend input from current buffer and take the
  11. specified text as stream of input characters
  12. LoadChar() : (defined in input.h) read next character from
  13. the input ; LoadChar() invokes loadbuf() on
  14. encounting a ASCII NUL character
  15. NoUnstack : if set to non-zero:
  16. loadbuf() reports "unexpected EOF" on encounting
  17. the end-of-file or end-of-stacked-text.
  18. Imported objects are:
  19. IDEPTH, DEBUG, READ_IN_ONE, PATHLENGTH: compile-time parameters
  20. Malloc(), Salloc(): memory allocation routines
  21. fatal(), lexerror(): exception handling
  22. FileName, LineNumber, WorkingDir: input trace for lexical analyser
  23. READ_IN_ONE DEFINED: every input file is read into memory completely
  24. and made an input buffer
  25. READ_IN_ONE NOT DEFINED: the input from files is buffered in
  26. a fixed length input buffer
  27. */
  28. #include <system.h>
  29. #include "nopp.h"
  30. #include "inputtype.h" /* UF */
  31. #include "interface.h"
  32. #include "arith.h"
  33. #include "LLlex.h"
  34. #include "input.h"
  35. #include "alloc.h"
  36. #ifndef NOPP
  37. #include "idepth.h" /* UF */
  38. #include "debug.h" /* UF */
  39. #include "pathlength.h" /* UF */
  40. #include "assert.h"
  41. #endif NOPP
  42. EXPORT char *ipp = 0; /* input pointer */
  43. EXPORT int NoUnstack = 0; /* if 1: report EOF */
  44. #ifndef READ_IN_ONE
  45. PRIVATE File *FilDes = 0; /* current input medium */
  46. #endif READ_IN_ONE
  47. #ifndef NOPP
  48. struct buffer_header {
  49. char *bh_name; /* file name where the text comes from */
  50. unsigned int bh_lineno;
  51. /* current lineno in file */
  52. long bh_size; /* = strlen (text), should be unsigned */
  53. char *bh_text; /* pointer to buffer containing text */
  54. char *bh_ipp; /* current read pointer (= stacked ipp) */
  55. char *bh_wdir; /* directory of current file */
  56. File *bh_fp; /* needed for files if !READ_IN_ONE */
  57. };
  58. PRIVATE struct buffer_header instack[IDEPTH]; /* stack of input media */
  59. PRIVATE struct buffer_header *head = 0; /* current input buffer */
  60. IMPORT char **WorkingDir; /* name of current working directory */
  61. #else NOPP
  62. long isize;
  63. char ibuf[BUFSIZ];
  64. #endif NOPP
  65. #ifdef READ_IN_ONE
  66. /* readfile() creates a buffer in which the text of the file
  67. is situated. A pointer to the start of this text is
  68. returned. *size is initialized with the buffer length.
  69. Note that the file input buffer is prepared for the
  70. preprocessor by inserting a '\n' in the beginning of the
  71. text and appending a '\n' at the end of the text. The
  72. file text start at position 1 of the input buffer. This is
  73. done to allow pushback.
  74. */
  75. PRIVATE char *
  76. readfile(filename, size)
  77. char *filename;
  78. long *size;
  79. {
  80. File *fp; /* filedescriptor for `filename' */
  81. char *cbuf; /* pointer to buffer to be returned */
  82. int tmp;
  83. long sys_filesize();
  84. if (sys_open(filename, OP_READ, &fp) == 0) /* can't open this file */
  85. return (char *) 0;
  86. if ((*size = sys_filesize(filename)) == -1L)
  87. fatal("(readfile) cannot get size of file");
  88. /* allocate enough space to store contents of the file */
  89. cbuf = Malloc(*size + 2);
  90. if (sys_read(fp, cbuf + 1, (int) *size, &tmp) == 0 || tmp != *size)
  91. fatal("(readfile) bad read");
  92. (*size)++; /* keep book of the size! */
  93. sys_close(fp); /* filedes no longer needed */
  94. cbuf[0] = '\0'; /* allow pushback of first char */
  95. cbuf[*size] = '\0'; /* invoke loadbuf() at end */
  96. return cbuf;
  97. }
  98. #endif READ_IN_ONE
  99. #ifndef NOPP
  100. #ifndef READ_IN_ONE
  101. /* Input buffer supplying routines: pushbuf() and popbuf()
  102. */
  103. PRIVATE char *bufstack[IDEPTH] = 0;
  104. PRIVATE bufstptr = 0;
  105. PRIVATE char *
  106. pushbuf()
  107. {
  108. if (bufstptr >= IDEPTH)
  109. fatal("ran out of input buffers");
  110. if (bufstack[bufstptr] == 0) {
  111. bufstack[bufstptr] = Malloc(BUFSIZ + 4);
  112. }
  113. return bufstack[bufstptr++];
  114. }
  115. PRIVATE
  116. popbuf()
  117. {
  118. bufstptr--;
  119. ASSERT(bufstptr >= 0);
  120. }
  121. #endif READ_IN_ONE
  122. #endif NOPP
  123. #ifndef NOPP
  124. /* Input buffer administration: push_bh() and pop_bh()
  125. */
  126. PRIVATE struct buffer_header *
  127. push_bh()
  128. {
  129. if (head) {
  130. if (head >= &instack[IDEPTH - 1])
  131. fatal("too many nested input texts");
  132. head->bh_ipp = ipp;
  133. head->bh_lineno = LineNumber;
  134. head++;
  135. }
  136. else
  137. head = &instack[0];
  138. return head;
  139. }
  140. #endif NOPP
  141. #ifndef NOPP
  142. /* pop_bh() uncovers the previous inputbuffer on the stack
  143. of headers. 0 is returned if there are no more
  144. inputbuffers on the stack, 1 is returned in the other case.
  145. */
  146. PRIVATE int
  147. pop_bh()
  148. {
  149. File *pfp = head->bh_fp;
  150. if (NoUnstack) {
  151. lexerror("unexpected EOF");
  152. }
  153. if (head <= &instack[0]) { /* no more entries */
  154. head = (struct buffer_header *) 0;
  155. return 0;
  156. }
  157. ipp = (--head)->bh_ipp; /* restore the previous input pointer */
  158. if (pfp != 0) { /* unstack a file */
  159. #ifndef READ_IN_ONE
  160. closefile(pfp);
  161. popbuf(); /* free last buffer */
  162. #endif READ_IN_ONE
  163. LineNumber = head->bh_lineno;
  164. FileName = head->bh_name;
  165. *WorkingDir = head->bh_wdir;
  166. }
  167. #ifndef READ_IN_ONE
  168. FilDes = head->bh_fp;
  169. #endif READ_IN_ONE
  170. return 1;
  171. }
  172. #endif NOPP
  173. #ifndef READ_IN_ONE
  174. /* low level IO routines: openfile(), readblock() and closefile()
  175. */
  176. PRIVATE File *
  177. openfile(filename)
  178. char *filename;
  179. {
  180. File *fp;
  181. if (filename == 0)
  182. return STDIN;
  183. if (sys_open(filename, OP_READ, &fp) == 0)
  184. return (File *)0;
  185. return fp;
  186. }
  187. PRIVATE
  188. closefile(fp)
  189. File *fp;
  190. {
  191. if (fp != STDIN)
  192. sys_close(fp);
  193. }
  194. PRIVATE int
  195. readblock(fp, buf)
  196. File *fp;
  197. char buf[];
  198. {
  199. int n;
  200. if (sys_read(fp, &buf[1], BUFSIZ, &n) == 0)
  201. fatal("(readblock) bad read");
  202. buf[0] = buf[n + 1] = '\0';
  203. return n;
  204. }
  205. #endif READ_IN_ONE
  206. /* Interface routines : InsertFile(), InsertText() and loadbuf()
  207. */
  208. EXPORT int
  209. InsertFile(filnam, table)
  210. char *filnam;
  211. char *table[];
  212. {
  213. char *mk_filename(), *newfn;
  214. char *strcpy();
  215. File *openfile();
  216. #ifdef READ_IN_ONE
  217. char *readfile(), *text;
  218. long size;
  219. #else READ_IN_ONE
  220. File *fp = 0;
  221. #endif READ_IN_ONE
  222. #ifdef READ_IN_ONE
  223. if (!filnam)
  224. return 0;
  225. #endif READ_IN_ONE
  226. #ifndef NOPP
  227. if (table == 0 || filnam[0] == '/') { /* don't look in the table! */
  228. #endif NOPP
  229. #ifdef READ_IN_ONE
  230. text = readfile(filnam, &size);
  231. #else READ_IN_ONE
  232. fp = openfile(filnam);
  233. if (filnam == 0)
  234. filnam = "standard input";
  235. #endif READ_IN_ONE
  236. #ifndef NOPP
  237. }
  238. else {
  239. ASSERT(filnam != 0);
  240. while (*table) { /* look in the directory table */
  241. newfn = mk_filename(*table++, filnam);
  242. #ifdef READ_IN_ONE
  243. if (text = readfile(newfn, &size))
  244. #else READ_IN_ONE
  245. if ((fp = openfile(newfn)) != 0)
  246. #endif READ_IN_ONE
  247. {
  248. /* free filnam ??? */
  249. filnam = Salloc(newfn, strlen(newfn) + 1);
  250. break;
  251. }
  252. }
  253. }
  254. #endif NOPP
  255. #ifdef READ_IN_ONE
  256. if (text)
  257. #else READ_IN_ONE
  258. if (fp != 0)
  259. #endif READ_IN_ONE
  260. #ifndef NOPP
  261. {
  262. struct buffer_header *push_bh();
  263. register struct buffer_header *bh = push_bh();
  264. setwdir(WorkingDir, filnam);
  265. bh->bh_lineno = LineNumber = 0;
  266. bh->bh_name = FileName = filnam;
  267. bh->bh_wdir = *WorkingDir;
  268. #ifdef READ_IN_ONE
  269. bh->bh_size = size;
  270. bh->bh_fp = STDIN; /* this is a file */
  271. ipp = bh->bh_text = text;
  272. #else READ_IN_ONE
  273. bh->bh_size = readblock(fp, ipp = bh->bh_text = pushbuf()) + 1;
  274. FilDes = bh->bh_fp = fp;
  275. #endif READ_IN_ONE
  276. bh->bh_text[0] = '\n'; /* wake up pp if '#' comes first */
  277. return 1;
  278. }
  279. #else NOPP
  280. {
  281. #ifdef READ_IN_ONE
  282. isize = size;
  283. ipp = text;
  284. #else READ_IN_ONE
  285. isize = readblock(FilDes = fp, ipp = &ibuf[0]) + 1;
  286. #endif READ_IN_ONE
  287. ibuf[0] = '\n';
  288. return 1;
  289. }
  290. #endif NOPP
  291. return 0;
  292. }
  293. #ifndef NOPP
  294. EXPORT
  295. InsertText(text, length)
  296. char *text;
  297. {
  298. struct buffer_header *push_bh();
  299. register struct buffer_header *bh = push_bh();
  300. bh->bh_name = FileName;
  301. bh->bh_lineno = LineNumber;
  302. bh->bh_size = (long) length;
  303. bh->bh_text = text;
  304. bh->bh_wdir = *WorkingDir;
  305. bh->bh_fp = 0; /* this is not a file ! */
  306. ipp = text + 1;
  307. #ifndef READ_IN_ONE
  308. FilDes = 0;
  309. #endif READ_IN_ONE
  310. }
  311. #endif NOPP
  312. /* loadbuf() is called if LoadChar meets a '\0' character
  313. which may be the end-of-buffer mark of the current input
  314. buffer. The '\0' could be genuine although not likely.
  315. Note: this routine is exported due to its occurence in the definition
  316. of LoadChar [input.h], that is defined as a macro.
  317. */
  318. EXPORT int
  319. loadbuf()
  320. {
  321. #ifndef NOPP
  322. if (!head) {
  323. /* stack exhausted, EOF on sourcefile */
  324. return EOI;
  325. }
  326. #endif NOPP
  327. #ifndef NOPP
  328. if (ipp < &(head->bh_text[head->bh_size]))
  329. #else NOPP
  330. if (ipp < &ibuf[isize])
  331. #endif NOPP
  332. {
  333. /* a genuine '\0' character has been seen */
  334. return '\0';
  335. }
  336. #ifndef READ_IN_ONE
  337. #ifndef NOPP
  338. if ( FilDes != 0
  339. && (head->bh_size = readblock(FilDes, head->bh_text)) > 0
  340. ) {
  341. return ipp = &(head->bh_text[1]), *ipp++;
  342. }
  343. #else NOPP
  344. if (FilDes != 0 && (isize = readblock(FilDes, &ibuf[0])) > 0)
  345. return ipp = &ibuf[1], *ipp++;
  346. #endif NOPP
  347. #endif READ_IN_ONE
  348. #ifdef NOPP
  349. if (NoUnstack)
  350. lexerror("unexpected EOF");
  351. #ifndef READ_IN_ONE
  352. closefile(FilDes);
  353. #endif READ_IN_ONE
  354. #endif NOPP
  355. return
  356. #ifndef NOPP
  357. pop_bh() ? (*ipp ? *ipp++ : loadbuf()) :
  358. #endif NOPP
  359. (ipp = &"\0\0"[1], EOI);
  360. }
  361. /* Some miscellaneous routines : setwdir() and mk_filename()
  362. */
  363. #ifndef NOPP
  364. /* setwdir() updates *wdir according to the old working
  365. directory (*wdir) and the filename fn, which may contain
  366. some path name. The algorithm used here is:
  367. setwdir(DIR, FILE):
  368. if (FILE == "/***")
  369. *DIR = "/"
  370. else
  371. if (contains(FILE, '/'))
  372. *DIR = directory(FILE)
  373. else
  374. *DIR remains unchanged
  375. */
  376. PRIVATE
  377. setwdir(wdir, fn)
  378. char *fn, **wdir;
  379. {
  380. register char *p;
  381. char *strrindex();
  382. p = strrindex(fn, '/');
  383. while (p && *(p + 1) == '\0') { /* remove trailing /'s */
  384. *p = '\0';
  385. p = strrindex(fn, '/');
  386. }
  387. if (fn[0] == '\0' || (fn[0] == '/' && p == &fn[0])) /* absolute path */
  388. *wdir = "/";
  389. else
  390. if (p) {
  391. *p = '\0';
  392. *wdir = Salloc(fn, p - &fn[0] + 1);
  393. *p = '/';
  394. }
  395. }
  396. #endif NOPP
  397. #ifndef NOPP
  398. /* mk_filename() concatenates a dir and filename.
  399. */
  400. PRIVATE char *
  401. mk_filename(dir, file)
  402. register char *dir, *file;
  403. {
  404. static char newfn[PATHLENGTH];
  405. register char *dst = &newfn[0];
  406. if (!(dir[0] == '.' && dir[1] == '\0')) {
  407. while (*dst++ = *dir++);
  408. *(dst - 1) = '/';
  409. }
  410. while (*dst++ = *file++);
  411. return &newfn[0];
  412. }
  413. #endif NOPP