input.c 9.9 KB

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