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