inp_pkg.body 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. /* INPUT AND BUFFER HANDLING MODULE */
  2. /*
  3. Input buffering module: this module contains the routines that
  4. offers an input buffering mechanism to the user.
  5. This module exports the following objects:
  6. InsertFile() : suspend input from current buffer and obtain the
  7. next input characters from the specified file
  8. InsertText() : suspend input from current buffer and take the
  9. specified text as stream of input characters
  10. LoadChar() : (defined in input.h) read next character from
  11. the input ; LoadChar() invokes loadbuf() on
  12. encounting a ASCII NUL character
  13. PushBack() : (defined in input.h) push last character back onto
  14. the input stream; NPUSHBACK characters of pushback
  15. are guaranteed, provided that they have all been read
  16. from the current input stream
  17. AtEoIT() : this routine is called at the end of an inserted text.
  18. A default one is provided, which does nothing.
  19. AtEoIF() : this routine is called at the end of an inserted file.
  20. A default one is provided, which does nothing.
  21. Imported objects are:
  22. INP_NPUSHBACK, INP_READ_IN_ONE, INP_TYPE, INP_VAR,
  23. routines from the "alloc" package, routines from the "storage"
  24. package, and routines from the "system" package.
  25. INP_READ_IN_ONE defined: every input file is read into memory completely
  26. and made an input buffer. Only use it if the size of a file
  27. fits always fits in an integer and you have lots of memory.
  28. INP_READ_IN_ONE not defined: the input from files is buffered in
  29. a fixed length input buffer
  30. INP_NPUSHBACK: the number of characters pushback
  31. */
  32. #if __STDC__
  33. #include <stdlib.h>
  34. #else
  35. extern char *malloc();
  36. #endif
  37. #include <system.h>
  38. #ifndef INP_NPUSHBACK
  39. #define INP_NPUSHBACK 1
  40. #endif
  41. #if INP_NPUSHBACK < 1
  42. #define INP_NPUSHBACK 1
  43. #endif
  44. #ifndef INP_BUFSIZE
  45. #define INP_BUFSIZE BUFSIZ
  46. #endif
  47. #if INP_NPUSHBACK > INP_BUFSIZE/2
  48. Now this is really ridiculous! You deserve what you get!!
  49. #endif
  50. #ifdef INP_TYPE
  51. extern INP_TYPE INP_VAR;
  52. #endif /* INP_TYPE */
  53. #ifdef DEBUG
  54. #define INP_PRIVATE
  55. #else
  56. #define INP_PRIVATE static
  57. #endif
  58. struct INP_buffer_header {
  59. struct INP_buffer_header *bh_next;
  60. int bh_size; /* = strlen (text), should be unsigned */
  61. char *bh_text; /* pointer to buffer containing text */
  62. char *bh_ipp; /* current read pointer (= stacked ipp) */
  63. #ifdef INP_TYPE
  64. INP_TYPE bh_i; /* user defined */
  65. #endif /* INP_TYPE */
  66. File *bh_fd; /* A file descriptor in case of a file */
  67. char bh_eofreturned; /* set if we returned eof for this buffer */
  68. };
  69. #ifndef INP_READ_IN_ONE
  70. struct INP_i_buf {
  71. struct INP_i_buf *ib_next;
  72. char ib_text[INP_BUFSIZE+INP_NPUSHBACK];
  73. };
  74. #endif /* not INP_READ_IN_ONE */
  75. char *_ipp;
  76. INP_PRIVATE struct INP_buffer_header *INP_head, *INP_free;
  77. #ifdef INP_READ_IN_ONE
  78. /* INP_rdfile() creates a buffer in which the text of the file
  79. is situated. A pointer to the start of this text is
  80. returned. *size is initialized with the buffer length.
  81. */
  82. _PROTOTYPE(INP_PRIVATE int INP_rdfile, (File *, char *, long *, char **));
  83. #if __STDC__
  84. INP_PRIVATE int INP_rdfile(File *fd, char *fn, long *size, char **pbuf)
  85. #else
  86. INP_PRIVATE int
  87. INP_rdfile(fd, fn, size, pbuf)
  88. register File *fd;
  89. char *fn; /* file name */
  90. register long *size;
  91. char **pbuf; /* output parameter */
  92. #endif
  93. {
  94. extern long sys_filesize();
  95. int rsize;
  96. if (
  97. (*size = sys_filesize(fn)) < 0
  98. ||
  99. ((unsigned) (*size + 1) != (*size + 1))
  100. ||
  101. !(*pbuf = malloc((unsigned) (*size + 1)))) {
  102. return 0;
  103. }
  104. if (
  105. !sys_read(fd, *pbuf, (int) *size, &rsize)
  106. ||
  107. *size != rsize
  108. ) {
  109. free(*pbuf);
  110. return 0;
  111. }
  112. (*pbuf)[rsize] = '\0'; /* invoke loadbuf() at end */
  113. return 1;
  114. }
  115. #endif /* INP_READ_IN_ONE */
  116. #ifndef INP_READ_IN_ONE
  117. /* Input buffer supplying routines: INP_pbuf()
  118. */
  119. INP_PRIVATE struct INP_i_buf *i_ptr;
  120. _PROTOTYPE(INP_PRIVATE char * INP_pbuf, (void));
  121. INP_PRIVATE char *INP_pbuf()
  122. {
  123. register struct INP_i_buf *ib =
  124. (struct INP_i_buf *) malloc(sizeof(struct INP_i_buf));
  125. if (!ib) return 0;
  126. ib->ib_next = i_ptr;
  127. i_ptr = ib;
  128. /* Don't give him all of it, we need some to implement a good
  129. PushBack
  130. */
  131. return &(ib->ib_text[INP_NPUSHBACK-1]);
  132. }
  133. #endif /* not INP_READ_IN_ONE */
  134. /* Input buffer administration: INP_push_bh() and INP_pop_bh()
  135. */
  136. _PROTOTYPE(INP_PRIVATE struct INP_buffer_header *INP_push_bh, (void));
  137. _PROTOTYPE(INP_PRIVATE int INP_pop_bh, (void));
  138. INP_PRIVATE struct INP_buffer_header *INP_push_bh()
  139. {
  140. register struct INP_buffer_header *bh;
  141. if ((bh = INP_head)) {
  142. bh->bh_ipp = _ipp;
  143. #ifdef INP_TYPE
  144. bh->bh_i = INP_VAR;
  145. #endif /* INP_TYPE */
  146. }
  147. bh = INP_free;
  148. if (bh) INP_free = bh->bh_next;
  149. else if (!(bh = (struct INP_buffer_header *)malloc(sizeof(struct INP_buffer_header)))) return 0;
  150. bh->bh_next = INP_head;
  151. bh->bh_eofreturned = 0;
  152. INP_head = bh;
  153. return bh;
  154. }
  155. /* INP_pop_bh() uncovers the previous inputbuffer on the stack
  156. of headers. 0 is returned if there are no more
  157. inputbuffers on the stack, 1 is returned in the other case.
  158. */
  159. INP_PRIVATE int INP_pop_bh()
  160. {
  161. register struct INP_buffer_header *bh = INP_head;
  162. bh = bh->bh_next;
  163. INP_head->bh_next = INP_free;
  164. INP_free = INP_head;
  165. INP_head = bh;
  166. if (!bh) { /* no more entries */
  167. INP_head = (struct INP_buffer_header *) 0;
  168. return 0;
  169. }
  170. _ipp = bh->bh_ipp; /* restore previous input pointer */
  171. #ifdef INP_TYPE
  172. INP_VAR = bh->bh_i;
  173. #endif /* INP_TYPE */
  174. return 1;
  175. }
  176. #ifndef INP_READ_IN_ONE
  177. /* low level I/O routine : read one block from current input
  178. stream : INP_rdblock
  179. */
  180. _PROTOTYPE(INP_PRIVATE int INP_rdblock, (File *, char *, int *));
  181. #if __STDC__
  182. INP_PRIVATE int INP_rdblock(File *fd, char *buf, int *n)
  183. #else
  184. INP_PRIVATE int
  185. INP_rdblock(fd, buf, n)
  186. File *fd;
  187. char *buf;
  188. int *n;
  189. #endif
  190. {
  191. if (!sys_read(fd, buf, INP_BUFSIZE, n)) {
  192. return 0;
  193. }
  194. buf[*n] = '\0';
  195. return 1;
  196. }
  197. #endif /* not INP_READ_IN_ONE */
  198. /* Miscellaneous routines :
  199. INP_mk_filename()
  200. */
  201. _PROTOTYPE(INP_PRIVATE int INP_mk_filename, (char *, char *, char **));
  202. /* INP_mk_filename() concatenates a dir and filename.
  203. */
  204. #if __STDC__
  205. INP_PRIVATE int INP_mk_filename(char *dir, char *file, char **newname)
  206. #else
  207. INP_PRIVATE int
  208. INP_mk_filename(dir, file, newname)
  209. register char *dir, *file;
  210. char **newname;
  211. #endif
  212. {
  213. register char *dst;
  214. dst = malloc((unsigned) (strlen(dir) + strlen(file) + 2));
  215. if (!dst) return 0;
  216. *newname = dst;
  217. if (*dir) {
  218. while (((*dst++) = (*dir++))) ;
  219. *(dst-1) = '/';
  220. }
  221. while (((*dst++) = (*file++)));
  222. return 1;
  223. }
  224. /* Interface routines : InsertFile, InsertText, and loadbuf
  225. */
  226. #if __STDC__
  227. int InsertFile(char *filnam, char *table[], char **result)
  228. #else
  229. int
  230. InsertFile(filnam, table, result)
  231. char *filnam;
  232. char *table[];
  233. char **result;
  234. #endif
  235. {
  236. char *newfn = 0;
  237. #ifdef INP_READ_IN_ONE
  238. char *text;
  239. long size;
  240. #endif /* INP_READ_IN_ONE */
  241. File *fd = 0;
  242. if (!filnam) fd = STDIN;
  243. else {
  244. if (table == 0 || filnam[0] == '/') {
  245. /* don't look in the table! */
  246. if (!sys_open(filnam, OP_READ, &fd)) return 0;
  247. }
  248. else {
  249. while (*table) {
  250. /* look in the directory table */
  251. if (!INP_mk_filename(*table++, filnam, &newfn)) {
  252. return 0;
  253. }
  254. if (sys_open(newfn, OP_READ, &fd)) {
  255. /* free filnam ??? NO we don't know
  256. where it comes from!
  257. */
  258. filnam = newfn;
  259. break;
  260. }
  261. free(newfn);
  262. newfn = 0;
  263. }
  264. }
  265. }
  266. if (fd) {
  267. register struct INP_buffer_header *bh = INP_push_bh();
  268. if (!bh) {
  269. if (fd != STDIN) sys_close(fd);
  270. return 0;
  271. }
  272. #ifdef INP_READ_IN_ONE
  273. if (fd == STDIN) return 0; /* illegal */
  274. if (!INP_rdfile(fd, filnam, &size, &text)) {
  275. sys_close(fd);
  276. return 0;
  277. }
  278. bh->bh_size = size;
  279. _ipp = bh->bh_text = text;
  280. #else /* not INP_READ_IN_ONE */
  281. if (
  282. !(_ipp = bh->bh_text = INP_pbuf())
  283. ||
  284. !INP_rdblock(fd,_ipp,&(bh->bh_size))) {
  285. if (fd != STDIN) sys_close(fd);
  286. return 0;
  287. }
  288. #endif /* INP_READ_IN_ONE */
  289. bh->bh_fd = fd; /* this is a file */
  290. if (result) *result = filnam;
  291. return 1;
  292. }
  293. return 0;
  294. }
  295. #if __STDC__
  296. int InsertText(char *text, int length)
  297. #else
  298. int
  299. InsertText(text, length)
  300. char *text;
  301. #endif
  302. {
  303. register struct INP_buffer_header *bh = INP_push_bh();
  304. if (!bh) return 0;
  305. bh->bh_size = (long) length;
  306. _ipp = bh->bh_text = text;
  307. bh->bh_fd = 0; /* No file! */
  308. return 1;
  309. }
  310. /* loadbuf() is called if LoadChar meets a '\0' character
  311. which may be the end-of-buffer mark of the current input
  312. buffer. The '\0' could be genuine although not likely.
  313. Note: this routine is exported due to its occurence in the definition
  314. of LoadChar [input.h], that is defined as a macro.
  315. */
  316. int loadbuf()
  317. {
  318. register struct INP_buffer_header *bh = INP_head;
  319. static char buf[INP_NPUSHBACK + 1];
  320. int FromFile;
  321. if (!bh) { /* stack exhausted, EOF on sourcefile */
  322. return EOI;
  323. }
  324. if (_ipp < &(bh->bh_text[bh->bh_size])) {
  325. /* a genuine '\0' character has been seen */
  326. return '\0';
  327. }
  328. if (!bh->bh_eofreturned) {
  329. FromFile = (bh->bh_fd != 0);
  330. #ifndef INP_READ_IN_ONE
  331. if (FromFile && bh->bh_size > 0) {
  332. #if INP_NPUSHBACK > 1
  333. register char *so = &(bh->bh_text[bh->bh_size]);
  334. register char *de = bh->bh_text;
  335. register int i = INP_NPUSHBACK - 1;
  336. if (i >= bh->bh_size) i = bh->bh_size - 1;
  337. while (i-- > 0) {
  338. /* make sure PushBack will work */
  339. *--de = *--so;
  340. }
  341. #endif
  342. if ( INP_rdblock(bh->bh_fd, bh->bh_text, &(bh->bh_size))
  343. &&
  344. bh->bh_size > 0
  345. ) {
  346. _ipp = bh->bh_text;
  347. return *_ipp++;
  348. }
  349. }
  350. #endif /* not INP_READ_IN_ONE */
  351. if (FromFile && bh->bh_fd != STDIN) sys_close(bh->bh_fd);
  352. #if INP_NPUSHBACK > 1
  353. {
  354. register char *so = &(bh->bh_text[bh->bh_size]);
  355. register char *de = &buf[INP_NPUSHBACK - 1];
  356. register int i = INP_NPUSHBACK - 1;
  357. if (i >= bh->bh_size) i = bh->bh_size - 1;
  358. for (;i > 0; i--) {
  359. /* make sure PushBack will work */
  360. *--de = *--so;
  361. }
  362. }
  363. #endif
  364. buf[INP_NPUSHBACK-1] = 0; /* make PushBack work on EOI */
  365. _ipp = &buf[INP_NPUSHBACK];
  366. if (bh->bh_fd) { /* unstack a file */
  367. #ifndef INP_READ_IN_ONE
  368. struct INP_i_buf *ib;
  369. ib = i_ptr->ib_next;
  370. free((char *) i_ptr);
  371. i_ptr = ib;
  372. #else /* INP_READ_IN_ONE */
  373. free(bh->bh_text);
  374. #endif /* INP_READ_IN_ONE */
  375. }
  376. bh->bh_text = buf;
  377. bh->bh_size = INP_NPUSHBACK - 1;
  378. if (FromFile) {
  379. if (AtEoIF()) {
  380. bh->bh_eofreturned = 1;
  381. return EOI;
  382. }
  383. }
  384. else {
  385. if (AtEoIT()) {
  386. bh->bh_eofreturned = 1;
  387. return EOI;
  388. }
  389. }
  390. }
  391. if (bh->bh_eofreturned && _ipp == &buf[INP_NPUSHBACK]) {
  392. return EOI;
  393. }
  394. if (INP_pop_bh()) {
  395. int c;
  396. LoadChar(c);
  397. return c;
  398. }
  399. _ipp = &buf[INP_NPUSHBACK];
  400. return EOI;
  401. }