1 /* INPUT AND BUFFER HANDLING MODULE */
4 Input buffering module: this module contains the routines that
5 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 PushBack() : (defined in input.h) push last character back onto
16 the input stream; NPUSHBACK characters of pushback
17 are guaranteed, provided that they have all been read
18 from the current input stream
19 AtEoIT() : this routine is called at the end of an inserted text.
20 A default one is provided, which does nothing.
21 AtEoIF() : this routine is called at the end of an inserted file.
22 A default one is provided, which does nothing.
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.
29 INP_READ_IN_ONE defined: every input file is read into memory completely
30 and made an input buffer. Only use it if the size of a file
31 fits always fits in an integer and you have lots of memory.
32 INP_READ_IN_ONE not defined: the input from files is buffered in
33 a fixed length input buffer
34 INP_NPUSHBACK: the number of characters pushback
40 extern char *malloc();
46 #define INP_NPUSHBACK 1
50 #define INP_NPUSHBACK 1
54 #define INP_BUFSIZE BUFSIZ
57 #if INP_NPUSHBACK > INP_BUFSIZE/2
58 Now this is really ridiculous! You deserve what you get!!
62 extern INP_TYPE INP_VAR;
68 #define INP_PRIVATE static
71 struct INP_buffer_header {
72 struct INP_buffer_header *bh_next;
73 int bh_size; /* = strlen (text), should be unsigned */
74 char *bh_text; /* pointer to buffer containing text */
75 char *bh_ipp; /* current read pointer (= stacked ipp) */
77 INP_TYPE bh_i; /* user defined */
79 File *bh_fd; /* A file descriptor in case of a file */
80 char bh_eofreturned; /* set if we returned eof for this buffer */
83 #ifndef INP_READ_IN_ONE
85 struct INP_i_buf *ib_next;
86 char ib_text[INP_BUFSIZE+INP_NPUSHBACK];
89 #endif /* not INP_READ_IN_ONE */
92 INP_PRIVATE struct INP_buffer_header *INP_head, *INP_free;
94 #ifdef INP_READ_IN_ONE
95 /* INP_rdfile() creates a buffer in which the text of the file
96 is situated. A pointer to the start of this text is
97 returned. *size is initialized with the buffer length.
100 _PROTOTYPE(INP_PRIVATE int INP_rdfile, (File *, char *, long *, char **));
103 INP_rdfile(fd, fn, size, pbuf)
105 char *fn; /* file name */
107 char **pbuf; /* output parameter */
109 extern long sys_filesize();
113 (*size = sys_filesize(fn)) < 0
115 ((unsigned) (*size + 1) != (*size + 1))
117 !(*pbuf = malloc((unsigned) (*size + 1)))) {
121 !sys_read(fd, *pbuf, (int) *size, &rsize)
128 (*pbuf)[rsize] = '\0'; /* invoke loadbuf() at end */
131 #endif /* INP_READ_IN_ONE */
133 #ifndef INP_READ_IN_ONE
134 /* Input buffer supplying routines: INP_pbuf()
137 INP_PRIVATE struct INP_i_buf *i_ptr;
139 _PROTOTYPE(INP_PRIVATE char * INP_pbuf, (void));
143 register struct INP_i_buf *ib =
144 (struct INP_i_buf *) malloc(sizeof(struct INP_i_buf));
150 /* Don't give him all of it, we need some to implement a good
153 return &(ib->ib_text[INP_NPUSHBACK-1]);
155 #endif /* not INP_READ_IN_ONE */
157 /* Input buffer administration: INP_push_bh() and INP_pop_bh()
159 _PROTOTYPE(INP_PRIVATE struct INP_buffer_header *INP_push_bh, (void));
160 _PROTOTYPE(INP_PRIVATE int INP_pop_bh, (void));
162 INP_PRIVATE struct INP_buffer_header *
165 register struct INP_buffer_header *bh;
171 #endif /* INP_TYPE */
174 if (bh) INP_free = bh->bh_next;
175 else if (!(bh = (struct INP_buffer_header *)malloc(sizeof(struct INP_buffer_header)))) return 0;
176 bh->bh_next = INP_head;
177 bh->bh_eofreturned = 0;
182 /* INP_pop_bh() uncovers the previous inputbuffer on the stack
183 of headers. 0 is returned if there are no more
184 inputbuffers on the stack, 1 is returned in the other case.
189 register struct INP_buffer_header *bh = INP_head;
193 INP_head->bh_next = INP_free;
197 if (!bh) { /* no more entries */
198 INP_head = (struct INP_buffer_header *) 0;
202 _ipp = bh->bh_ipp; /* restore previous input pointer */
205 #endif /* INP_TYPE */
210 #ifndef INP_READ_IN_ONE
211 /* low level I/O routine : read one block from current input
214 _PROTOTYPE(INP_PRIVATE int INP_rdblock, (File *, char *, int *));
217 INP_rdblock(fd, buf, n)
223 if (!sys_read(fd, buf, INP_BUFSIZE, n)) {
229 #endif /* not INP_READ_IN_ONE */
231 /* Miscellaneous routines :
234 _PROTOTYPE(INP_PRIVATE int INP_mk_filename, (char *, char *, char **));
236 /* INP_mk_filename() concatenates a dir and filename.
239 INP_mk_filename(dir, file, newname)
240 register char *dir, *file;
246 dst = malloc((unsigned) (strlen(dir) + strlen(file) + 2));
250 while (*dst++ = *dir++) ;
253 while (*dst++ = *file++);
257 /* Interface routines : InsertFile, InsertText, and loadbuf
261 InsertFile(filnam, table, result)
268 #ifdef INP_READ_IN_ONE
271 #endif /* INP_READ_IN_ONE */
274 if (!filnam) fd = STDIN;
276 if (table == 0 || filnam[0] == '/') {
277 /* don't look in the table! */
278 if (!sys_open(filnam, OP_READ, &fd)) return 0;
282 /* look in the directory table */
283 if (!INP_mk_filename(*table++, filnam, &newfn)) {
286 if (sys_open(newfn, OP_READ, &fd)) {
287 /* free filnam ??? NO we don't know
300 register struct INP_buffer_header *bh = INP_push_bh();
303 if (fd != STDIN) sys_close(fd);
306 #ifdef INP_READ_IN_ONE
307 if (fd == STDIN) return 0; /* illegal */
308 if (!INP_rdfile(fd, filnam, &size, &text)) {
313 _ipp = bh->bh_text = text;
314 #else /* not INP_READ_IN_ONE */
316 !(_ipp = bh->bh_text = INP_pbuf())
318 !INP_rdblock(fd,_ipp,&(bh->bh_size))) {
319 if (fd != STDIN) sys_close(fd);
322 #endif /* INP_READ_IN_ONE */
323 bh->bh_fd = fd; /* this is a file */
324 if (result) *result = filnam;
331 InsertText(text, length)
334 register struct INP_buffer_header *bh = INP_push_bh();
337 bh->bh_size = (long) length;
338 _ipp = bh->bh_text = text;
339 bh->bh_fd = 0; /* No file! */
343 /* loadbuf() is called if LoadChar meets a '\0' character
344 which may be the end-of-buffer mark of the current input
345 buffer. The '\0' could be genuine although not likely.
346 Note: this routine is exported due to its occurence in the definition
347 of LoadChar [input.h], that is defined as a macro.
352 register struct INP_buffer_header *bh = INP_head;
353 static char buf[INP_NPUSHBACK + 1];
356 if (!bh) { /* stack exhausted, EOF on sourcefile */
360 if (_ipp < &(bh->bh_text[bh->bh_size])) {
361 /* a genuine '\0' character has been seen */
365 if (!bh->bh_eofreturned) {
366 FromFile = (bh->bh_fd != 0);
368 #ifndef INP_READ_IN_ONE
369 if (FromFile && bh->bh_size > 0) {
370 #if INP_NPUSHBACK > 1
371 register char *so = &(bh->bh_text[bh->bh_size]);
372 register char *de = bh->bh_text;
373 register int i = INP_NPUSHBACK - 1;
375 if (i >= bh->bh_size) i = bh->bh_size - 1;
377 /* make sure PushBack will work */
381 if ( INP_rdblock(bh->bh_fd, bh->bh_text, &(bh->bh_size))
390 #endif /* not INP_READ_IN_ONE */
391 if (FromFile && bh->bh_fd != STDIN) sys_close(bh->bh_fd);
393 #if INP_NPUSHBACK > 1
395 register char *so = &(bh->bh_text[bh->bh_size]);
396 register char *de = &buf[INP_NPUSHBACK - 1];
397 register int i = INP_NPUSHBACK - 1;
399 if (i >= bh->bh_size) i = bh->bh_size - 1;
401 /* make sure PushBack will work */
406 buf[INP_NPUSHBACK-1] = 0; /* make PushBack work on EOI */
407 _ipp = &buf[INP_NPUSHBACK];
409 if (bh->bh_fd) { /* unstack a file */
410 #ifndef INP_READ_IN_ONE
411 struct INP_i_buf *ib;
414 free((char *) i_ptr);
416 #else /* INP_READ_IN_ONE */
418 #endif /* INP_READ_IN_ONE */
421 bh->bh_size = INP_NPUSHBACK - 1;
424 bh->bh_eofreturned = 1;
430 bh->bh_eofreturned = 1;
436 if (bh->bh_eofreturned && _ipp == &buf[INP_NPUSHBACK]) {
445 _ipp = &buf[INP_NPUSHBACK];