misc.c revision 1.2 1 1.2 glass /* File : misc.c
2 1.2 glass Author : Ozan Yigit
3 1.2 glass Updated: 26-Mar-1993
4 1.2 glass Purpose: Miscellaneous support code for PD M4.
5 1.2 glass */
6 1.2 glass
7 1.1 cgd #include "mdef.h"
8 1.2 glass #include "extr.h"
9 1.2 glass #include "ourlims.h"
10 1.2 glass
11 1.2 glass #ifdef DUFFCP
12 1.2 glass
13 1.2 glass /* This version of the ANSI standard function memcpy()
14 1.2 glass uses Duff's Device (tm Tom Duff) to unroll the copying loop:
15 1.2 glass while (count-- > 0) *to++ = *from++;
16 1.2 glass */
17 1.2 glass void memcpy(to, from, count)
18 1.2 glass register char *from, *to;
19 1.2 glass register int count;
20 1.2 glass {
21 1.2 glass if (count > 0) {
22 1.2 glass register int loops = (count+8-1) >> 3; /* div 8 round up */
23 1.2 glass
24 1.2 glass switch (count & (8-1)) { /* mod 8 */
25 1.2 glass case 0: do { *to++ = *from++;
26 1.2 glass case 7: *to++ = *from++;
27 1.2 glass case 6: *to++ = *from++;
28 1.2 glass case 5: *to++ = *from++;
29 1.2 glass case 4: *to++ = *from++;
30 1.2 glass case 3: *to++ = *from++;
31 1.2 glass case 2: *to++ = *from++;
32 1.2 glass case 1: *to++ = *from++;
33 1.2 glass } while (--loops > 0);
34 1.2 glass }
35 1.2 glass }
36 1.2 glass }
37 1.2 glass
38 1.2 glass #endif
39 1.2 glass
40 1.2 glass
41 1.2 glass /* strsave(s)
42 1.2 glass return a new malloc()ed copy of s -- same as V.3's strdup().
43 1.2 glass */
44 1.2 glass char *strsave(s)
45 1.2 glass char *s;
46 1.2 glass {
47 1.2 glass register int n = strlen(s)+1;
48 1.2 glass char *p = malloc(n);
49 1.2 glass
50 1.2 glass if (p) memcpy(p, s, n);
51 1.2 glass return p;
52 1.2 glass }
53 1.2 glass
54 1.2 glass
55 1.2 glass /* indx(s1, s2)
56 1.2 glass if s1 can be decomposed as alpha || s2 || omega, return the length
57 1.2 glass of the shortest such alpha, otherwise return -1.
58 1.2 glass */
59 1.2 glass int indx(s1, s2)
60 1.2 glass char *s1;
61 1.2 glass char *s2;
62 1.2 glass {
63 1.2 glass register char *t;
64 1.2 glass register char *m;
65 1.2 glass register char *p;
66 1.2 glass
67 1.2 glass for (p = s1; *p; p++) {
68 1.2 glass for (t = p, m = s2; *m && *m == *t; m++, t++);
69 1.2 glass if (!*m) return p-s1;
70 1.2 glass }
71 1.2 glass return -1;
72 1.2 glass }
73 1.2 glass
74 1.2 glass
75 1.2 glass char pbmsg[] = "m4: too many characters pushed back";
76 1.2 glass
77 1.2 glass /* Xputback(c)
78 1.2 glass push character c back onto the input stream.
79 1.2 glass This is now macro putback() in misc.h
80 1.2 glass */
81 1.2 glass void Xputback(c)
82 1.2 glass char c;
83 1.2 glass {
84 1.2 glass if (bp < endpbb) *bp++ = c; else error(pbmsg);
85 1.2 glass }
86 1.2 glass
87 1.2 glass
88 1.2 glass /* pbstr(s)
89 1.2 glass push string s back onto the input stream.
90 1.2 glass putback() has been unfolded here to improve performance.
91 1.2 glass Example:
92 1.2 glass s = <ABC>
93 1.2 glass bp = <more stuff>
94 1.2 glass After the call:
95 1.2 glass bp = <more stuffCBA>
96 1.2 glass It would be more efficient if we ran the pushback buffer in the
97 1.2 glass opposite direction
98 1.2 glass */
99 1.2 glass void pbstr(s)
100 1.2 glass register char *s;
101 1.2 glass {
102 1.2 glass register char *es;
103 1.2 glass register char *zp;
104 1.2 glass
105 1.2 glass zp = bp;
106 1.2 glass for (es = s; *es; ) es++; /* now es points to terminating NUL */
107 1.2 glass bp += es-s; /* advance bp as far as it should go */
108 1.2 glass if (bp >= endpbb) error("m4: too many characters to push back");
109 1.2 glass while (es > s) *zp++ = *--es;
110 1.2 glass }
111 1.2 glass
112 1.2 glass
113 1.2 glass /* pbqtd(s)
114 1.2 glass pushes string s back "quoted", doing whatever has to be done to it to
115 1.2 glass make sure that the result will evaluate to the original value. As it
116 1.2 glass happens, we have only to add lquote and rquote.
117 1.2 glass */
118 1.2 glass void pbqtd(s)
119 1.2 glass register char *s;
120 1.2 glass {
121 1.2 glass register char *es;
122 1.1 cgd register char *zp;
123 1.1 cgd
124 1.1 cgd zp = bp;
125 1.2 glass for (es = s; *es; ) es++; /* now es points to terminating NUL */
126 1.2 glass bp += 2+es-s; /* advance bp as far as it should go */
127 1.2 glass if (bp >= endpbb) error("m4: too many characters to push back");
128 1.2 glass *zp++ = rquote;
129 1.2 glass while (es > s) *zp++ = *--es;
130 1.2 glass *zp++ = lquote;
131 1.2 glass }
132 1.2 glass
133 1.2 glass
134 1.2 glass /* pbnum(n)
135 1.2 glass convert a number to a (decimal) string and push it back.
136 1.2 glass The original definition did not work for MININT; this does.
137 1.2 glass */
138 1.2 glass void pbnum(n)
139 1.2 glass int n;
140 1.2 glass {
141 1.2 glass register int num;
142 1.2 glass
143 1.2 glass num = n > 0 ? -n : n; /* MININT <= num <= 0 */
144 1.2 glass do {
145 1.2 glass putback('0' - (num % 10));
146 1.2 glass } while ((num /= 10) < 0);
147 1.2 glass if (n < 0) putback('-');
148 1.2 glass }
149 1.2 glass
150 1.2 glass
151 1.2 glass /* pbrad(n, r, m)
152 1.2 glass converts a number n to base r ([-36..-2] U [2..36]), with at least
153 1.2 glass m digits. If r == 10 and m == 1, this is exactly the same as pbnum.
154 1.2 glass However, this uses the function int2str() from R.A.O'Keefe's public
155 1.2 glass domain string library, and puts the results of that back.
156 1.2 glass The Unix System V Release 3 version of m4 accepts radix 1;
157 1.2 glass THIS VERSION OF M4 DOES NOT ACCEPT RADIX 1 OR -1,
158 1.2 glass nor do we accept radix < -36 or radix > 36. At the moment such bad
159 1.2 glass radices quietly produce nothing. The V.3 treatment of radix 1 is
160 1.2 glass push back abs(n) "1"s, then
161 1.2 glass if n < 0, push back one "-".
162 1.2 glass Until I come across something which uses it, I can't bring myself to
163 1.2 glass implement this.
164 1.2 glass
165 1.2 glass I have, however, found a use for radix 0. Unsurprisingly, it is
166 1.2 glass related to radix 0 in Edinburgh Prolog.
167 1.2 glass eval('c1c2...cn', 0, m)
168 1.2 glass pushes back max(m-n,0) blanks and the characters c1...cn. This can
169 1.2 glass adjust to any byte size as long as UCHAR_MAX = (1 << CHAR_BIT) - 1.
170 1.2 glass In particular, eval(c, 0) where 0 < c <= UCHAR_MAX, pushes back the
171 1.2 glass character with code c. Note that this has to agree with eval(); so
172 1.2 glass both of them have to use the same byte ordering.
173 1.2 glass */
174 1.2 glass void pbrad(n, r, m)
175 1.2 glass long int n;
176 1.2 glass int r, m;
177 1.2 glass {
178 1.2 glass char buffer[34];
179 1.2 glass char *p;
180 1.2 glass int L;
181 1.1 cgd
182 1.2 glass if (r == 0) {
183 1.2 glass unsigned long int x = (unsigned long)n;
184 1.2 glass int n;
185 1.2 glass
186 1.2 glass for (n = 0; x; x >>= CHAR_BIT, n++) buffer[n] = x & UCHAR_MAX;
187 1.2 glass for (L = n; --L >= 0; ) putback(buffer[L]);
188 1.2 glass for (L = m-n; --L >= 0; ) putback(' ');
189 1.2 glass return;
190 1.2 glass }
191 1.2 glass L = m - (int2str(p = buffer, -r, n)-buffer);
192 1.2 glass if (buffer[0] == '-') L++, p++;
193 1.2 glass if (L > 0) {
194 1.2 glass pbstr(p);
195 1.2 glass while (--L >= 0) putback('0');
196 1.2 glass if (p != buffer) putback('-');
197 1.2 glass } else {
198 1.2 glass pbstr(buffer);
199 1.2 glass }
200 1.2 glass }
201 1.2 glass
202 1.2 glass
203 1.2 glass char csmsg[] = "m4: string space overflow";
204 1.2 glass
205 1.2 glass /* chrsave(c)
206 1.2 glass put the character c in the string space.
207 1.2 glass */
208 1.2 glass void Xchrsave(c)
209 1.2 glass char c;
210 1.2 glass {
211 1.2 glass #if 0
212 1.2 glass if (sp < 0) putc(c, active); else
213 1.2 glass #endif
214 1.2 glass if (ep < endest) *ep++ = c; else
215 1.2 glass error(csmsg);
216 1.2 glass }
217 1.2 glass
218 1.2 glass
219 1.2 glass /* getdiv(ind)
220 1.2 glass read in a diversion file and then delete it.
221 1.2 glass */
222 1.2 glass void getdiv(ind)
223 1.2 glass int ind;
224 1.2 glass {
225 1.2 glass register int c;
226 1.2 glass register FILE *dfil;
227 1.2 glass register FILE *afil;
228 1.2 glass
229 1.2 glass afil = active;
230 1.2 glass if (outfile[ind] == afil)
231 1.2 glass error("m4: undivert: diversion still active.");
232 1.2 glass (void) fclose(outfile[ind]);
233 1.2 glass outfile[ind] = NULL;
234 1.2 glass m4temp[UNIQUE] = '0' + ind;
235 1.2 glass if ((dfil = fopen(m4temp, "r")) == NULL)
236 1.2 glass error("m4: cannot undivert.");
237 1.2 glass while ((c = getc(dfil)) != EOF) putc(c, afil);
238 1.2 glass (void) fclose(dfil);
239 1.2 glass
240 1.2 glass #if vms
241 1.2 glass if (remove(m4temp)) error("m4: cannot unlink.");
242 1.2 glass #else
243 1.2 glass if (unlink(m4temp) == -1) error("m4: cannot unlink.");
244 1.2 glass #endif
245 1.2 glass }
246 1.2 glass
247 1.2 glass
248 1.2 glass /* killdiv()
249 1.2 glass delete all the diversion files which have been created.
250 1.2 glass */
251 1.2 glass void killdiv()
252 1.2 glass {
253 1.2 glass register int n;
254 1.2 glass
255 1.2 glass for (n = 0; n < MAXOUT; n++) {
256 1.2 glass if (outfile[n] != NULL) {
257 1.2 glass (void) fclose(outfile[n]);
258 1.2 glass m4temp[UNIQUE] = '0' + n;
259 1.2 glass #if unix
260 1.2 glass (void) unlink(m4temp);
261 1.2 glass #else
262 1.2 glass (void) remove(m4temp);
263 1.2 glass #endif
264 1.2 glass }
265 1.2 glass }
266 1.2 glass }
267 1.2 glass
268 1.2 glass
269 1.2 glass /* error(s)
270 1.2 glass close all files, report a fatal error, and quit, letting the caller know.
271 1.2 glass */
272 1.2 glass void error(s)
273 1.2 glass char *s;
274 1.2 glass {
275 1.2 glass killdiv();
276 1.2 glass fprintf(stderr, "%s\n", s);
277 1.2 glass exit(1);
278 1.2 glass }
279 1.2 glass
280 1.2 glass
281 1.2 glass /* Interrupt handling
282 1.2 glass */
283 1.1 cgd static char *msg = "\ninterrupted.";
284 1.2 glass
285 1.2 glass #ifdef __STDC__
286 1.2 glass void onintr(int signo)
287 1.2 glass #else
288 1.2 glass onintr()
289 1.2 glass #endif
290 1.2 glass {
291 1.2 glass error(msg);
292 1.2 glass }
293 1.2 glass
294 1.2 glass
295 1.2 glass void usage()
296 1.2 glass {
297 1.2 glass fprintf(stderr, "Usage: m4 [-e] [-[BHST]int] [-Dname[=val]] [-Uname]\n");
298 1.2 glass exit(1);
299 1.2 glass }
300 1.2 glass
301 1.2 glass #ifdef GETOPT
302 1.2 glass /* Henry Spencer's getopt() - get option letter from argv */
303 1.2 glass
304 1.2 glass char *optarg; /* Global argument pointer. */
305 1.2 glass int optind = 0; /* Global argv index. */
306 1.2 glass
307 1.2 glass static char *scan = NULL; /* Private scan pointer. */
308 1.2 glass
309 1.2 glass #ifndef __STDC__
310 1.2 glass extern char *index();
311 1.2 glass #define strchr index
312 1.2 glass #endif
313 1.2 glass
314 1.2 glass int getopt(argc, argv, optstring)
315 1.2 glass int argc;
316 1.2 glass char **argv;
317 1.2 glass char *optstring;
318 1.2 glass {
319 1.2 glass register char c;
320 1.2 glass register char *place;
321 1.2 glass
322 1.2 glass optarg = NULL;
323 1.2 glass
324 1.2 glass if (scan == NULL || *scan == '\0') {
325 1.2 glass if (optind == 0) optind++;
326 1.2 glass if (optind >= argc
327 1.2 glass || argv[optind][0] != '-'
328 1.2 glass || argv[optind][1] == '\0')
329 1.2 glass return EOF;
330 1.2 glass if (strcmp(argv[optind], "--") == 0) {
331 1.2 glass optind++;
332 1.2 glass return EOF;
333 1.2 glass }
334 1.2 glass scan = argv[optind]+1;
335 1.2 glass optind++;
336 1.2 glass }
337 1.2 glass c = *scan++;
338 1.2 glass place = strchr(optstring, c);
339 1.2 glass
340 1.2 glass if (place == NULL || c == ':') {
341 1.2 glass fprintf(stderr, "%s: unknown option -%c\n", argv[0], c);
342 1.2 glass return '?';
343 1.2 glass }
344 1.2 glass place++;
345 1.2 glass if (*place == ':') {
346 1.2 glass if (*scan != '\0') {
347 1.2 glass optarg = scan;
348 1.2 glass scan = NULL;
349 1.2 glass } else {
350 1.2 glass optarg = argv[optind];
351 1.2 glass optind++;
352 1.2 glass }
353 1.2 glass }
354 1.2 glass return c;
355 1.2 glass }
356 1.2 glass #endif
357 1.2 glass
358