1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
20 * *
21 ***********************************************************************/
22 #pragma prototyped
23 /*
24 * Glenn Fowler
25 * AT&T Research
26 *
27 * return an Sfio_t* to a file or string that
28 *
29 * splices \\n to single lines
30 * checks for "..." and '...' spanning newlines
31 * drops #...\n comments
32 *
33 * if <arg> is a file and first line matches
34 * #!!! <level> <message> !!!
35 * then error(<lev>,"%s: %s",<arg>,<msg>) called
36 *
37 * NOTE: seek disabled and string disciplines cannot be composed
38 * quoted \n translated to \r
39 */
40
41 #include <ast.h>
42 #include <error.h>
43 #include <tok.h>
44
45 typedef struct
46 {
47 Sfdisc_t disc;
48 Sfio_t* sp;
49 int quote;
50 int* line;
51 } Splice_t;
52
53 /*
54 * the splicer
55 */
56
57 static int
spliceline(Sfio_t * s,int op,void * val,Sfdisc_t * ad)58 spliceline(Sfio_t* s, int op, void* val, Sfdisc_t* ad)
59 {
60 Splice_t* d = (Splice_t*)ad;
61 register char* b;
62 register int c;
63 register int n;
64 register int q;
65 register int j;
66 register char* e;
67 char* buf;
68
69 NoP(val);
70 switch (op)
71 {
72 case SF_CLOSING:
73 sfclose(d->sp);
74 return 0;
75 case SF_DPOP:
76 free(d);
77 return 0;
78 case SF_READ:
79 do
80 {
81 if (!(buf = sfgetr(d->sp, '\n', 0)) && !(buf = sfgetr(d->sp, '\n', -1)))
82 return 0;
83 n = sfvalue(d->sp);
84 q = d->quote;
85 j = 0;
86 (*d->line)++;
87 if (n > 1 && buf[n - 2] == '\\')
88 {
89 j = 1;
90 n -= 2;
91 if (q == '#')
92 {
93 n = 0;
94 continue;
95 }
96 }
97 else if (q == '#')
98 {
99 q = 0;
100 n = 0;
101 continue;
102 }
103 if (n > 0)
104 {
105 e = (b = buf) + n;
106 while (b < e)
107 {
108 if ((c = *b++) == '\\')
109 b++;
110 else if (c == q)
111 q = 0;
112 else if (!q)
113 {
114 if (c == '\'' || c == '"')
115 q = c;
116 else if (c == '#' && (b == (buf + 1) || (c = *(b - 2)) == ' ' || c == '\t'))
117 {
118 if (buf[n - 1] != '\n')
119 {
120 q = '#';
121 n = b - buf - 2;
122 }
123 else if (n = b - buf - 1)
124 buf[n - 1] = '\n';
125 break;
126 }
127 }
128 }
129 if (n > 0)
130 {
131 if (!j && buf[n - 1] != '\n' && (s->_flags & SF_STRING))
132 buf[n++] = '\n';
133 if (q && buf[n - 1] == '\n')
134 buf[n - 1] = '\r';
135 }
136 }
137 } while (n <= 0);
138 sfsetbuf(s, buf, n);
139 d->quote = q;
140 return 1;
141 default:
142 return 0;
143 }
144 }
145
146 /*
147 * open a stream to parse lines
148 *
149 * flags: 0 arg: open Sfio_t*
150 * flags: SF_READ arg: file name
151 * flags: SF_STRING arg: null terminated char*
152 *
153 * if line!=0 then it points to a line count that starts at 0
154 * and is incremented for each input line
155 */
156
157 Sfio_t*
tokline(const char * arg,int flags,int * line)158 tokline(const char* arg, int flags, int* line)
159 {
160 Sfio_t* f;
161 Sfio_t* s;
162 Splice_t* d;
163 char* p;
164 char* e;
165
166 static int hidden;
167
168 if (!(d = newof(0, Splice_t, 1, 0)))
169 return 0;
170 if (!(s = sfopen(NiL, NiL, "s")))
171 {
172 free(d);
173 return 0;
174 }
175 if (!(flags & (SF_STRING|SF_READ)))
176 f = (Sfio_t*)arg;
177 else if (!(f = sfopen(NiL, arg, (flags & SF_STRING) ? "s" : "r")))
178 {
179 free(d);
180 sfclose(s);
181 return 0;
182 }
183 else if ((p = sfreserve(f, 0, 0)) && sfvalue(f) > 11 && strmatch(p, "#!!! +([-0-9]) *([!\n]) !!!\n*") && (e = strchr(p, '\n')))
184 {
185 flags = strtol(p + 5, &p, 10);
186 error(flags, "%s:%-.*s", arg, e - p - 4, p);
187 }
188 d->disc.exceptf = spliceline;
189 d->sp = f;
190 *(d->line = line ? line : &hidden) = 0;
191 sfdisc(s, (Sfdisc_t*)d);
192 return s;
193 }
194