1 /* Copyright (C) 1992-1998 The Geometry Center
2 * Copyright (C) 1998-2000 Stuart Levy, Tamara Munzner, Mark Phillips
3 * Copyright (C) 2002-2007 Claus-Justus Heine
4 *
5 * This file is part of Geomview.
6 *
7 * Geomview is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2, or (at
10 * your option) any later version.
11 *
12 * Geomview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with Geomview; see the file COPYING. If not, write
19 * to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
20 * USA, or visit http://www.gnu.org.
21 */
22
23 /*
24 * Geometry object routines, like in futil.c, but FILE replace with
25 * IOBFILE implemented in iobuffer.c. This way we can seek back safely
26 * on pipes, sockets, etc.
27 *
28 * Utility routines, useful for many objects
29 *
30 * int
31 * iobfgetnf(iobf, nfloats, floatp, binary)
32 * Read an array of floats from a file in "ascii" or "binary" format.
33 * Returns number of floats successfully read, should = nfloats.
34 * "Binary" means "IEEE 32-bit floating-point" format.
35 *
36 * int
37 * iobfgetni(IOBFILE *iobf, int nints, int *intsp, int binary)
38 * Read an array of ints from a file in "ascii" or "binary" format.
39 * Returns number of ints successfully read, should = nints.
40 * "Binary" means "32-bit big-endian" integer format.
41 *
42 * int
43 * iobfgetns(IOBFILE *iobf, int nshorts, short *intsp, int binary)
44 * Read an array of shorts from a file in "ascii" or "binary" format.
45 * Returns number of shorts successfully read, should = nints.
46 * "Binary" means "16-bit big-endian" integer format.
47 *
48 * int
49 * iobfexpectstr(IOBFILE *iobf, char *string)
50 * Expect the given string to appear immediately on file.
51 * Return 0 if the complete string is found,
52 * else the offset+1 of the last matched char within string.
53 * The first unmatched char is ungetc'd.
54 *
55 * int
56 * iobfexpecttoken(IOBFILE *iobf, char *string)
57 * Expect the given string to appear on the iobf, possibly after
58 * skipping some white space and comments.
59 * Return 0 if found, else the offset+1 of last matched char in string.
60 * The first unmatched char is ungetc'd.
61 *
62 * int iobfnextc(IOBFILE *f, int flags)
63 * Advances f to the next "interesting" character and
64 * returns it. The returned char is ungetc'ed so the next getc()
65 * will yield the same value.
66 * Interesting depends on flags:
67 * 0 : Skip blanks, tabs, newlines, and comments (#...\n).
68 * 1 : Skip blanks, tabs, and comments, but newlines are interesting
69 * (including the \n that terminates a comment).
70 * 2 : Skip blanks, tabs, and newlines, but stop at #.
71 * 3 : Skip blanks and tabs but stop at # or \n.
72 *
73 * int async_iobfnextc(IOBFILE *f, int flags)
74 * Like fnextc() above, but guarantees not to block if no data is
75 * immediately available. It returns either an interesting character,
76 * EOF, or the special code NODATA (== -2).
77 * if fd == -1, then fileno(f) is used, otherwise fd.
78 *
79 * int async_iobfgetc(IOBFILE *f, false)
80 * Like getc(), but guarantees not to block. Returns NODATA if
81 * nothing is immediately available.
82 *
83 * char *iobftoken(IOBFILE *f, int flags)
84 * Skips uninteresting characters with fnextc(f, flags),
85 * then returns a "token" - string of consecutive interesting characters.
86 * Returns NULL if EOF is reached with no token, or if
87 * flags specifies stopping at end-of-line and this is encountered with
88 * no token found.
89 * The token is effectively statically allocated and will be
90 * overwritten by the next ftoken() call.
91 *
92 * char *iobfdelimtok(char *delims, IOBFILE *f, int flags)
93 * Like ftoken(), but specially handles the characters in delims[].
94 * If one appears at the beginning of the token, it's returned as
95 * a single-character token.
96 * If a member of delims[] appears after other characters have been
97 * accumulated, it's considered to terminate the token.
98 * So successive calls to fdelimtok("()", f, 0)
99 * on a file containing (fred smith)
100 * would return "(", "fred", "smith", and ")".
101 * Behavior is undefined if one of the predefined delimiters
102 * (white space or #) appears in delims[]. Explicit quoting
103 * (with ", ' or \) overrides detection of delimiters.
104 *
105 * int iobfgettransform(IOBFILE *f, int ntransforms,
106 * float *transforms, int binary)
107 * Reads 4x4 matrices from IOBFILE. Returns the number of matrices found,
108 * up to ntransforms. Returns 0 if no numbers are found.
109 * On finding incomplete matrices (not a multiple of 16 floats)
110 * returns -1, regardless of whether any whole matrices were found.
111 * Matrices are expected in the form used to transform a row vector
112 * multiplied on the left, i.e. p * T -> p'; thus Euclidean translations
113 * appear in the last row.
114 *
115 * int iobfputtransform(IOBFILE *f, int ntransforms,
116 * float *transforms, int binary)
117 * Writes 4x4 matrices to IOBFILE. Returns the number written, i.e.
118 * ntransforms unless an error occurs.
119 *
120 * int iobfputnf(IOBFILE *f, int nfloats, float *fv, int binary)
121 * Writes 'nfloats' floats to the given file. ASCII is in %g format,
122 * separated by blanks.
123 *
124 */
125
126
127 #ifdef HAVE_CONFIG_H
128 # include "config.h"
129 #endif
130
131 #include <stdio.h>
132 #include <sys/types.h>
133 #include <math.h>
134
135 /* Try to get the prototype for select */
136 #if HAVE_SYS_SELECT_H
137 # include <sys/select.h>
138 #endif
139 #if HAVE_UNISTD_H
140 # include <unistd.h>
141 #endif
142 #if HAVE_SYS_TIME_H
143 # include <sys/time.h>
144 #endif
145 #if HAVE_SYS_TYPES_H
146 # include <sys/types.h>
147 #endif
148
149 #include <stdlib.h>
150 #include <string.h>
151 #include <ctype.h>
152
153 #include "ooglutil.h"
154
155 #include "iobuffer.h"
156
157 #undef getc
158 #define getc gobble
159 #define ungetc gobble
160 #define fgetc gobble
161
162 #ifndef WORDS_BIGENDIAN
gv_ntohl(unsigned int v)163 static inline int gv_ntohl(unsigned int v) {
164 return (((v >> 24) & 0x000000FF) |
165 ((v << 24) & 0xFF000000) |
166 ((v >> 8) & 0x0000FF00) |
167 ((v << 8) & 0x00FF0000));
168 }
gv_ntohs(unsigned short s)169 static inline short gv_ntohs(unsigned short s) {
170 return (((s >> 8) & 0x00FF) | ((s << 8) & 0xFF00));
171 }
172 #else
gv_ntohl(unsigned int v)173 static inline int gv_ntohl(unsigned int v) {
174 return v;
175 }
gv_ntohs(unsigned short s)176 static inline short gv_ntohs(unsigned short s) {
177 return s;
178 }
179 #endif
180
gv_htons(unsigned short s)181 static inline short gv_htons(unsigned short s)
182 {
183 return gv_ntohs(s);
184 }
gv_htonl(unsigned int v)185 static inline int gv_htonl(unsigned int v) {
186 return gv_ntohl(v);
187 }
188
iobfnextc(IOBFILE * f,int flags)189 int iobfnextc(IOBFILE *f, int flags)
190 {
191 int c;
192
193 c = iobfgetc(f);
194 for(;;) {
195 switch(c) {
196 case EOF:
197 return EOF;
198
199 case ' ':
200 case '\t':
201 break; /* Always skip blanks and tabs */
202
203 case '#':
204 if(flags & 2) /* 2: stop on comments, else skip */
205 goto fim;
206
207 while((c = iobfgetc(f)) != '\n' && c != EOF)
208 ;
209 continue; /* Rescan this c */
210
211 case '\n':
212 if(!(flags & 1)) /* 1: stop on \n's, else skip them */
213 break;
214 /* flags&1 => fall into default */
215
216 default:
217 fim:
218 iobfungetc(c, f);
219 return c;
220 }
221
222 c = iobfgetc(f);
223 }
224 }
225
226 /* Read an array of white-space-separated floats from file 'f' in
227 * ASCII, fast. Returns the number successfully read.
228 */
iobfgetnf(IOBFILE * f,int maxf,float * fv,int binary)229 int iobfgetnf(IOBFILE *f, int maxf, float *fv, int binary)
230 {
231 int ngot;
232 float v = 0;
233 int c = EOF;
234 long n;
235 int s, es, nd, any;
236
237 if(binary) {
238 #if WORDS_BIGENDIAN
239 /* Easy -- our native floating point == big-endian IEEE */
240 return iobfread((char *)fv, sizeof(float), maxf, f);
241 #else /* not native big-endian IEEE */
242 union {
243 int wi;
244 float wf;
245 } w;
246 for(n=0; n<maxf && iobfread((char *)&w,sizeof(float),1,f) > 0; n++) {
247 w.wi = gv_ntohl(w.wi);
248 fv[n] = w.wf;
249 }
250 return n;
251 #endif /* not native big-endian IEEE */
252 }
253
254 /* Read ASCII format floats */
255 for(ngot = 0; ngot < maxf; ngot++) {
256 if(iobfnextc(f, 0) == EOF)
257 return(ngot);
258 n = 0;
259 s = 0;
260 nd = 0;
261 any = 0;
262 if((c = iobfgetc(f)) == '-') {
263 s = 1;
264 c = iobfgetc(f);
265 }
266 while(c >= '0' && c <= '9') {
267 n = n*10 + c - '0';
268 nd++;
269 if(n >= 214748364) { /* 2^31 / 10 */
270 v = any ? v*pow(10.0, nd) + (float)n : (float)n;
271 nd = n = 0;
272 any = 1;
273 }
274 c = iobfgetc(f);
275 }
276 v = any ? v*pow(10.0, nd) + (float)n : (float)n;
277 any += nd;
278 if(c == '.') {
279 nd = n = 0;
280 while((c = iobfgetc(f)) >= '0' && c <= '9') {
281 n = n*10 + c - '0';
282 nd++;
283 if(n >= 214748364) {
284 v += (float)n / pow(10.0f, nd);
285 n = 0;
286 }
287 }
288 v += (float)n / pow(10.0, nd);
289 }
290 if(any == 0 && nd == 0)
291 break;
292 if(c == 'e' || c == 'E') {
293 es = nd = 0;
294 switch(c = iobfgetc(f)) {
295 case '-':
296 es = 1; /* And fall through */
297 case '+':
298 c = iobfgetc(f);
299 }
300 n = 0;
301 while(c >= '0' && c <= '9') {
302 n = n*10 + c - '0';
303 nd++;
304 c = iobfgetc(f);
305 }
306 if(nd == 0)
307 break;
308 if(es) v /= pow(10.0, n);
309 else v *= pow(10.0, n);
310 }
311 fv[ngot] = s ? -v : v;
312 }
313 if(c!=EOF) iobfungetc(c, f);
314 return(ngot);
315 }
316
317 /* Read an array of white-space-separated floats from file 'f' in
318 * ASCII, fast. Returns the number successfully read.
319 */
iobfgetnd(IOBFILE * f,int maxd,double * dv,int binary)320 int iobfgetnd(IOBFILE *f, int maxd, double *dv, int binary)
321 {
322 int ngot;
323 double v = 0;
324 int c = EOF;
325 long n;
326 int s, es, nd, any;
327
328 if(binary) {
329 #if WORDS_BIGENDIAN
330 /* Easy -- our native floating point == big-endian IEEE */
331 return iobfread((char *)dv, sizeof(double), maxd, f);
332 #else /* not native big-endian IEEE */
333 union {
334 int wi[2];
335 double wd;
336 } w;
337 int tmp;
338 for(n=0; n<maxd && iobfread((char *)&w,sizeof(double),1,f) > 0; n++) {
339 tmp = gv_ntohl(w.wi[0]);
340 w.wi[0] = gv_ntohl(w.wi[1]);
341 w.wi[1] = tmp;
342 dv[n] = w.wd;
343 }
344 return n;
345 #endif /* not native big-endian IEEE */
346 }
347
348 /* Read ASCII format floats */
349 for(ngot = 0; ngot < maxd; ngot++) {
350 if(iobfnextc(f, 0) == EOF)
351 return(ngot);
352 n = 0;
353 s = 0;
354 nd = 0;
355 any = 0;
356 if((c = iobfgetc(f)) == '-') {
357 s = 1;
358 c = iobfgetc(f);
359 }
360 while(c >= '0' && c <= '9') {
361 n = n*10 + c - '0';
362 nd++;
363 if(n >= 214748364) { /* 2^31 / 10 */
364 v = any ? v*pow(10.0, nd) + (float)n : (float)n;
365 nd = n = 0;
366 any = 1;
367 }
368 c = iobfgetc(f);
369 }
370 v = any ? v*pow(10.0, (double)nd) + (float)n : (float)n;
371 any += nd;
372 if(c == '.') {
373 nd = n = 0;
374 while((c = iobfgetc(f)) >= '0' && c <= '9') {
375 n = n*10 + c - '0';
376 nd++;
377 if(n >= 214748364) {
378 v += (float)n / pow(10.0, (double)nd);
379 n = 0;
380 }
381 }
382 v += (float)n / pow(10.0, (double)nd);
383 }
384 if(any == 0 && nd == 0)
385 break;
386 if(c == 'e' || c == 'E') {
387 es = nd = 0;
388 switch(c = iobfgetc(f)) {
389 case '-':
390 es = 1; /* And fall through */
391 case '+':
392 c = iobfgetc(f);
393 }
394 n = 0;
395 while(c >= '0' && c <= '9') {
396 n = n*10 + c - '0';
397 nd++;
398 c = iobfgetc(f);
399 }
400 if(nd == 0)
401 break;
402 if(es) v /= pow(10.0, (double)n);
403 else v *= pow(10.0, n);
404 }
405 dv[ngot] = s ? -v : v;
406 }
407 if(c!=EOF) iobfungetc(c, f);
408 return(ngot);
409 }
410
411 int
iobfgetni(IOBFILE * f,int maxi,int * iv,int binary)412 iobfgetni(IOBFILE *f, int maxi, int *iv, int binary)
413 {
414 int ngot;
415 int c = EOF;
416 long n;
417 int s, any;
418
419 if(binary) {
420 #if WORDS_BIGENDIAN
421 /* Easy -- our native floating point == big-endian IEEE */
422 return iobfread((char *)iv, sizeof(int), maxi, f);
423 #else /* not native big-endian int's */
424 int w;
425 for(n = 0; n < maxi && iobfread(&w,4,1,f) > 0; n++)
426 iv[n] = gv_ntohl(w);
427 return n;
428 #endif /* not native big-endian int's */
429 }
430
431 /* Read ASCII format floats */
432 for(ngot = 0; ngot < maxi; ngot++) {
433 if(iobfnextc(f, 0) == EOF)
434 return(ngot);
435 n = 0;
436 s = 0;
437 any = 0;
438 if((c = iobfgetc(f)) == '-') {
439 s = 1;
440 c = iobfgetc(f);
441 }
442 while(c >= '0' && c <= '9') {
443 n = n*10 + c - '0';
444 any = 1;
445 c = iobfgetc(f);
446 }
447 if(!any)
448 break;
449 iv[ngot] = s ? -n : n;
450 }
451 if(c!=EOF) iobfungetc(c, f);
452 return(ngot);
453 }
454
455 int
iobfgetns(IOBFILE * f,int maxs,short * sv,int binary)456 iobfgetns(IOBFILE *f, int maxs, short *sv, int binary)
457 {
458 int ngot;
459 int c = EOF;
460 long n;
461 int s, any;
462
463 if(binary) {
464 #if WORDS_BIGENDIAN
465 /* Easy -- our native floating point == big-endian IEEE */
466 return iobfread((char *)sv, sizeof(short), maxs, f);
467 #else /* not native big-endian int's */
468 short w;
469 for(n = 0; n < maxs && iobfread(&w,2,1,f) > 0; n++)
470 sv[n] = gv_ntohs(w);
471 return n;
472 #endif /* not native big-endian int's */
473 }
474
475 /* Read ASCII format floats */
476 for(ngot = 0; ngot < maxs; ngot++) {
477 if(iobfnextc(f, 0) == EOF)
478 return(ngot);
479 n = s = any = 0;
480 if((c = iobfgetc(f)) == '-') {
481 s = 1;
482 c = iobfgetc(f);
483 }
484 while(c >= '0' && c <= '9') {
485 n = n*10 + c - '0';
486 any = 1;
487 c = iobfgetc(f);
488 }
489 if(!any)
490 break;
491 sv[ngot] = s ? -n : n;
492 }
493 if(c!=EOF) iobfungetc(c, f);
494 return(ngot);
495 }
496
497 /*
498 * Check for a string on a file.
499 * If found, return 0.
500 * If not, return the offset of the last matched char +1
501 * and iobfungetc the failed char so the caller can see it.
502 */
503 int
iobfexpectstr(IOBFILE * iobf,char * str)504 iobfexpectstr(IOBFILE *iobf, char *str)
505 {
506 char *p = str;
507 int c;
508
509 while(*p != '\0') {
510 if((c = iobfgetc(iobf)) != *p++) {
511 if(c != EOF)
512 iobfungetc(c, iobf);
513 return(p - str);
514 }
515 }
516 return 0;
517 }
518
519 /*
520 * Check for a string on a iobf, skipping leading blanks.
521 */
522 int
iobfexpecttoken(IOBFILE * iobf,char * str)523 iobfexpecttoken(IOBFILE *iobf, char *str)
524 {
525 (void) iobfnextc(iobf, 0);
526 return iobfexpectstr(iobf, str);
527 }
528
iobfescape(IOBFILE * f)529 int iobfescape(IOBFILE *f)
530 {
531 int n, k, c = iobfgetc(f);
532
533 switch (c) {
534 case 'n': return '\n';
535 case 'b': return '\b';
536 case 't': return '\t';
537 case 'r': return '\r';
538 }
539 if (c < '0' || c > '7')
540 return c;
541
542 n = c-'0'; k = 2;
543 while ((c = iobfgetc(f)) >= '0' && c <= '7') {
544 n = (n*8) | (c-'0');
545 if(--k <= 0)
546 return n;
547 }
548 if (c != EOF) iobfungetc(c, f);
549 return n;
550 }
551
552 /*
553 * Get a token, return a string or NULL.
554 * Tokens may be "quoted" or 'quoted'; backslashes accepted.
555 * The string is statically allocated and should be copied if
556 * needed before the next call to ftoken().
557 */
558 char *
iobfquotedelimtok(const char * delims,IOBFILE * iobf,int flags,int * quote)559 iobfquotedelimtok(const char *delims, IOBFILE *iobf, int flags, int *quote)
560 {
561 static char *token = NULL;
562 static int troom = 0;
563 int c;
564 char *p;
565 const char *q;
566 int term;
567
568 if((term = iobfnextc(iobf, flags)) == EOF)
569 return NULL;
570
571 if(token == NULL) {
572 troom = 50;
573 token = malloc(troom * sizeof(char));
574 if(token == NULL)
575 return NULL;
576 }
577
578 p = token;
579 switch (term) {
580 case '"':
581 case '\'':
582 *quote = term;
583 (void)iobfgetc(iobf);
584 for(;;) {
585 if((c = iobfgetc(iobf)) == EOF || c == term)
586 break;
587 else if (c == '\\')
588 c = iobfescape(iobf);
589 *p++ = c;
590 if(p == &token[troom]) {
591 token = realloc(token, troom * 2);
592 if(token == NULL)
593 return NULL;
594 p = &token[troom];
595 troom *= 2;
596 }
597 }
598 break;
599
600 default:
601 *quote = '\0';
602 if(isspace(term))
603 return NULL;
604 while((c = iobfgetc(iobf)) != EOF && !isspace(c)) {
605 if(c == '\\')
606 c = iobfescape(iobf);
607 *p = c;
608 if(++p == &token[troom]) {
609 token = realloc(token, troom * 2);
610 if(token == NULL)
611 return NULL;
612 p = &token[troom];
613 troom *= 2;
614 }
615 for(q = delims; *q && c != *q; q++)
616 ;
617 if(*q) {
618 if(p > token+1) {
619 p--;
620 iobfungetc(c, iobf);
621 }
622 break;
623 }
624 }
625 break;
626 }
627 *p = '\0';
628 return token;
629 }
630
iobfdelimtok(const char * delims,IOBFILE * iobf,int flags)631 char *iobfdelimtok(const char *delims, IOBFILE *iobf, int flags)
632 {
633 int tmp;
634 return iobfquotedelimtok(delims, iobf, flags, &tmp);
635 }
636 /*
637 * Get a token, return a string or NULL.
638 * Tokens may be "quoted" or 'quoted'; backslashes accepted.
639 * The string is statically allocated and should be copied if
640 * needed before the next call to ftoken().
641 */
642 char *
iobfquotetoken(IOBFILE * iobf,int flags,int * quote)643 iobfquotetoken(IOBFILE *iobf, int flags, int *quote)
644 {
645 return iobfquotedelimtok("", iobf, flags, quote);
646 }
647
648 char *
iobftoken(IOBFILE * iobf,int flags)649 iobftoken(IOBFILE *iobf, int flags)
650 {
651 return iobfdelimtok("", iobf, flags);
652 }
653
654 /*
655 * Load one or more Transforms from a file.
656 * Return 1 on success, 0 on failure.
657 */
658 int
iobfgettransform(IOBFILE * iobf,int ntrans,float * trans,int binary)659 iobfgettransform(IOBFILE *iobf, int ntrans, float *trans /* float trans[ntrans][4][4] */, int binary)
660 {
661 float *T;
662 int nt;
663
664 for(nt = 0; nt < ntrans; nt++) {
665 T = trans + 16*nt;
666 switch(iobfgetnf(iobf, 16, T, binary)) {
667 case 16:
668 break;
669
670 case 0:
671 return nt;
672
673 default:
674 return -1;
675 }
676 }
677 return ntrans;
678 }
679
680 /*
681 * Given a file pointer, return a string attempting to show the context
682 * of its current position. If no data is available, returns the empty string.
683 */
684 #define CONTEXT_SIZE 256
685
686 char *
iobfcontext(IOBFILE * f)687 iobfcontext(IOBFILE *f)
688 {
689 static char *cont = NULL;
690 static char dflt[] = "";
691 char buf[1024];
692 int npre, nlpre, nlpost, tab, len;
693 int predots = 4, postdots = 4;
694 char *p, *q;
695 char *lastline, *lastnonblank;
696 char base[CONTEXT_SIZE], *ptr;
697 int cnt;
698
699 if (f == NULL)
700 return dflt;
701 if (iobfeof(f)) {
702 return "> END OF IOBFILE\n";
703 }
704
705 cnt = iobfgetbuffer(f, base, sizeof(base), -1);
706
707 if(cnt <= 0) {
708 return dflt;
709 }
710
711 ptr = base + cnt;
712 p = ptr;
713 for(npre = nlpre = 0; --p >= base && npre < CONTEXT_SIZE; npre++) {
714 if(*p == '\n') {
715 if(++nlpre > 2 || npre > 60) {
716 predots = 0;
717 break;
718 }
719 } else if(*p & 0x80 || *p == 0) { /* binary data? */
720 break;
721 }
722 }
723 strcpy(buf, "> ... ");
724 q = buf + 2 + predots;
725 tab = 2 + predots;
726 for(p = ptr - npre; p < ptr; ) {
727 switch(*q++ = *p++) {
728 case '\n': case '\r': *q++ = '>'; *q++ = ' '; tab = 2; break;
729 case '\t': tab += 8-(tab&7); break;
730 default: tab++;
731 }
732 }
733 len = npre;
734 nlpost = 0;
735 lastline = lastnonblank = q;
736 for(p = ptr; p < ptr + cnt && len < CONTEXT_SIZE; len++, q++) {
737 *q = *p++;
738 if(*q == '\n') {
739 if(nlpost == 0) {
740 while(--tab > 0) *++q = '-'; /* Point ---^ to error */
741 *++q = '^'; *++q = '\n';
742 }
743 if((++nlpost >= 2 || len > 80) && len > 32) {
744 postdots = 0;
745 break;
746 }
747 lastline = q;
748 *++q = '>'; *++q = ' ';
749 } else if(*q & 0x80 || *q == 0) /* Binary data */
750 break;
751 else if(isprint(*q))
752 lastnonblank = q;
753 }
754 if(postdots && lastnonblank < lastline) {
755 q = lastline; /* Suppress trailing white space */
756 postdots = 0; /* to avoid final ``> ...'' */
757 }
758 strcpy(q, " ...\n" + 4-postdots);
759 if(nlpost == 0) {
760 q += strlen(q);
761 while(--tab > 0) *q++ = '-';
762 strcpy(q, "^\n");
763 }
764 if(cont) {
765 free(cont);
766 }
767 return (cont = strdup(buf));
768 }
769
770 /***************************************************************************/
771
772 int
iobfhasdata(IOBFILE * f)773 iobfhasdata(IOBFILE *f)
774 {
775 return iobfgetbuffer(f, NULL, 0, 1) > 0;
776 }
777
778 int
async_iobfgetc(IOBFILE * f)779 async_iobfgetc(IOBFILE *f)
780 {
781 #if HAVE_SELECT
782 fd_set fds;
783 int fd;
784 static struct timeval notime = { 0, 0 };
785
786 fd = iobfileno(f);
787
788 if(iobfhasdata(f))
789 return iobfgetc(f);
790 if (fd < 0)
791 return NODATA;
792 FD_ZERO(&fds);
793 FD_SET(fd, &fds);
794 if(select(fd+1, &fds, NULL, NULL, ¬ime) == 1)
795 return iobfgetc(f);
796 return NODATA;
797 #else
798 return iobfgetc(f);
799 #endif
800 }
801
802 int
async_iobfnextc(IOBFILE * f,int flags)803 async_iobfnextc(IOBFILE *f, int flags)
804 {
805 int c;
806
807 c = async_iobfgetc(f);
808 for(;;) {
809 switch(c) {
810 case EOF:
811 case NODATA:
812 return(c);
813
814 case ' ':
815 case '\t':
816 break; /* Always skip blanks and tabs */
817
818 case '#':
819 if(flags & 2) /* 2: stop on comments, else skip */
820 goto fim;
821
822 while((c = iobfgetc(f)) != '\n' && c != EOF)
823 ;
824 continue; /* Rescan this c */
825
826 case '\n':
827 if(!(flags & 1)) /* 1: stop on \n's, else skip them */
828 break;
829 /* flags&1 => fall into default */
830
831 default:
832 fim:
833 iobfungetc(c, f);
834 return(c);
835 }
836
837 c = async_iobfgetc(f);
838 }
839 }
840
841 /*
842 * Local Variables: ***
843 * mode: c ***
844 * c-basic-offset: 2 ***
845 * End: ***
846 */
847