inp_pkg.body 9.4 KB

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