Sat Jun 27 19:18:58 2020 UTC ()
eval: Make radix optional even if minimum result width is specified.
This is what GNU m4 does too.


(uwe)
diff -r1.27 -r1.28 src/usr.bin/m4/eval.c

cvs diff -r1.27 -r1.28 src/usr.bin/m4/eval.c (switch to unified diff)

--- src/usr.bin/m4/eval.c 2018/07/30 22:58:09 1.27
+++ src/usr.bin/m4/eval.c 2020/06/27 19:18:58 1.28
@@ -1,1053 +1,1053 @@ @@ -1,1053 +1,1053 @@
1/* $OpenBSD: eval.c,v 1.66 2008/08/21 21:01:47 espie Exp $ */ 1/* $OpenBSD: eval.c,v 1.66 2008/08/21 21:01:47 espie Exp $ */
2/* $NetBSD: eval.c,v 1.27 2018/07/30 22:58:09 kre Exp $ */ 2/* $NetBSD: eval.c,v 1.28 2020/06/27 19:18:58 uwe Exp $ */
3 3
4/* 4/*
5 * Copyright (c) 1989, 1993 5 * Copyright (c) 1989, 1993
6 * The Regents of the University of California. All rights reserved. 6 * The Regents of the University of California. All rights reserved.
7 * 7 *
8 * This code is derived from software contributed to Berkeley by 8 * This code is derived from software contributed to Berkeley by
9 * Ozan Yigit at York University. 9 * Ozan Yigit at York University.
10 * 10 *
11 * Redistribution and use in source and binary forms, with or without 11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions 12 * modification, are permitted provided that the following conditions
13 * are met: 13 * are met:
14 * 1. Redistributions of source code must retain the above copyright 14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer. 15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright 16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the 17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution. 18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors 19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software 20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission. 21 * without specific prior written permission.
22 * 22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE. 33 * SUCH DAMAGE.
34 */ 34 */
35 35
36/* 36/*
37 * eval.c 37 * eval.c
38 * Facility: m4 macro processor 38 * Facility: m4 macro processor
39 * by: oz 39 * by: oz
40 */ 40 */
41#if HAVE_NBTOOL_CONFIG_H 41#if HAVE_NBTOOL_CONFIG_H
42#include "nbtool_config.h" 42#include "nbtool_config.h"
43#endif 43#endif
44#include <sys/cdefs.h> 44#include <sys/cdefs.h>
45__RCSID("$NetBSD: eval.c,v 1.27 2018/07/30 22:58:09 kre Exp $"); 45__RCSID("$NetBSD: eval.c,v 1.28 2020/06/27 19:18:58 uwe Exp $");
46 46
47#include <sys/types.h> 47#include <sys/types.h>
48#include <ctype.h> 48#include <ctype.h>
49#include <err.h> 49#include <err.h>
50#include <errno.h> 50#include <errno.h>
51#include <limits.h> 51#include <limits.h>
52#include <unistd.h> 52#include <unistd.h>
53#include <stdio.h> 53#include <stdio.h>
54#include <stdlib.h> 54#include <stdlib.h>
55#include <stddef.h> 55#include <stddef.h>
56#include <stdint.h> 56#include <stdint.h>
57#include <string.h> 57#include <string.h>
58#include <inttypes.h> 58#include <inttypes.h>
59#include <fcntl.h> 59#include <fcntl.h>
60#include "mdef.h" 60#include "mdef.h"
61#include "stdd.h" 61#include "stdd.h"
62#include "extern.h" 62#include "extern.h"
63#include "pathnames.h" 63#include "pathnames.h"
64 64
65static void dodefn(const char *); 65static void dodefn(const char *);
66static void dopushdef(const char *, const char *); 66static void dopushdef(const char *, const char *);
67static void dodump(const char *[], int); 67static void dodump(const char *[], int);
68static void dotrace(const char *[], int, int); 68static void dotrace(const char *[], int, int);
69static void doifelse(const char *[], int); 69static void doifelse(const char *[], int);
70static int doincl(const char *); 70static int doincl(const char *);
71static int dopaste(const char *); 71static int dopaste(const char *);
72static void dochq(const char *[], int); 72static void dochq(const char *[], int);
73static void dochc(const char *[], int); 73static void dochc(const char *[], int);
74static void dom4wrap(const char *); 74static void dom4wrap(const char *);
75static void dodiv(int); 75static void dodiv(int);
76static void doundiv(const char *[], int); 76static void doundiv(const char *[], int);
77static void dosub(const char *[], int); 77static void dosub(const char *[], int);
78static void map(char *, const char *, const char *, const char *); 78static void map(char *, const char *, const char *, const char *);
79static const char *handledash(char *, char *, const char *); 79static const char *handledash(char *, char *, const char *);
80static void expand_builtin(const char *[], int, int); 80static void expand_builtin(const char *[], int, int);
81static void expand_macro(const char *[], int); 81static void expand_macro(const char *[], int);
82static void dump_one_def(const char *, struct macro_definition *); 82static void dump_one_def(const char *, struct macro_definition *);
83 83
84unsigned long expansion_id; 84unsigned long expansion_id;
85 85
86/* 86/*
87 * eval - eval all macros and builtins calls 87 * eval - eval all macros and builtins calls
88 * argc - number of elements in argv. 88 * argc - number of elements in argv.
89 * argv - element vector : 89 * argv - element vector :
90 * argv[0] = definition of a user 90 * argv[0] = definition of a user
91 * macro or NULL if built-in. 91 * macro or NULL if built-in.
92 * argv[1] = name of the macro or 92 * argv[1] = name of the macro or
93 * built-in. 93 * built-in.
94 * argv[2] = parameters to user-defined 94 * argv[2] = parameters to user-defined
95 * . macro or built-in. 95 * . macro or built-in.
96 * . 96 * .
97 * 97 *
98 * A call in the form of macro-or-builtin() will result in: 98 * A call in the form of macro-or-builtin() will result in:
99 * argv[0] = nullstr 99 * argv[0] = nullstr
100 * argv[1] = macro-or-builtin 100 * argv[1] = macro-or-builtin
101 * argv[2] = nullstr 101 * argv[2] = nullstr
102 * 102 *
103 * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin 103 * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin
104 */ 104 */
105void 105void
106eval(const char *argv[], int argc, int td, int is_traced) 106eval(const char *argv[], int argc, int td, int is_traced)
107{ 107{
108 size_t mark = SIZE_MAX; 108 size_t mark = SIZE_MAX;
109 109
110 expansion_id++; 110 expansion_id++;
111 if (td & RECDEF)  111 if (td & RECDEF)
112 m4errx(1, "expanding recursive definition for %s.", argv[1]); 112 m4errx(1, "expanding recursive definition for %s.", argv[1]);
113 if (is_traced) 113 if (is_traced)
114 mark = trace(argv, argc, infile+ilevel); 114 mark = trace(argv, argc, infile+ilevel);
115 if (td == MACRTYPE) 115 if (td == MACRTYPE)
116 expand_macro(argv, argc); 116 expand_macro(argv, argc);
117 else 117 else
118 expand_builtin(argv, argc, td); 118 expand_builtin(argv, argc, td);
119 if (mark != SIZE_MAX) 119 if (mark != SIZE_MAX)
120 finish_trace(mark); 120 finish_trace(mark);
121} 121}
122 122
123/* 123/*
124 * expand_builtin - evaluate built-in macros. 124 * expand_builtin - evaluate built-in macros.
125 */ 125 */
126void 126void
127expand_builtin(const char *argv[], int argc, int td) 127expand_builtin(const char *argv[], int argc, int td)
128{ 128{
129 int c, n; 129 int c, n;
130 int ac; 130 int ac;
131 static int sysval = 0; 131 static int sysval = 0;
132 132
133#ifdef DEBUG 133#ifdef DEBUG
134 printf("argc = %d\n", argc); 134 printf("argc = %d\n", argc);
135 for (n = 0; n < argc; n++) 135 for (n = 0; n < argc; n++)
136 printf("argv[%d] = %s\n", n, argv[n]); 136 printf("argv[%d] = %s\n", n, argv[n]);
137 fflush(stdout); 137 fflush(stdout);
138#endif 138#endif
139 139
140 /* 140 /*
141 * if argc == 3 and argv[2] is null, then we 141 * if argc == 3 and argv[2] is null, then we
142 * have macro-or-builtin() type call. We adjust 142 * have macro-or-builtin() type call. We adjust
143 * argc to avoid further checking.. 143 * argc to avoid further checking..
144 */ 144 */
145 /* we keep the initial value for those built-ins that differentiate 145 /* we keep the initial value for those built-ins that differentiate
146 * between builtin() and builtin. 146 * between builtin() and builtin.
147 */ 147 */
148 ac = argc; 148 ac = argc;
149 149
150 if (argc == 3 && !*(argv[2]) && !mimic_gnu) 150 if (argc == 3 && !*(argv[2]) && !mimic_gnu)
151 argc--; 151 argc--;
152 152
153 switch (td & TYPEMASK) { 153 switch (td & TYPEMASK) {
154 154
155 case DEFITYPE: 155 case DEFITYPE:
156 if (argc > 2) 156 if (argc > 2)
157 dodefine(argv[2], (argc > 3) ? argv[3] : null); 157 dodefine(argv[2], (argc > 3) ? argv[3] : null);
158 break; 158 break;
159 159
160 case PUSDTYPE: 160 case PUSDTYPE:
161 if (argc > 2) 161 if (argc > 2)
162 dopushdef(argv[2], (argc > 3) ? argv[3] : null); 162 dopushdef(argv[2], (argc > 3) ? argv[3] : null);
163 break; 163 break;
164 164
165 case DUMPTYPE: 165 case DUMPTYPE:
166 dodump(argv, argc); 166 dodump(argv, argc);
167 break; 167 break;
168 168
169 case TRACEONTYPE: 169 case TRACEONTYPE:
170 dotrace(argv, argc, 1); 170 dotrace(argv, argc, 1);
171 break; 171 break;
172 172
173 case TRACEOFFTYPE: 173 case TRACEOFFTYPE:
174 dotrace(argv, argc, 0); 174 dotrace(argv, argc, 0);
175 break; 175 break;
176 176
177 case EXPRTYPE: 177 case EXPRTYPE:
178 /* 178 /*
179 * doexpr - evaluate arithmetic 179 * doexpr - evaluate arithmetic
180 * expression 180 * expression
181 */ 181 */
182 { 182 {
183 int base = 10; 183 int base = 10;
184 int maxdigits = 0; 184 int maxdigits = 0;
185 int e; 185 int e;
186 186
187 if (argc > 3) { 187 if (argc > 3 && *argv[3] != '\0') {
188 base = strtoi(argv[3], NULL, 0, 2, 36, &e); 188 base = strtoi(argv[3], NULL, 0, 2, 36, &e);
189 if (e) { 189 if (e) {
190 m4errx(1, "expr: base %s invalid.", argv[3]); 190 m4errx(1, "expr: base %s invalid.", argv[3]);
191 } 191 }
192 } 192 }
193 if (argc > 4) { 193 if (argc > 4) {
194 maxdigits = strtoi(argv[4], NULL, 0, 0, INT_MAX, &e); 194 maxdigits = strtoi(argv[4], NULL, 0, 0, INT_MAX, &e);
195 if (e) { 195 if (e) {
196 m4errx(1, "expr: maxdigits %s invalid.", argv[4]); 196 m4errx(1, "expr: maxdigits %s invalid.", argv[4]);
197 } 197 }
198 } 198 }
199 if (argc > 2) 199 if (argc > 2)
200 pbnumbase(expr(argv[2]), base, maxdigits); 200 pbnumbase(expr(argv[2]), base, maxdigits);
201 break; 201 break;
202 } 202 }
203 203
204 case IFELTYPE: 204 case IFELTYPE:
205 if (argc > 4) 205 if (argc > 4)
206 doifelse(argv, argc); 206 doifelse(argv, argc);
207 break; 207 break;
208 208
209 case IFDFTYPE: 209 case IFDFTYPE:
210 /* 210 /*
211 * doifdef - select one of two 211 * doifdef - select one of two
212 * alternatives based on the existence of 212 * alternatives based on the existence of
213 * another definition 213 * another definition
214 */ 214 */
215 if (argc > 3) { 215 if (argc > 3) {
216 if (lookup_macro_definition(argv[2]) != NULL) 216 if (lookup_macro_definition(argv[2]) != NULL)
217 pbstr(argv[3]); 217 pbstr(argv[3]);
218 else if (argc > 4) 218 else if (argc > 4)
219 pbstr(argv[4]); 219 pbstr(argv[4]);
220 } 220 }
221 break; 221 break;
222 222
223 case LENGTYPE: 223 case LENGTYPE:
224 /* 224 /*
225 * dolen - find the length of the 225 * dolen - find the length of the
226 * argument 226 * argument
227 */ 227 */
228 pbnum((argc > 2) ? strlen(argv[2]) : 0); 228 pbnum((argc > 2) ? strlen(argv[2]) : 0);
229 break; 229 break;
230 230
231 case INCRTYPE: 231 case INCRTYPE:
232 /* 232 /*
233 * doincr - increment the value of the 233 * doincr - increment the value of the
234 * argument 234 * argument
235 */ 235 */
236 if (argc > 2) 236 if (argc > 2)
237 pbnum(atoi(argv[2]) + 1); 237 pbnum(atoi(argv[2]) + 1);
238 break; 238 break;
239 239
240 case DECRTYPE: 240 case DECRTYPE:
241 /* 241 /*
242 * dodecr - decrement the value of the 242 * dodecr - decrement the value of the
243 * argument 243 * argument
244 */ 244 */
245 if (argc > 2) 245 if (argc > 2)
246 pbnum(atoi(argv[2]) - 1); 246 pbnum(atoi(argv[2]) - 1);
247 break; 247 break;
248 248
249 case SYSCTYPE: 249 case SYSCTYPE:
250 /* 250 /*
251 * dosys - execute system command 251 * dosys - execute system command
252 */ 252 */
253 if (argc > 2) { 253 if (argc > 2) {
254 fflush(stdout); 254 fflush(stdout);
255 sysval = system(argv[2]); 255 sysval = system(argv[2]);
256 } 256 }
257 break; 257 break;
258 258
259 case SYSVTYPE: 259 case SYSVTYPE:
260 /* 260 /*
261 * dosysval - return value of the last 261 * dosysval - return value of the last
262 * system call. 262 * system call.
263 *  263 *
264 */ 264 */
265 pbnum(sysval); 265 pbnum(sysval);
266 break; 266 break;
267 267
268 case ESYSCMDTYPE: 268 case ESYSCMDTYPE:
269 if (argc > 2) 269 if (argc > 2)
270 doesyscmd(argv[2]); 270 doesyscmd(argv[2]);
271 break; 271 break;
272 case INCLTYPE: 272 case INCLTYPE:
273 if (argc > 2) 273 if (argc > 2)
274 if (!doincl(argv[2])) 274 if (!doincl(argv[2]))
275 err(1, "%s at line %lu: include(%s)", 275 err(1, "%s at line %lu: include(%s)",
276 CURRENT_NAME, CURRENT_LINE, argv[2]); 276 CURRENT_NAME, CURRENT_LINE, argv[2]);
277 break; 277 break;
278 278
279 case SINCTYPE: 279 case SINCTYPE:
280 if (argc > 2) 280 if (argc > 2)
281 (void) doincl(argv[2]); 281 (void) doincl(argv[2]);
282 break; 282 break;
283#ifdef EXTENDED 283#ifdef EXTENDED
284 case PASTTYPE: 284 case PASTTYPE:
285 if (argc > 2) 285 if (argc > 2)
286 if (!dopaste(argv[2])) 286 if (!dopaste(argv[2]))
287 err(1, "%s at line %lu: paste(%s)",  287 err(1, "%s at line %lu: paste(%s)",
288 CURRENT_NAME, CURRENT_LINE, argv[2]); 288 CURRENT_NAME, CURRENT_LINE, argv[2]);
289 break; 289 break;
290 290
291 case SPASTYPE: 291 case SPASTYPE:
292 if (argc > 2) 292 if (argc > 2)
293 (void) dopaste(argv[2]); 293 (void) dopaste(argv[2]);
294 break; 294 break;
295 case FORMATTYPE: 295 case FORMATTYPE:
296 doformat(argv, argc); 296 doformat(argv, argc);
297 break; 297 break;
298#endif 298#endif
299 case CHNQTYPE: 299 case CHNQTYPE:
300 dochq(argv, ac); 300 dochq(argv, ac);
301 break; 301 break;
302 302
303 case CHNCTYPE: 303 case CHNCTYPE:
304 dochc(argv, argc); 304 dochc(argv, argc);
305 break; 305 break;
306 306
307 case SUBSTYPE: 307 case SUBSTYPE:
308 /* 308 /*
309 * dosub - select substring 309 * dosub - select substring
310 *  310 *
311 */ 311 */
312 if (argc > 3) 312 if (argc > 3)
313 dosub(argv, argc); 313 dosub(argv, argc);
314 break; 314 break;
315 315
316 case SHIFTYPE: 316 case SHIFTYPE:
317 /* 317 /*
318 * doshift - push back all arguments 318 * doshift - push back all arguments
319 * except the first one (i.e. skip 319 * except the first one (i.e. skip
320 * argv[2]) 320 * argv[2])
321 */ 321 */
322 if (argc > 3) { 322 if (argc > 3) {
323 for (n = argc - 1; n > 3; n--) { 323 for (n = argc - 1; n > 3; n--) {
324 pbstr(rquote); 324 pbstr(rquote);
325 pbstr(argv[n]); 325 pbstr(argv[n]);
326 pbstr(lquote); 326 pbstr(lquote);
327 pushback(COMMA); 327 pushback(COMMA);
328 } 328 }
329 pbstr(rquote); 329 pbstr(rquote);
330 pbstr(argv[3]); 330 pbstr(argv[3]);
331 pbstr(lquote); 331 pbstr(lquote);
332 } 332 }
333 break; 333 break;
334 334
335 case DIVRTYPE: 335 case DIVRTYPE:
336 if (argc > 2 && (n = atoi(argv[2])) != 0) 336 if (argc > 2 && (n = atoi(argv[2])) != 0)
337 dodiv(n); 337 dodiv(n);
338 else { 338 else {
339 active = stdout; 339 active = stdout;
340 oindex = 0; 340 oindex = 0;
341 } 341 }
342 break; 342 break;
343 343
344 case UNDVTYPE: 344 case UNDVTYPE:
345 doundiv(argv, argc); 345 doundiv(argv, argc);
346 break; 346 break;
347 347
348 case DIVNTYPE: 348 case DIVNTYPE:
349 /* 349 /*
350 * dodivnum - return the number of 350 * dodivnum - return the number of
351 * current output diversion 351 * current output diversion
352 */ 352 */
353 pbnum(oindex); 353 pbnum(oindex);
354 break; 354 break;
355 355
356 case UNDFTYPE: 356 case UNDFTYPE:
357 /* 357 /*
358 * doundefine - undefine a previously 358 * doundefine - undefine a previously
359 * defined macro(s) or m4 keyword(s). 359 * defined macro(s) or m4 keyword(s).
360 */ 360 */
361 if (argc > 2) 361 if (argc > 2)
362 for (n = 2; n < argc; n++) 362 for (n = 2; n < argc; n++)
363 macro_undefine(argv[n]); 363 macro_undefine(argv[n]);
364 break; 364 break;
365 365
366 case POPDTYPE: 366 case POPDTYPE:
367 /* 367 /*
368 * dopopdef - remove the topmost 368 * dopopdef - remove the topmost
369 * definitions of macro(s) or m4 369 * definitions of macro(s) or m4
370 * keyword(s). 370 * keyword(s).
371 */ 371 */
372 if (argc > 2) 372 if (argc > 2)
373 for (n = 2; n < argc; n++) 373 for (n = 2; n < argc; n++)
374 macro_popdef(argv[n]); 374 macro_popdef(argv[n]);
375 break; 375 break;
376 376
377 case MKTMTYPE: 377 case MKTMTYPE:
378 /* 378 /*
379 * dotemp - create a temporary file 379 * dotemp - create a temporary file
380 */ 380 */
381 if (argc > 2) { 381 if (argc > 2) {
382 int fd; 382 int fd;
383 char *temp; 383 char *temp;
384 384
385 temp = xstrdup(argv[2]); 385 temp = xstrdup(argv[2]);
386  386
387 fd = mkstemp(temp); 387 fd = mkstemp(temp);
388 if (fd == -1) 388 if (fd == -1)
389 err(1,  389 err(1,
390 "%s at line %lu: couldn't make temp file %s",  390 "%s at line %lu: couldn't make temp file %s",
391 CURRENT_NAME, CURRENT_LINE, argv[2]); 391 CURRENT_NAME, CURRENT_LINE, argv[2]);
392 close(fd); 392 close(fd);
393 pbstr(temp); 393 pbstr(temp);
394 free(temp); 394 free(temp);
395 } 395 }
396 break; 396 break;
397 397
398 case TRNLTYPE: 398 case TRNLTYPE:
399 /* 399 /*
400 * dotranslit - replace all characters in 400 * dotranslit - replace all characters in
401 * the source string that appears in the 401 * the source string that appears in the
402 * "from" string with the corresponding 402 * "from" string with the corresponding
403 * characters in the "to" string. 403 * characters in the "to" string.
404 */ 404 */
405 if (argc > 3) { 405 if (argc > 3) {
406 char *temp; 406 char *temp;
407 407
408 temp = xalloc(strlen(argv[2])+1, NULL); 408 temp = xalloc(strlen(argv[2])+1, NULL);
409 if (argc > 4) 409 if (argc > 4)
410 map(temp, argv[2], argv[3], argv[4]); 410 map(temp, argv[2], argv[3], argv[4]);
411 else 411 else
412 map(temp, argv[2], argv[3], null); 412 map(temp, argv[2], argv[3], null);
413 pbstr(temp); 413 pbstr(temp);
414 free(temp); 414 free(temp);
415 } else if (argc > 2) 415 } else if (argc > 2)
416 pbstr(argv[2]); 416 pbstr(argv[2]);
417 break; 417 break;
418 418
419 case INDXTYPE: 419 case INDXTYPE:
420 /* 420 /*
421 * doindex - find the index of the second 421 * doindex - find the index of the second
422 * argument string in the first argument 422 * argument string in the first argument
423 * string. -1 if not present. 423 * string. -1 if not present.
424 */ 424 */
425 pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1); 425 pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
426 break; 426 break;
427 427
428 case ERRPTYPE: 428 case ERRPTYPE:
429 /* 429 /*
430 * doerrp - print the arguments to stderr 430 * doerrp - print the arguments to stderr
431 * file 431 * file
432 */ 432 */
433 if (argc > 2) { 433 if (argc > 2) {
434 for (n = 2; n < argc; n++) 434 for (n = 2; n < argc; n++)
435 fprintf(stderr, "%s%s", 435 fprintf(stderr, "%s%s",
436 mimic_gnu && n == 2 ? "" : " ", 436 mimic_gnu && n == 2 ? "" : " ",
437 argv[n]); 437 argv[n]);
438 if (!mimic_gnu) 438 if (!mimic_gnu)
439 fprintf(stderr, "\n"); 439 fprintf(stderr, "\n");
440 } 440 }
441 break; 441 break;
442 442
443 case DNLNTYPE: 443 case DNLNTYPE:
444 /* 444 /*
445 * dodnl - eat-up-to and including 445 * dodnl - eat-up-to and including
446 * newline 446 * newline
447 */ 447 */
448 while ((c = gpbc()) != '\n' && c != EOF) 448 while ((c = gpbc()) != '\n' && c != EOF)
449 ; 449 ;
450 break; 450 break;
451 451
452 case M4WRTYPE: 452 case M4WRTYPE:
453 /* 453 /*
454 * dom4wrap - set up for 454 * dom4wrap - set up for
455 * wrap-up/wind-down activity 455 * wrap-up/wind-down activity
456 */ 456 */
457 if (argc > 2) 457 if (argc > 2)
458 dom4wrap(argv[2]); 458 dom4wrap(argv[2]);
459 break; 459 break;
460 460
461 case EXITTYPE: 461 case EXITTYPE:
462 /* 462 /*
463 * doexit - immediate exit from m4. 463 * doexit - immediate exit from m4.
464 */ 464 */
465 killdiv(); 465 killdiv();
466 exit((argc > 2) ? atoi(argv[2]) : 0); 466 exit((argc > 2) ? atoi(argv[2]) : 0);
467 break; 467 break;
468 468
469 case DEFNTYPE: 469 case DEFNTYPE:
470 if (argc > 2) 470 if (argc > 2)
471 for (n = 2; n < argc; n++) 471 for (n = 2; n < argc; n++)
472 dodefn(argv[n]); 472 dodefn(argv[n]);
473 break; 473 break;
474 474
475 case INDIRTYPE: /* Indirect call */ 475 case INDIRTYPE: /* Indirect call */
476 if (argc > 2) 476 if (argc > 2)
477 doindir(argv, argc); 477 doindir(argv, argc);
478 break; 478 break;
479  479
480 case BUILTINTYPE: /* Builtins only */ 480 case BUILTINTYPE: /* Builtins only */
481 if (argc > 2) 481 if (argc > 2)
482 dobuiltin(argv, argc); 482 dobuiltin(argv, argc);
483 break; 483 break;
484 484
485 case PATSTYPE: 485 case PATSTYPE:
486 if (argc > 2) 486 if (argc > 2)
487 dopatsubst(argv, argc); 487 dopatsubst(argv, argc);
488 break; 488 break;
489 case REGEXPTYPE: 489 case REGEXPTYPE:
490 if (argc > 2) 490 if (argc > 2)
491 doregexp(argv, argc); 491 doregexp(argv, argc);
492 break; 492 break;
493 case LINETYPE: 493 case LINETYPE:
494 doprintlineno(infile+ilevel); 494 doprintlineno(infile+ilevel);
495 break; 495 break;
496 case FILENAMETYPE: 496 case FILENAMETYPE:
497 doprintfilename(infile+ilevel); 497 doprintfilename(infile+ilevel);
498 break; 498 break;
499 case SELFTYPE: 499 case SELFTYPE:
500 pbstr(rquote); 500 pbstr(rquote);
501 pbstr(argv[1]); 501 pbstr(argv[1]);
502 pbstr(lquote); 502 pbstr(lquote);
503 break; 503 break;
504 default: 504 default:
505 m4errx(1, "eval: major botch."); 505 m4errx(1, "eval: major botch.");
506 break; 506 break;
507 } 507 }
508} 508}
509 509
510/* 510/*
511 * expand_macro - user-defined macro expansion 511 * expand_macro - user-defined macro expansion
512 */ 512 */
513void 513void
514expand_macro(const char *argv[], int argc) 514expand_macro(const char *argv[], int argc)
515{ 515{
516 const char *t; 516 const char *t;
517 const char *p; 517 const char *p;
518 int n; 518 int n;
519 int argno; 519 int argno;
520 520
521 t = argv[0]; /* defn string as a whole */ 521 t = argv[0]; /* defn string as a whole */
522 p = t; 522 p = t;
523 while (*p) 523 while (*p)
524 p++; 524 p++;
525 p--; /* last character of defn */ 525 p--; /* last character of defn */
526 while (p > t) { 526 while (p > t) {
527 if (*(p - 1) != ARGFLAG) 527 if (*(p - 1) != ARGFLAG)
528 PUSHBACK(*p); 528 PUSHBACK(*p);
529 else { 529 else {
530 switch (*p) { 530 switch (*p) {
531 531
532 case '#': 532 case '#':
533 pbnum(argc - 2); 533 pbnum(argc - 2);
534 break; 534 break;
535 case '0': 535 case '0':
536 case '1': 536 case '1':
537 case '2': 537 case '2':
538 case '3': 538 case '3':
539 case '4': 539 case '4':
540 case '5': 540 case '5':
541 case '6': 541 case '6':
542 case '7': 542 case '7':
543 case '8': 543 case '8':
544 case '9': 544 case '9':
545 argno = *p - '0'; 545 argno = *p - '0';
546 if (mimic_gnu) { 546 if (mimic_gnu) {
547 const unsigned char *q = 547 const unsigned char *q =
548 (const unsigned char *)p; 548 (const unsigned char *)p;
549 while (isdigit(*++q)) { 549 while (isdigit(*++q)) {
550 bp--; 550 bp--;
551 argno = argno * 10 + *q - '0'; 551 argno = argno * 10 + *q - '0';
552 } 552 }
553 } 553 }
554 if (argno < argc - 1) 554 if (argno < argc - 1)
555 pbstr(argv[argno + 1]); 555 pbstr(argv[argno + 1]);
556 break; 556 break;
557 case '*': 557 case '*':
558 if (argc > 2) { 558 if (argc > 2) {
559 for (n = argc - 1; n > 2; n--) { 559 for (n = argc - 1; n > 2; n--) {
560 pbstr(argv[n]); 560 pbstr(argv[n]);
561 pushback(COMMA); 561 pushback(COMMA);
562 } 562 }
563 pbstr(argv[2]); 563 pbstr(argv[2]);
564 } 564 }
565 break; 565 break;
566 case '@': 566 case '@':
567 if (argc > 2) { 567 if (argc > 2) {
568 for (n = argc - 1; n > 2; n--) { 568 for (n = argc - 1; n > 2; n--) {
569 pbstr(rquote); 569 pbstr(rquote);
570 pbstr(argv[n]); 570 pbstr(argv[n]);
571 pbstr(lquote); 571 pbstr(lquote);
572 pushback(COMMA); 572 pushback(COMMA);
573 } 573 }
574 pbstr(rquote); 574 pbstr(rquote);
575 pbstr(argv[2]); 575 pbstr(argv[2]);
576 pbstr(lquote); 576 pbstr(lquote);
577 } 577 }
578 break; 578 break;
579 default: 579 default:
580 PUSHBACK(*p); 580 PUSHBACK(*p);
581 PUSHBACK('$'); 581 PUSHBACK('$');
582 break; 582 break;
583 } 583 }
584 p--; 584 p--;
585 } 585 }
586 p--; 586 p--;
587 } 587 }
588 if (p == t) /* do last character */ 588 if (p == t) /* do last character */
589 PUSHBACK(*p); 589 PUSHBACK(*p);
590} 590}
591 591
592 592
593/* 593/*
594 * dodefine - install definition in the table 594 * dodefine - install definition in the table
595 */ 595 */
596void 596void
597dodefine(const char *name, const char *defn) 597dodefine(const char *name, const char *defn)
598{ 598{
599 if (!*name && !mimic_gnu) 599 if (!*name && !mimic_gnu)
600 m4errx(1, "null definition."); 600 m4errx(1, "null definition.");
601 else  601 else
602 macro_define(name, defn); 602 macro_define(name, defn);
603} 603}
604 604
605/* 605/*
606 * dodefn - push back a quoted definition of 606 * dodefn - push back a quoted definition of
607 * the given name. 607 * the given name.
608 */ 608 */
609static void 609static void
610dodefn(const char *name) 610dodefn(const char *name)
611{ 611{
612 struct macro_definition *p; 612 struct macro_definition *p;
613 613
614 if ((p = lookup_macro_definition(name)) != NULL) { 614 if ((p = lookup_macro_definition(name)) != NULL) {
615 if ((p->type & TYPEMASK) == MACRTYPE) { 615 if ((p->type & TYPEMASK) == MACRTYPE) {
616 pbstr(rquote); 616 pbstr(rquote);
617 pbstr(p->defn); 617 pbstr(p->defn);
618 pbstr(lquote); 618 pbstr(lquote);
619 } else { 619 } else {
620 pbstr(p->defn); 620 pbstr(p->defn);
621 pbstr(BUILTIN_MARKER); 621 pbstr(BUILTIN_MARKER);
622 } 622 }
623 } 623 }
624} 624}
625 625
626/* 626/*
627 * dopushdef - install a definition in the hash table 627 * dopushdef - install a definition in the hash table
628 * without removing a previous definition. Since 628 * without removing a previous definition. Since
629 * each new entry is entered in *front* of the 629 * each new entry is entered in *front* of the
630 * hash bucket, it hides a previous definition from 630 * hash bucket, it hides a previous definition from
631 * lookup. 631 * lookup.
632 */ 632 */
633static void 633static void
634dopushdef(const char *name, const char *defn) 634dopushdef(const char *name, const char *defn)
635{ 635{
636 if (!*name && !mimic_gnu) 636 if (!*name && !mimic_gnu)
637 m4errx(1, "null definition."); 637 m4errx(1, "null definition.");
638 else 638 else
639 macro_pushdef(name, defn); 639 macro_pushdef(name, defn);
640} 640}
641 641
642/* 642/*
643 * dump_one_def - dump the specified definition. 643 * dump_one_def - dump the specified definition.
644 */ 644 */
645static void 645static void
646dump_one_def(const char *name, struct macro_definition *p) 646dump_one_def(const char *name, struct macro_definition *p)
647{ 647{
648 if (!traceout) 648 if (!traceout)
649 traceout = stderr; 649 traceout = stderr;
650 if (mimic_gnu) { 650 if (mimic_gnu) {
651 if ((p->type & TYPEMASK) == MACRTYPE) 651 if ((p->type & TYPEMASK) == MACRTYPE)
652 fprintf(traceout, "%s:\t%s\n", name, p->defn); 652 fprintf(traceout, "%s:\t%s\n", name, p->defn);
653 else { 653 else {
654 fprintf(traceout, "%s:\t<%s>\n", name, p->defn); 654 fprintf(traceout, "%s:\t<%s>\n", name, p->defn);
655 } 655 }
656 } else 656 } else
657 fprintf(traceout, "`%s'\t`%s'\n", name, p->defn); 657 fprintf(traceout, "`%s'\t`%s'\n", name, p->defn);
658} 658}
659 659
660/* 660/*
661 * dodumpdef - dump the specified definitions in the hash 661 * dodumpdef - dump the specified definitions in the hash
662 * table to stderr. If nothing is specified, the entire 662 * table to stderr. If nothing is specified, the entire
663 * hash table is dumped. 663 * hash table is dumped.
664 */ 664 */
665static void 665static void
666dodump(const char *argv[], int argc) 666dodump(const char *argv[], int argc)
667{ 667{
668 int n; 668 int n;
669 struct macro_definition *p; 669 struct macro_definition *p;
670 670
671 if (argc > 2) { 671 if (argc > 2) {
672 for (n = 2; n < argc; n++) 672 for (n = 2; n < argc; n++)
673 if ((p = lookup_macro_definition(argv[n])) != NULL) 673 if ((p = lookup_macro_definition(argv[n])) != NULL)
674 dump_one_def(argv[n], p); 674 dump_one_def(argv[n], p);
675 } else 675 } else
676 macro_for_all(dump_one_def); 676 macro_for_all(dump_one_def);
677} 677}
678 678
679/* 679/*
680 * dotrace - mark some macros as traced/untraced depending upon on. 680 * dotrace - mark some macros as traced/untraced depending upon on.
681 */ 681 */
682static void 682static void
683dotrace(const char *argv[], int argc, int on) 683dotrace(const char *argv[], int argc, int on)
684{ 684{
685 int n; 685 int n;
686 686
687 if (argc > 2) { 687 if (argc > 2) {
688 for (n = 2; n < argc; n++) 688 for (n = 2; n < argc; n++)
689 mark_traced(argv[n], on); 689 mark_traced(argv[n], on);
690 } else 690 } else
691 mark_traced(NULL, on); 691 mark_traced(NULL, on);
692} 692}
693 693
694/* 694/*
695 * doifelse - select one of two alternatives - loop. 695 * doifelse - select one of two alternatives - loop.
696 */ 696 */
697static void 697static void
698doifelse(const char *argv[], int argc) 698doifelse(const char *argv[], int argc)
699{ 699{
700 cycle { 700 cycle {
701 if (argc < 5) 701 if (argc < 5)
702 m4errx(1, "wrong number of args for ifelse"); 702 m4errx(1, "wrong number of args for ifelse");
703 if (STREQ(argv[2], argv[3])) 703 if (STREQ(argv[2], argv[3]))
704 pbstr(argv[4]); 704 pbstr(argv[4]);
705 else if (argc == 6) 705 else if (argc == 6)
706 pbstr(argv[5]); 706 pbstr(argv[5]);
707 else if (argc > 6) { 707 else if (argc > 6) {
708 argv += 3; 708 argv += 3;
709 argc -= 3; 709 argc -= 3;
710 continue; 710 continue;
711 } 711 }
712 break; 712 break;
713 } 713 }
714} 714}
715 715
716/* 716/*
717 * doinclude - include a given file. 717 * doinclude - include a given file.
718 */ 718 */
719static int 719static int
720doincl(const char *ifile) 720doincl(const char *ifile)
721{ 721{
722#ifndef REAL_FREEZE 722#ifndef REAL_FREEZE
723 if (thawing) 723 if (thawing)
724 return 1; 724 return 1;
725#endif 725#endif
726 if (ilevel + 1 == MAXINP) 726 if (ilevel + 1 == MAXINP)
727 m4errx(1, "too many include files."); 727 m4errx(1, "too many include files.");
728 if (fopen_trypath(infile+ilevel+1, ifile) != NULL) { 728 if (fopen_trypath(infile+ilevel+1, ifile) != NULL) {
729 ilevel++; 729 ilevel++;
730 bbase[ilevel] = bufbase = bp; 730 bbase[ilevel] = bufbase = bp;
731 return (1); 731 return (1);
732 } else 732 } else
733 return (0); 733 return (0);
734} 734}
735 735
736#ifdef EXTENDED 736#ifdef EXTENDED
737/* 737/*
738 * dopaste - include a given file without any 738 * dopaste - include a given file without any
739 * macro processing. 739 * macro processing.
740 */ 740 */
741static int 741static int
742dopaste(const char *pfile) 742dopaste(const char *pfile)
743{ 743{
744 FILE *pf; 744 FILE *pf;
745 int c; 745 int c;
746 746
747 if ((pf = fopen(pfile, "r")) != NULL) { 747 if ((pf = fopen(pfile, "r")) != NULL) {
748 if (synch_lines) 748 if (synch_lines)
749 fprintf(active, "#line 1 \"%s\"\n", pfile); 749 fprintf(active, "#line 1 \"%s\"\n", pfile);
750 while ((c = getc(pf)) != EOF) 750 while ((c = getc(pf)) != EOF)
751 putc(c, active); 751 putc(c, active);
752 (void) fclose(pf); 752 (void) fclose(pf);
753 emit_synchline(); 753 emit_synchline();
754 return (1); 754 return (1);
755 } else 755 } else
756 return (0); 756 return (0);
757} 757}
758#endif 758#endif
759 759
760/* 760/*
761 * dochq - change quote characters 761 * dochq - change quote characters
762 */ 762 */
763static void 763static void
764dochq(const char *argv[], int ac) 764dochq(const char *argv[], int ac)
765{ 765{
766 if (ac == 2) { 766 if (ac == 2) {
767 lquote[0] = LQUOTE; lquote[1] = EOS; 767 lquote[0] = LQUOTE; lquote[1] = EOS;
768 rquote[0] = RQUOTE; rquote[1] = EOS; 768 rquote[0] = RQUOTE; rquote[1] = EOS;
769 } else { 769 } else {
770 strlcpy(lquote, argv[2], sizeof(lquote)); 770 strlcpy(lquote, argv[2], sizeof(lquote));
771 if (ac > 3) { 771 if (ac > 3) {
772 strlcpy(rquote, argv[3], sizeof(rquote)); 772 strlcpy(rquote, argv[3], sizeof(rquote));
773 } else { 773 } else {
774 rquote[0] = ECOMMT; rquote[1] = EOS; 774 rquote[0] = ECOMMT; rquote[1] = EOS;
775 } 775 }
776 } 776 }
777} 777}
778 778
779/* 779/*
780 * dochc - change comment characters 780 * dochc - change comment characters
781 */ 781 */
782static void 782static void
783dochc(const char *argv[], int argc) 783dochc(const char *argv[], int argc)
784{ 784{
785/* XXX Note that there is no difference between no argument and a single 785/* XXX Note that there is no difference between no argument and a single
786 * empty argument. 786 * empty argument.
787 */ 787 */
788 if (argc == 2) { 788 if (argc == 2) {
789 scommt[0] = EOS; 789 scommt[0] = EOS;
790 ecommt[0] = EOS; 790 ecommt[0] = EOS;
791 } else { 791 } else {
792 strlcpy(scommt, argv[2], sizeof(scommt)); 792 strlcpy(scommt, argv[2], sizeof(scommt));
793 if (argc == 3) { 793 if (argc == 3) {
794 ecommt[0] = ECOMMT; ecommt[1] = EOS; 794 ecommt[0] = ECOMMT; ecommt[1] = EOS;
795 } else { 795 } else {
796 strlcpy(ecommt, argv[3], sizeof(ecommt)); 796 strlcpy(ecommt, argv[3], sizeof(ecommt));
797 } 797 }
798 } 798 }
799} 799}
800 800
801/* 801/*
802 * dom4wrap - expand text at EOF 802 * dom4wrap - expand text at EOF
803 */ 803 */
804static void 804static void
805dom4wrap(const char *text) 805dom4wrap(const char *text)
806{ 806{
807 if (wrapindex >= maxwraps) { 807 if (wrapindex >= maxwraps) {
808 if (maxwraps == 0) 808 if (maxwraps == 0)
809 maxwraps = 16; 809 maxwraps = 16;
810 else 810 else
811 maxwraps *= 2; 811 maxwraps *= 2;
812 m4wraps = xrealloc(m4wraps, maxwraps * sizeof(*m4wraps), 812 m4wraps = xrealloc(m4wraps, maxwraps * sizeof(*m4wraps),
813 "too many m4wraps"); 813 "too many m4wraps");
814 } 814 }
815 m4wraps[wrapindex++] = xstrdup(text); 815 m4wraps[wrapindex++] = xstrdup(text);
816} 816}
817 817
818/* 818/*
819 * dodivert - divert the output to a temporary file 819 * dodivert - divert the output to a temporary file
820 */ 820 */
821static void 821static void
822dodiv(int n) 822dodiv(int n)
823{ 823{
824 int fd; 824 int fd;
825 825
826 oindex = n; 826 oindex = n;
827 if (n >= maxout) { 827 if (n >= maxout) {
828 if (mimic_gnu) 828 if (mimic_gnu)
829 resizedivs(n + 10); 829 resizedivs(n + 10);
830 else 830 else
831 n = 0; /* bitbucket */ 831 n = 0; /* bitbucket */
832 } 832 }
833 833
834 if (n < 0) 834 if (n < 0)
835 n = 0; /* bitbucket */ 835 n = 0; /* bitbucket */
836 if (outfile[n] == NULL) { 836 if (outfile[n] == NULL) {
837 char fname[] = _PATH_DIVNAME; 837 char fname[] = _PATH_DIVNAME;
838 838
839 if ((fd = mkstemp(fname)) < 0 ||  839 if ((fd = mkstemp(fname)) < 0 ||
840 (outfile[n] = fdopen(fd, "w+")) == NULL) 840 (outfile[n] = fdopen(fd, "w+")) == NULL)
841 err(1, "%s: cannot divert", fname); 841 err(1, "%s: cannot divert", fname);
842 if (unlink(fname) == -1) 842 if (unlink(fname) == -1)
843 err(1, "%s: cannot unlink", fname); 843 err(1, "%s: cannot unlink", fname);
844 } 844 }
845 active = outfile[n]; 845 active = outfile[n];
846} 846}
847 847
848/* 848/*
849 * doundivert - undivert a specified output, or all 849 * doundivert - undivert a specified output, or all
850 * other outputs, in numerical order. 850 * other outputs, in numerical order.
851 */ 851 */
852static void 852static void
853doundiv(const char *argv[], int argc) 853doundiv(const char *argv[], int argc)
854{ 854{
855 int ind; 855 int ind;
856 int n; 856 int n;
857 857
858 if (argc > 2) { 858 if (argc > 2) {
859 for (ind = 2; ind < argc; ind++) { 859 for (ind = 2; ind < argc; ind++) {
860 int e; 860 int e;
861 n = strtoi(argv[ind], NULL, 0, 1, INT_MAX, &e); 861 n = strtoi(argv[ind], NULL, 0, 1, INT_MAX, &e);
862 if (e) { 862 if (e) {
863 if (errno == EINVAL && mimic_gnu) 863 if (errno == EINVAL && mimic_gnu)
864 getdivfile(argv[ind]); 864 getdivfile(argv[ind]);
865 } else { 865 } else {
866 if (n < maxout && outfile[n] != NULL) 866 if (n < maxout && outfile[n] != NULL)
867 getdiv(n); 867 getdiv(n);
868 } 868 }
869 } 869 }
870 } 870 }
871 else 871 else
872 for (n = 1; n < maxout; n++) 872 for (n = 1; n < maxout; n++)
873 if (outfile[n] != NULL) 873 if (outfile[n] != NULL)
874 getdiv(n); 874 getdiv(n);
875} 875}
876 876
877/* 877/*
878 * dosub - select substring 878 * dosub - select substring
879 */ 879 */
880static void 880static void
881dosub(const char *argv[], int argc) 881dosub(const char *argv[], int argc)
882{ 882{
883 const char *ap, *fc, *k; 883 const char *ap, *fc, *k;
884 int nc; 884 int nc;
885 885
886 ap = argv[2]; /* target string */ 886 ap = argv[2]; /* target string */
887#ifdef EXPR 887#ifdef EXPR
888 fc = ap + expr(argv[3]); /* first char */ 888 fc = ap + expr(argv[3]); /* first char */
889#else 889#else
890 fc = ap + atoi(argv[3]); /* first char */ 890 fc = ap + atoi(argv[3]); /* first char */
891#endif 891#endif
892 nc = strlen(fc); 892 nc = strlen(fc);
893 if (argc >= 5) 893 if (argc >= 5)
894#ifdef EXPR 894#ifdef EXPR
895 nc = min(nc, expr(argv[4])); 895 nc = min(nc, expr(argv[4]));
896#else 896#else
897 nc = min(nc, atoi(argv[4])); 897 nc = min(nc, atoi(argv[4]));
898#endif 898#endif
899 if (fc >= ap && fc < ap + strlen(ap)) 899 if (fc >= ap && fc < ap + strlen(ap))
900 for (k = fc + nc - 1; k >= fc; k--) 900 for (k = fc + nc - 1; k >= fc; k--)
901 pushback(*k); 901 pushback(*k);
902} 902}
903 903
904/* 904/*
905 * map: 905 * map:
906 * map every character of s1 that is specified in from 906 * map every character of s1 that is specified in from
907 * into s3 and replace in s. (source s1 remains untouched) 907 * into s3 and replace in s. (source s1 remains untouched)
908 * 908 *
909 * This is a standard implementation of map(s,from,to) function of ICON 909 * This is a standard implementation of map(s,from,to) function of ICON
910 * language. Within mapvec, we replace every character of "from" with 910 * language. Within mapvec, we replace every character of "from" with
911 * the corresponding character in "to". If "to" is shorter than "from", 911 * the corresponding character in "to". If "to" is shorter than "from",
912 * than the corresponding entries are null, which means that those 912 * than the corresponding entries are null, which means that those
913 * characters dissapear altogether. Furthermore, imagine 913 * characters dissapear altogether. Furthermore, imagine
914 * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case, 914 * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
915 * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s' 915 * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
916 * ultimately maps to `*'. In order to achieve this effect in an efficient 916 * ultimately maps to `*'. In order to achieve this effect in an efficient
917 * manner (i.e. without multiple passes over the destination string), we 917 * manner (i.e. without multiple passes over the destination string), we
918 * loop over mapvec, starting with the initial source character. if the 918 * loop over mapvec, starting with the initial source character. if the
919 * character value (dch) in this location is different than the source 919 * character value (dch) in this location is different than the source
920 * character (sch), sch becomes dch, once again to index into mapvec, until 920 * character (sch), sch becomes dch, once again to index into mapvec, until
921 * the character value stabilizes (i.e. sch = dch, in other words 921 * the character value stabilizes (i.e. sch = dch, in other words
922 * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary 922 * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
923 * character, it will stabilize, since mapvec[0] == 0 at all times. At the 923 * character, it will stabilize, since mapvec[0] == 0 at all times. At the
924 * end, we restore mapvec* back to normal where mapvec[n] == n for 924 * end, we restore mapvec* back to normal where mapvec[n] == n for
925 * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is 925 * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
926 * about 5 times faster than any algorithm that makes multiple passes over 926 * about 5 times faster than any algorithm that makes multiple passes over
927 * destination string. 927 * destination string.
928 */ 928 */
929static void 929static void
930map(char *dest, const char *src, const char *from, const char *to) 930map(char *dest, const char *src, const char *from, const char *to)
931{ 931{
932 const char *tmp; 932 const char *tmp;
933 unsigned char sch, dch; 933 unsigned char sch, dch;
934 unsigned char found[256]; 934 unsigned char found[256];
935 static char frombis[257]; 935 static char frombis[257];
936 static char tobis[257]; 936 static char tobis[257];
937 static unsigned char mapvec[256] = { 937 static unsigned char mapvec[256] = {
938 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 938 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
939 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 939 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
940 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 940 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
941 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 941 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
942 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 942 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
943 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 943 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
944 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 944 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
945 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 945 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
946 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 946 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
947 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 947 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
948 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 948 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
949 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 949 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
950 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 950 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
951 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 951 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
952 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 952 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
953 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 953 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
954 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 954 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
955 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 955 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
956 }; 956 };
957 957
958 if (*src) { 958 if (*src) {
959 if (mimic_gnu) { 959 if (mimic_gnu) {
960 /* 960 /*
961 * expand character ranges on the fly 961 * expand character ranges on the fly
962 */ 962 */
963 from = handledash(frombis, frombis + 256, from); 963 from = handledash(frombis, frombis + 256, from);
964 to = handledash(tobis, tobis + 256, to); 964 to = handledash(tobis, tobis + 256, to);
965 } 965 }
966 tmp = from; 966 tmp = from;
967 /* 967 /*
968 * create a mapping between "from" and 968 * create a mapping between "from" and
969 * "to" 969 * "to"
970 */ 970 */
971 memset(found, 0, sizeof(found)); 971 memset(found, 0, sizeof(found));
972 for (; (sch = (unsigned char)*from) != '\0'; from++) { 972 for (; (sch = (unsigned char)*from) != '\0'; from++) {
973 if (!mimic_gnu || !found[sch]) { 973 if (!mimic_gnu || !found[sch]) {
974 found[sch] = 1; 974 found[sch] = 1;
975 mapvec[sch] = *to; 975 mapvec[sch] = *to;
976 } 976 }
977 if (*to) 977 if (*to)
978 to++; 978 to++;
979 } 979 }
980 980
981 if (mimic_gnu) { 981 if (mimic_gnu) {
982 for (; (sch = (unsigned char)*src) != '\0'; src++) { 982 for (; (sch = (unsigned char)*src) != '\0'; src++) {
983 if (!found[sch]) 983 if (!found[sch])
984 *dest++ = sch; 984 *dest++ = sch;
985 else if ((dch = mapvec[sch]) != '\0') 985 else if ((dch = mapvec[sch]) != '\0')
986 *dest++ = dch; 986 *dest++ = dch;
987 } 987 }
988 } else { 988 } else {
989 while (*src) { 989 while (*src) {
990 sch = (unsigned char)(*src++); 990 sch = (unsigned char)(*src++);
991 dch = mapvec[sch]; 991 dch = mapvec[sch];
992 while (dch != sch) { 992 while (dch != sch) {
993 sch = dch; 993 sch = dch;
994 dch = mapvec[sch]; 994 dch = mapvec[sch];
995 } 995 }
996 if ((*dest = (char)dch)) 996 if ((*dest = (char)dch))
997 dest++; 997 dest++;
998 } 998 }
999 } 999 }
1000 /* 1000 /*
1001 * restore all the changed characters 1001 * restore all the changed characters
1002 */ 1002 */
1003 while (*tmp) { 1003 while (*tmp) {
1004 mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp); 1004 mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp);
1005 tmp++; 1005 tmp++;
1006 } 1006 }
1007 } 1007 }
1008 *dest = '\0'; 1008 *dest = '\0';
1009} 1009}
1010 1010
1011 1011
1012/* 1012/*
1013 * handledash: 1013 * handledash:
1014 * use buffer to copy the src string, expanding character ranges 1014 * use buffer to copy the src string, expanding character ranges
1015 * on the way. 1015 * on the way.
1016 */ 1016 */
1017static const char * 1017static const char *
1018handledash(char *buffer, char *end, const char *src) 1018handledash(char *buffer, char *end, const char *src)
1019{ 1019{
1020 char *p; 1020 char *p;
1021  1021
1022 p = buffer; 1022 p = buffer;
1023 while(*src) { 1023 while(*src) {
1024 if (src[1] == '-' && src[2]) { 1024 if (src[1] == '-' && src[2]) {
1025 unsigned char i; 1025 unsigned char i;
1026 if ((unsigned char)src[0] <= (unsigned char)src[2]) { 1026 if ((unsigned char)src[0] <= (unsigned char)src[2]) {
1027 for (i = (unsigned char)src[0];  1027 for (i = (unsigned char)src[0];
1028 i <= (unsigned char)src[2]; i++) { 1028 i <= (unsigned char)src[2]; i++) {
1029 *p++ = i; 1029 *p++ = i;
1030 if (p == end) { 1030 if (p == end) {
1031 *p = '\0'; 1031 *p = '\0';
1032 return buffer; 1032 return buffer;
1033 } 1033 }
1034 } 1034 }
1035 } else { 1035 } else {
1036 for (i = (unsigned char)src[0];  1036 for (i = (unsigned char)src[0];
1037 i >= (unsigned char)src[2]; i--) { 1037 i >= (unsigned char)src[2]; i--) {
1038 *p++ = i; 1038 *p++ = i;
1039 if (p == end) { 1039 if (p == end) {
1040 *p = '\0'; 1040 *p = '\0';
1041 return buffer; 1041 return buffer;
1042 } 1042 }
1043 } 1043 }
1044 } 1044 }
1045 src += 3; 1045 src += 3;
1046 } else 1046 } else
1047 *p++ = *src++; 1047 *p++ = *src++;
1048 if (p == end) 1048 if (p == end)
1049 break; 1049 break;
1050 } 1050 }
1051 *p = '\0'; 1051 *p = '\0';
1052 return buffer; 1052 return buffer;
1053} 1053}