inp_pkg.body 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  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. INP_PRIVATE int
  84. INP_rdfile(fd, fn, size, pbuf)
  85. register File *fd;
  86. char *fn; /* file name */
  87. register long *size;
  88. char **pbuf; /* output parameter */
  89. {
  90. extern long sys_filesize();
  91. int rsize;
  92. if (
  93. (*size = sys_filesize(fn)) < 0
  94. ||
  95. ((unsigned) (*size + 1) != (*size + 1))
  96. ||
  97. !(*pbuf = malloc((unsigned) (*size + 1)))) {
  98. return 0;
  99. }
  100. if (
  101. !sys_read(fd, *pbuf, (int) *size, &rsize)
  102. ||
  103. *size != rsize
  104. ) {
  105. free(*pbuf);
  106. return 0;
  107. }
  108. (*pbuf)[rsize] = '\0'; /* invoke loadbuf() at end */
  109. return 1;
  110. }
  111. #endif /* INP_READ_IN_ONE */
  112. #ifndef INP_READ_IN_ONE
  113. /* Input buffer supplying routines: INP_pbuf()
  114. */
  115. INP_PRIVATE struct INP_i_buf *i_ptr;
  116. _PROTOTYPE(INP_PRIVATE char * INP_pbuf, (void));
  117. INP_PRIVATE char *
  118. INP_pbuf()
  119. {
  120. register struct INP_i_buf *ib =
  121. (struct INP_i_buf *) malloc(sizeof(struct INP_i_buf));
  122. if (!ib) return 0;
  123. ib->ib_next = i_ptr;
  124. i_ptr = ib;
  125. /* Don't give him all of it, we need some to implement a good
  126. PushBack
  127. */
  128. return &(ib->ib_text[INP_NPUSHBACK-1]);
  129. }
  130. #endif /* not INP_READ_IN_ONE */
  131. /* Input buffer administration: INP_push_bh() and INP_pop_bh()
  132. */
  133. _PROTOTYPE(INP_PRIVATE struct INP_buffer_header *INP_push_bh, (void));
  134. _PROTOTYPE(INP_PRIVATE int INP_pop_bh, (void));
  135. INP_PRIVATE struct INP_buffer_header *
  136. INP_push_bh()
  137. {
  138. register struct INP_buffer_header *bh;
  139. if (bh = INP_head) {
  140. bh->bh_ipp = _ipp;
  141. #ifdef INP_TYPE
  142. bh->bh_i = INP_VAR;
  143. #endif /* INP_TYPE */
  144. }
  145. bh = INP_free;
  146. if (bh) INP_free = bh->bh_next;
  147. else if (!(bh = (struct INP_buffer_header *)malloc(sizeof(struct INP_buffer_header)))) return 0;
  148. bh->bh_next = INP_head;
  149. bh->bh_eofreturned = 0;
  150. INP_head = bh;
  151. return bh;
  152. }
  153. /* INP_pop_bh() uncovers the previous inputbuffer on the stack
  154. of headers. 0 is returned if there are no more
  155. inputbuffers on the stack, 1 is returned in the other case.
  156. */
  157. INP_PRIVATE int
  158. INP_pop_bh()
  159. {
  160. register struct INP_buffer_header *bh = INP_head;
  161. bh = bh->bh_next;
  162. INP_head->bh_next = INP_free;
  163. INP_free = INP_head;
  164. INP_head = bh;
  165. if (!bh) { /* no more entries */
  166. INP_head = (struct INP_buffer_header *) 0;
  167. return 0;
  168. }
  169. _ipp = bh->bh_ipp; /* restore previous input pointer */
  170. #ifdef INP_TYPE
  171. INP_VAR = bh->bh_i;
  172. #endif /* INP_TYPE */
  173. return 1;
  174. }
  175. #ifndef INP_READ_IN_ONE
  176. /* low level I/O routine : read one block from current input
  177. stream : INP_rdblock
  178. */
  179. _PROTOTYPE(INP_PRIVATE int INP_rdblock, (File *, char *, int *));
  180. INP_PRIVATE int
  181. INP_rdblock(fd, buf, n)
  182. File *fd;
  183. char *buf;
  184. int *n;
  185. {
  186. if (!sys_read(fd, buf, INP_BUFSIZE, n)) {
  187. return 0;
  188. }
  189. buf[*n] = '\0';
  190. return 1;
  191. }
  192. #endif /* not INP_READ_IN_ONE */
  193. /* Miscellaneous routines :
  194. INP_mk_filename()
  195. */
  196. _PROTOTYPE(INP_PRIVATE int INP_mk_filename, (char *, char *, char **));
  197. /* INP_mk_filename() concatenates a dir and filename.
  198. */
  199. INP_PRIVATE int
  200. INP_mk_filename(dir, file, newname)
  201. register char *dir, *file;
  202. char **newname;
  203. {
  204. register char *dst;
  205. dst = malloc((unsigned) (strlen(dir) + strlen(file) + 2));
  206. if (!dst) return 0;
  207. *newname = dst;
  208. if (*dir) {
  209. while (*dst++ = *dir++) ;
  210. *(dst-1) = '/';
  211. }
  212. while (*dst++ = *file++);
  213. return 1;
  214. }
  215. /* Interface routines : InsertFile, InsertText, and loadbuf
  216. */
  217. int
  218. InsertFile(filnam, table, result)
  219. char *filnam;
  220. char *table[];
  221. char **result;
  222. {
  223. char *newfn = 0;
  224. #ifdef INP_READ_IN_ONE
  225. char *text;
  226. long size;
  227. #endif /* INP_READ_IN_ONE */
  228. File *fd = 0;
  229. if (!filnam) fd = STDIN;
  230. else {
  231. if (table == 0 || filnam[0] == '/') {
  232. /* don't look in the table! */
  233. if (!sys_open(filnam, OP_READ, &fd)) return 0;
  234. }
  235. else {
  236. while (*table) {
  237. /* look in the directory table */
  238. if (!INP_mk_filename(*table++, filnam, &newfn)) {
  239. return 0;
  240. }
  241. if (sys_open(newfn, OP_READ, &fd)) {
  242. /* free filnam ??? NO we don't know
  243. where it comes from!
  244. */
  245. filnam = newfn;
  246. break;
  247. }
  248. free(newfn);
  249. newfn = 0;
  250. }
  251. }
  252. }
  253. if (fd) {
  254. register struct INP_buffer_header *bh = INP_push_bh();
  255. if (!bh) {
  256. if (fd != STDIN) sys_close(fd);
  257. return 0;
  258. }
  259. #ifdef INP_READ_IN_ONE
  260. if (fd == STDIN) return 0; /* illegal */
  261. if (!INP_rdfile(fd, filnam, &size, &text)) {
  262. sys_close(fd);
  263. return 0;
  264. }
  265. bh->bh_size = size;
  266. _ipp = bh->bh_text = text;
  267. #else /* not INP_READ_IN_ONE */
  268. if (
  269. !(_ipp = bh->bh_text = INP_pbuf())
  270. ||
  271. !INP_rdblock(fd,_ipp,&(bh->bh_size))) {
  272. if (fd != STDIN) sys_close(fd);
  273. return 0;
  274. }
  275. #endif /* INP_READ_IN_ONE */
  276. bh->bh_fd = fd; /* this is a file */
  277. if (result) *result = filnam;
  278. return 1;
  279. }
  280. return 0;
  281. }
  282. int
  283. InsertText(text, length)
  284. char *text;
  285. {
  286. register struct INP_buffer_header *bh = INP_push_bh();
  287. if (!bh) return 0;
  288. bh->bh_size = (long) length;
  289. _ipp = bh->bh_text = text;
  290. bh->bh_fd = 0; /* No file! */
  291. return 1;
  292. }
  293. /* loadbuf() is called if LoadChar meets a '\0' character
  294. which may be the end-of-buffer mark of the current input
  295. buffer. The '\0' could be genuine although not likely.
  296. Note: this routine is exported due to its occurence in the definition
  297. of LoadChar [input.h], that is defined as a macro.
  298. */
  299. int
  300. loadbuf()
  301. {
  302. register struct INP_buffer_header *bh = INP_head;
  303. static char buf[INP_NPUSHBACK + 1];
  304. int FromFile;
  305. if (!bh) { /* stack exhausted, EOF on sourcefile */
  306. return EOI;
  307. }
  308. if (_ipp < &(bh->bh_text[bh->bh_size])) {
  309. /* a genuine '\0' character has been seen */
  310. return '\0';
  311. }
  312. if (!bh->bh_eofreturned) {
  313. FromFile = (bh->bh_fd != 0);
  314. #ifndef INP_READ_IN_ONE
  315. if (FromFile && bh->bh_size > 0) {
  316. #if INP_NPUSHBACK > 1
  317. register char *so = &(bh->bh_text[bh->bh_size]);
  318. register char *de = bh->bh_text;
  319. register int i = INP_NPUSHBACK - 1;
  320. if (i >= bh->bh_size) i = bh->bh_size - 1;
  321. while (i-- > 0) {
  322. /* make sure PushBack will work */
  323. *--de = *--so;
  324. }
  325. #endif
  326. if ( INP_rdblock(bh->bh_fd, bh->bh_text, &(bh->bh_size))
  327. &&
  328. bh->bh_size > 0
  329. ) {
  330. _ipp = bh->bh_text;
  331. return *_ipp++;
  332. }
  333. }
  334. #endif /* not INP_READ_IN_ONE */
  335. if (FromFile && bh->bh_fd != STDIN) sys_close(bh->bh_fd);
  336. #if INP_NPUSHBACK > 1
  337. {
  338. register char *so = &(bh->bh_text[bh->bh_size]);
  339. register char *de = &buf[INP_NPUSHBACK - 1];
  340. register int i = INP_NPUSHBACK - 1;
  341. if (i >= bh->bh_size) i = bh->bh_size - 1;
  342. for (;i > 0; i--) {
  343. /* make sure PushBack will work */
  344. *--de = *--so;
  345. }
  346. }
  347. #endif
  348. buf[INP_NPUSHBACK-1] = 0; /* make PushBack work on EOI */
  349. _ipp = &buf[INP_NPUSHBACK];
  350. if (bh->bh_fd) { /* unstack a file */
  351. #ifndef INP_READ_IN_ONE
  352. struct INP_i_buf *ib;
  353. ib = i_ptr->ib_next;
  354. free((char *) i_ptr);
  355. i_ptr = ib;
  356. #else /* INP_READ_IN_ONE */
  357. free(bh->bh_text);
  358. #endif /* INP_READ_IN_ONE */
  359. }
  360. bh->bh_text = buf;
  361. bh->bh_size = INP_NPUSHBACK - 1;
  362. if (FromFile) {
  363. if (AtEoIF()) {
  364. bh->bh_eofreturned = 1;
  365. return EOI;
  366. }
  367. }
  368. else {
  369. if (AtEoIT()) {
  370. bh->bh_eofreturned = 1;
  371. return EOI;
  372. }
  373. }
  374. }
  375. if (bh->bh_eofreturned && _ipp == &buf[INP_NPUSHBACK]) {
  376. return EOI;
  377. }
  378. if (INP_pop_bh()) {
  379. int c;
  380. LoadChar(c);
  381. return c;
  382. }
  383. _ipp = &buf[INP_NPUSHBACK];
  384. return EOI;
  385. }