plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

s_rdinstack.c (2260B)


      1 
      2 #include <u.h>
      3 #include <libc.h>
      4 #include <bio.h>
      5 #include "libString.h"
      6 
      7 struct Sinstack{
      8 	int	depth;
      9 	Biobuf	*fp[32];	/* hard limit to avoid infinite recursion */
     10 };
     11 
     12 /* initialize */
     13 extern Sinstack *
     14 s_allocinstack(char *file)
     15 {
     16 	Sinstack *sp;
     17 	Biobuf *fp;
     18 
     19 	fp = Bopen(file, OREAD);
     20 	if(fp == nil)
     21 		return nil;
     22 
     23 	sp = malloc(sizeof *sp);
     24 	sp->depth = 0;
     25 	sp->fp[0] = fp;
     26 	return sp;
     27 }
     28 
     29 extern void
     30 s_freeinstack(Sinstack *sp)
     31 {
     32 	while(sp->depth >= 0)
     33 		Bterm(sp->fp[sp->depth--]);
     34 	free(sp);
     35 }
     36 
     37 /*  Append an input line to a String.
     38  *
     39  *  Empty lines and leading whitespace are removed.
     40  */
     41 static char *
     42 rdline(Biobuf *fp, String *to)
     43 {
     44 	int c;
     45 	int len = 0;
     46 
     47 	c = Bgetc(fp);
     48 
     49 	/* eat leading white */
     50 	while(c==' ' || c=='\t' || c=='\n' || c=='\r')
     51 		c = Bgetc(fp);
     52 
     53 	if(c < 0)
     54 		return 0;
     55 
     56 	for(;;){
     57 		switch(c) {
     58 		case -1:
     59 			goto out;
     60 		case '\\':
     61 			c = Bgetc(fp);
     62 			if (c != '\n') {
     63 				s_putc(to, '\\');
     64 				s_putc(to, c);
     65 				len += 2;
     66 			}
     67 			break;
     68 		case '\r':
     69 			break;
     70 		case '\n':
     71 			if(len != 0)
     72 				goto out;
     73 			break;
     74 		default:
     75 			s_putc(to, c);
     76 			len++;
     77 			break;
     78 		}
     79 		c = Bgetc(fp);
     80 	}
     81 out:
     82 	s_terminate(to);
     83 	return to->ptr - len;
     84 }
     85 
     86 /* Append an input line to a String.
     87  *
     88  * Returns a pointer to the character string (or 0).
     89  * Leading whitespace and newlines are removed.
     90  * Lines starting with #include cause us to descend into the new file.
     91  * Empty lines and other lines starting with '#' are ignored.
     92  */
     93 extern char *
     94 s_rdinstack(Sinstack *sp, String *to)
     95 {
     96 	char *p;
     97 	Biobuf *fp, *nfp;
     98 
     99 	s_terminate(to);
    100 	fp = sp->fp[sp->depth];
    101 
    102 	for(;;){
    103 		p = rdline(fp, to);
    104 		if(p == nil){
    105 			if(sp->depth == 0)
    106 				break;
    107 			Bterm(fp);
    108 			sp->depth--;
    109 			return s_rdinstack(sp, to);
    110 		}
    111 
    112 		if(strncmp(p, "#include", 8) == 0 && (p[8] == ' ' || p[8] == '\t')){
    113 			to->ptr = p;
    114 			p += 8;
    115 
    116 			/* sanity (and looping) */
    117 			if(sp->depth >= nelem(sp->fp))
    118 				sysfatal("s_rdinstack: includes too deep");
    119 
    120 			/* skip white */
    121 			while(*p == ' ' || *p == '\t')
    122 				p++;
    123 
    124 			nfp = Bopen(p, OREAD);
    125 			if(nfp == nil)
    126 				continue;
    127 			sp->depth++;
    128 			sp->fp[sp->depth] = nfp;
    129 			return s_rdinstack(sp, to);
    130 		}
    131 
    132 		/* got milk? */
    133 		if(*p != '#')
    134 			break;
    135 
    136 		/* take care of comments */
    137 		to->ptr = p;
    138 		s_terminate(to);
    139 	}
    140 	return p;
    141 }