|
1 #ifndef __SYMBIAN32__ |
|
2 // zutil.c - misc utilities |
|
3 // |
|
4 // © Portions Copyright (c) Symbian Software Ltd 2007. All rights reserved. |
|
5 // |
|
6 /* |
|
7 * This file is part of zsh, the Z shell. |
|
8 * |
|
9 * Copyright (c) 1999 Sven Wischnowsky |
|
10 * All rights reserved. |
|
11 * |
|
12 * Permission is hereby granted, without written agreement and without |
|
13 * license or royalty fees, to use, copy, modify, and distribute this |
|
14 * software and to distribute modified versions of this software for any |
|
15 * purpose, provided that the above copyright notice and the following |
|
16 * two paragraphs appear in all copies of this software. |
|
17 * |
|
18 * In no event shall Sven Wischnowsky or the Zsh Development Group be liable |
|
19 * to any party for direct, indirect, special, incidental, or consequential |
|
20 * damages arising out of the use of this software and its documentation, |
|
21 * even if Sven Wischnowsky and the Zsh Development Group have been advised of |
|
22 * the possibility of such damage. |
|
23 * |
|
24 * Sven Wischnowsky and the Zsh Development Group specifically disclaim any |
|
25 * warranties, including, but not limited to, the implied warranties of |
|
26 * merchantability and fitness for a particular purpose. The software |
|
27 * provided hereunder is on an "as is" basis, and Sven Wischnowsky and the |
|
28 * Zsh Development Group have no obligation to provide maintenance, |
|
29 * support, updates, enhancements, or modifications. |
|
30 * |
|
31 */ |
|
32 #include "zutil.mdh" |
|
33 #include "zutil.pro" |
|
34 |
|
35 #ifdef __SYMBIAN32__ |
|
36 #ifdef __WINSCW__ |
|
37 #pragma warn_unusedarg off |
|
38 #pragma warn_possunwant off |
|
39 #endif//__WINSCW__ |
|
40 #endif//__SYMBIAN32__ |
|
41 |
|
42 /* Style stuff. */ |
|
43 |
|
44 typedef struct stypat *Stypat; |
|
45 typedef struct style *Style; |
|
46 |
|
47 /* A pattern and the styles for it. */ |
|
48 |
|
49 struct style { |
|
50 Style next; /* next in stypat list */ |
|
51 Stypat pats; /* patterns */ |
|
52 char *name; |
|
53 }; |
|
54 |
|
55 struct stypat { |
|
56 Stypat next; |
|
57 char *pat; /* pattern string */ |
|
58 Patprog prog; /* compiled pattern */ |
|
59 int weight; /* how specific is the pattern? */ |
|
60 Eprog eval; /* eval-on-retrieve? */ |
|
61 char **vals; |
|
62 }; |
|
63 |
|
64 /* List of styles. */ |
|
65 |
|
66 static Style zstyles, zlstyles; |
|
67 |
|
68 /* Memory stuff. */ |
|
69 |
|
70 static void |
|
71 freestypat(Stypat p) |
|
72 { |
|
73 zsfree(p->pat); |
|
74 freepatprog(p->prog); |
|
75 if (p->vals) |
|
76 freearray(p->vals); |
|
77 if (p->eval) |
|
78 freeeprog(p->eval); |
|
79 zfree(p, sizeof(*p)); |
|
80 } |
|
81 |
|
82 static void |
|
83 freeallstyles(void) |
|
84 { |
|
85 Style s, sn; |
|
86 Stypat p, pn; |
|
87 |
|
88 for (s = zstyles; s; s = sn) { |
|
89 sn = s->next; |
|
90 for (p = s->pats; p; p = pn) { |
|
91 pn = p->next; |
|
92 freestypat(p); |
|
93 } |
|
94 zsfree(s->name); |
|
95 zfree(s, sizeof(*s)); |
|
96 } |
|
97 zstyles = zlstyles = NULL; |
|
98 } |
|
99 |
|
100 /* Get the style struct for a name. */ |
|
101 |
|
102 static Style |
|
103 getstyle(char *name) |
|
104 { |
|
105 Style s; |
|
106 |
|
107 for (s = zstyles; s; s = s->next) |
|
108 if (!strcmp(name, s->name)) |
|
109 return s; |
|
110 |
|
111 return NULL; |
|
112 } |
|
113 |
|
114 /* Store a value for a style. */ |
|
115 |
|
116 static int |
|
117 setstypat(Style s, char *pat, Patprog prog, char **vals, int eval) |
|
118 { |
|
119 int weight, tmp, first; |
|
120 char *str; |
|
121 Stypat p, q, qq; |
|
122 Eprog eprog = NULL; |
|
123 |
|
124 if (eval) { |
|
125 int ef = errflag; |
|
126 |
|
127 eprog = parse_string(zjoin(vals, ' ', 1)); |
|
128 errflag = ef; |
|
129 |
|
130 if (!eprog) |
|
131 { |
|
132 freepatprog(prog); |
|
133 return 1; |
|
134 } |
|
135 |
|
136 eprog = dupeprog(eprog, 0); |
|
137 } |
|
138 for (p = s->pats; p; p = p->next) |
|
139 if (!strcmp(pat, p->pat)) { |
|
140 |
|
141 /* Exists -> replace. */ |
|
142 |
|
143 if (p->vals) |
|
144 freearray(p->vals); |
|
145 if (p->eval) |
|
146 freeeprog(p->eval); |
|
147 p->vals = zarrdup(vals); |
|
148 p->eval = eprog; |
|
149 freepatprog(prog); |
|
150 |
|
151 return 0; |
|
152 } |
|
153 |
|
154 /* New pattern. */ |
|
155 |
|
156 p = (Stypat) zalloc(sizeof(*p)); |
|
157 p->pat = ztrdup(pat); |
|
158 p->prog = prog; |
|
159 p->vals = zarrdup(vals); |
|
160 p->eval = eprog; |
|
161 p->next = NULL; |
|
162 |
|
163 /* Calculate the weight. */ |
|
164 |
|
165 for (weight = 0, tmp = 2, first = 1, str = pat; *str; str++) { |
|
166 if (first && *str == '*' && (!str[1] || str[1] == ':')) { |
|
167 /* Only `*' in this component. */ |
|
168 tmp = 0; |
|
169 continue; |
|
170 } |
|
171 first = 0; |
|
172 |
|
173 if (*str == '(' || *str == '|' || *str == '*' || *str == '[' || |
|
174 *str == '<' || *str == '?' || *str == '#' || *str == '^') |
|
175 /* Is pattern. */ |
|
176 tmp = 1; |
|
177 |
|
178 if (*str == ':') { |
|
179 /* Yet another component. */ |
|
180 |
|
181 first = 1; |
|
182 weight += tmp; |
|
183 tmp = 2; |
|
184 } |
|
185 } |
|
186 p->weight = (weight += tmp); |
|
187 |
|
188 for (qq = NULL, q = s->pats; q && q->weight >= weight; |
|
189 qq = q, q = q->next); |
|
190 |
|
191 p->next = q; |
|
192 if (qq) |
|
193 qq->next = p; |
|
194 else |
|
195 s->pats = p; |
|
196 |
|
197 return 0; |
|
198 } |
|
199 |
|
200 /* Add a new style. */ |
|
201 |
|
202 static Style |
|
203 addstyle(char *name) |
|
204 { |
|
205 Style s; |
|
206 |
|
207 s = (Style) zalloc(sizeof(*s)); |
|
208 s->next = NULL; |
|
209 s->pats = NULL; |
|
210 s->name = ztrdup(name); |
|
211 |
|
212 if (zlstyles) |
|
213 zlstyles->next = s; |
|
214 else |
|
215 zstyles = s; |
|
216 zlstyles = s; |
|
217 |
|
218 return s; |
|
219 } |
|
220 |
|
221 static char ** |
|
222 evalstyle(Stypat p) |
|
223 { |
|
224 int ef = errflag; |
|
225 char **ret, *str; |
|
226 |
|
227 unsetparam("reply"); |
|
228 execode(p->eval, 1, 0); |
|
229 if (errflag) { |
|
230 errflag = ef; |
|
231 return NULL; |
|
232 } |
|
233 errflag = ef; |
|
234 |
|
235 queue_signals(); |
|
236 if ((ret = getaparam("reply"))) |
|
237 ret = arrdup(ret); |
|
238 else if ((str = getsparam("reply"))) { |
|
239 ret = (char **) hcalloc(2 * sizeof(char *)); |
|
240 ret[0] = dupstring(str); |
|
241 } |
|
242 unqueue_signals(); |
|
243 unsetparam("reply"); |
|
244 |
|
245 return ret; |
|
246 } |
|
247 |
|
248 /* Look up a style for a context pattern. This does the matching. */ |
|
249 |
|
250 static char ** |
|
251 lookupstyle(char *ctxt, char *style) |
|
252 { |
|
253 Style s; |
|
254 Stypat p; |
|
255 |
|
256 for (s = zstyles; s; s = s->next) |
|
257 if (!strcmp(s->name, style)) |
|
258 for (p = s->pats; p; p = p->next) |
|
259 if (pattry(p->prog, ctxt)) |
|
260 return (p->eval ? evalstyle(p) : p->vals); |
|
261 |
|
262 return NULL; |
|
263 } |
|
264 |
|
265 static int |
|
266 bin_zstyle(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) |
|
267 { |
|
268 int min, max, n, add = 0, list = 0, eval = 0; |
|
269 |
|
270 if (!args[0]) |
|
271 list = 1; |
|
272 else if (args[0][0] == '-') { |
|
273 char oc; |
|
274 |
|
275 if ((oc = args[0][1]) && oc != '-') { |
|
276 if (args[0][2]) { |
|
277 zwarnnam(nam, "invalid argument: %s", args[0], 0); |
|
278 return 1; |
|
279 } |
|
280 if (oc == 'L') |
|
281 list = 2; |
|
282 else if (oc == 'e') { |
|
283 eval = add = 1; |
|
284 args++; |
|
285 } |
|
286 } else { |
|
287 add = 1; |
|
288 args++; |
|
289 } |
|
290 } else |
|
291 add = 1; |
|
292 |
|
293 if (add) { |
|
294 Style s; |
|
295 Patprog prog; |
|
296 char *pat; |
|
297 |
|
298 if (arrlen(args) < 2) { |
|
299 zwarnnam(nam, "not enough arguments", NULL, 0); |
|
300 return 1; |
|
301 } |
|
302 pat = dupstring(args[0]); |
|
303 tokenize(pat); |
|
304 |
|
305 if (!(prog = patcompile(pat, PAT_ZDUP, NULL))) { |
|
306 zwarnnam(nam, "invalid pattern: %s", args[0], 0); |
|
307 return 1; |
|
308 } |
|
309 if (!(s = getstyle(args[1]))) |
|
310 s = addstyle(args[1]); |
|
311 return setstypat(s, args[0], prog, args + 2, eval); |
|
312 } |
|
313 if (list) { |
|
314 Style s; |
|
315 Stypat p; |
|
316 char **v; |
|
317 |
|
318 for (s = zstyles; s; s = s->next) { |
|
319 if (list == 1) { |
|
320 quotedzputs(s->name, stdout); |
|
321 putchar('\n'); |
|
322 } |
|
323 for (p = s->pats; p; p = p->next) { |
|
324 if (list == 1) |
|
325 printf("%s %s", (p->eval ? "(eval)" : " "), p->pat); |
|
326 else { |
|
327 printf("zstyle %s", (p->eval ? "-e " : "")); |
|
328 quotedzputs(p->pat, stdout); |
|
329 printf(" %s", s->name); |
|
330 } |
|
331 for (v = p->vals; *v; v++) { |
|
332 putchar(' '); |
|
333 quotedzputs(*v, stdout); |
|
334 } |
|
335 putchar('\n'); |
|
336 } |
|
337 } |
|
338 return 0; |
|
339 } |
|
340 switch (args[0][1]) { |
|
341 case 'd': min = 0; max = -1; break; |
|
342 case 's': min = 3; max = 4; break; |
|
343 case 'b': min = 3; max = 3; break; |
|
344 case 'a': min = 3; max = 3; break; |
|
345 case 't': min = 2; max = -1; break; |
|
346 case 'T': min = 2; max = -1; break; |
|
347 case 'm': min = 3; max = 3; break; |
|
348 case 'g': min = 1; max = 3; break; |
|
349 default: |
|
350 zwarnnam(nam, "invalid option: %s", args[0], 0); |
|
351 return 1; |
|
352 } |
|
353 n = arrlen(args) - 1; |
|
354 if (n < min) { |
|
355 zwarnnam(nam, "not enough arguments", NULL, 0); |
|
356 return 1; |
|
357 } else if (max >= 0 && n > max) { |
|
358 zwarnnam(nam, "too many arguments", NULL, 0); |
|
359 return 1; |
|
360 } |
|
361 switch (args[0][1]) { |
|
362 case 'd': |
|
363 { |
|
364 Style s; |
|
365 |
|
366 if (args[1]) { |
|
367 if (args[2]) { |
|
368 char *pat = args[1]; |
|
369 |
|
370 for (args += 2; *args; args++) { |
|
371 if ((s = getstyle(*args))) { |
|
372 Stypat p, q; |
|
373 |
|
374 for (q = NULL, p = s->pats; p; |
|
375 q = p, p = p->next) { |
|
376 if (!strcmp(p->pat, pat)) { |
|
377 if (q) |
|
378 q->next = p->next; |
|
379 else |
|
380 s->pats = p->next; |
|
381 freestypat(p); |
|
382 break; |
|
383 } |
|
384 } |
|
385 } |
|
386 } |
|
387 } else { |
|
388 Stypat p, q; |
|
389 |
|
390 for (s = zstyles; s; s = s->next) { |
|
391 for (q = NULL, p = s->pats; p; q = p, p = p->next) { |
|
392 if (!strcmp(p->pat, args[1])) { |
|
393 if (q) |
|
394 q->next = p->next; |
|
395 else |
|
396 s->pats = p->next; |
|
397 freestypat(p); |
|
398 break; |
|
399 } |
|
400 } |
|
401 } |
|
402 } |
|
403 } else |
|
404 freeallstyles(); |
|
405 } |
|
406 break; |
|
407 case 's': |
|
408 { |
|
409 char **vals, *ret; |
|
410 int val; |
|
411 |
|
412 if ((vals = lookupstyle(args[1], args[2])) && vals[0]) { |
|
413 ret = sepjoin(vals, (args[4] ? args[4] : " "), 0); |
|
414 val = 0; |
|
415 } else { |
|
416 ret = ztrdup(""); |
|
417 val = 1; |
|
418 } |
|
419 setsparam(args[3], ret); |
|
420 |
|
421 return val; |
|
422 } |
|
423 break; |
|
424 case 'b': |
|
425 { |
|
426 char **vals, *ret; |
|
427 int val; |
|
428 |
|
429 if ((vals = lookupstyle(args[1], args[2])) && |
|
430 vals[0] && !vals[1] && |
|
431 (!strcmp(vals[0], "yes") || |
|
432 !strcmp(vals[0], "true") || |
|
433 !strcmp(vals[0], "on") || |
|
434 !strcmp(vals[0], "1"))) { |
|
435 ret = "yes"; |
|
436 val = 0; |
|
437 } else { |
|
438 ret = "no"; |
|
439 val = 1; |
|
440 } |
|
441 setsparam(args[3], ztrdup(ret)); |
|
442 |
|
443 return val; |
|
444 } |
|
445 break; |
|
446 case 'a': |
|
447 { |
|
448 char **vals, **ret; |
|
449 int val; |
|
450 |
|
451 if ((vals = lookupstyle(args[1], args[2]))) { |
|
452 ret = zarrdup(vals); |
|
453 val = 0; |
|
454 } else { |
|
455 char *dummy = NULL; |
|
456 |
|
457 ret = zarrdup(&dummy); |
|
458 val = 1; |
|
459 } |
|
460 setaparam(args[3], ret); |
|
461 |
|
462 return val; |
|
463 } |
|
464 break; |
|
465 case 't': |
|
466 case 'T': |
|
467 { |
|
468 char **vals; |
|
469 |
|
470 if ((vals = lookupstyle(args[1], args[2])) && vals[0]) { |
|
471 if (args[3]) { |
|
472 char **ap = args + 3, **p; |
|
473 |
|
474 while (*ap) { |
|
475 p = vals; |
|
476 while (*p) |
|
477 if (!strcmp(*ap, *p++)) |
|
478 return 0; |
|
479 ap++; |
|
480 } |
|
481 return 1; |
|
482 } else |
|
483 return !(!strcmp(vals[0], "true") || |
|
484 !strcmp(vals[0], "yes") || |
|
485 !strcmp(vals[0], "on") || |
|
486 !strcmp(vals[0], "1")); |
|
487 } |
|
488 return (args[0][1] == 't' ? (vals ? 1 : 2) : 0); |
|
489 } |
|
490 break; |
|
491 case 'm': |
|
492 { |
|
493 char **vals; |
|
494 Patprog prog; |
|
495 |
|
496 tokenize(args[3]); |
|
497 |
|
498 if ((vals = lookupstyle(args[1], args[2])) && |
|
499 (prog = patcompile(args[3], PAT_STATIC, NULL))) { |
|
500 while (*vals) |
|
501 if (pattry(prog, *vals++)) |
|
502 return 0; |
|
503 } |
|
504 return 1; |
|
505 } |
|
506 break; |
|
507 case 'g': |
|
508 { |
|
509 LinkList l = newlinklist(); |
|
510 int ret = 1; |
|
511 Style s; |
|
512 Stypat p; |
|
513 |
|
514 if (args[2]) { |
|
515 if (args[3]) { |
|
516 if ((s = getstyle(args[3]))) { |
|
517 for (p = s->pats; p; p = p->next) { |
|
518 if (!strcmp(args[2], p->pat)) { |
|
519 char **v = p->vals; |
|
520 |
|
521 while (*v) |
|
522 addlinknode(l, *v++); |
|
523 |
|
524 ret = 0; |
|
525 break; |
|
526 } |
|
527 } |
|
528 } |
|
529 } else { |
|
530 for (s = zstyles; s; s = s->next) |
|
531 for (p = s->pats; p; p = p->next) |
|
532 if (!strcmp(args[2], p->pat)) { |
|
533 addlinknode(l, s->name); |
|
534 break; |
|
535 } |
|
536 ret = 0; |
|
537 } |
|
538 } else { |
|
539 LinkNode n; |
|
540 |
|
541 for (s = zstyles; s; s = s->next) |
|
542 for (p = s->pats; p; p = p->next) { |
|
543 for (n = firstnode(l); n; incnode(n)) |
|
544 if (!strcmp(p->pat, (char *) getdata(n))) |
|
545 break; |
|
546 if (!n) |
|
547 addlinknode(l, p->pat); |
|
548 } |
|
549 ret = 0; |
|
550 } |
|
551 set_list_array(args[1], l); |
|
552 |
|
553 return ret; |
|
554 } |
|
555 } |
|
556 return 0; |
|
557 } |
|
558 |
|
559 /* Format stuff. */ |
|
560 |
|
561 /* |
|
562 * One chunk of text, to allow recursive handling of ternary |
|
563 * expressions in zformat -f output. |
|
564 * instr The input string. |
|
565 * specs The format specifiers, specs[c] is the string from c:string |
|
566 * outp *outp is the start of the output string |
|
567 * ousedp (*outp)[*ousedp] is where to write next |
|
568 * olenp *olenp is the size allocated for *outp |
|
569 * endchar Terminator character in addition to `\0' (may be '\0') |
|
570 * skip If 1, don't output, just parse. |
|
571 */ |
|
572 static char *zformat_substring(char* instr, char **specs, char **outp, |
|
573 int *ousedp, int *olenp, int endchar, int skip) |
|
574 { |
|
575 char *s; |
|
576 |
|
577 for (s = instr; *s && *s != endchar; s++) { |
|
578 if (*s == '%') { |
|
579 int right, min = -1, max = -1, outl, testit; |
|
580 char *spec, *start = s; |
|
581 |
|
582 if ((right = (*++s == '-'))) |
|
583 s++; |
|
584 |
|
585 if (*s >= '0' && *s <= '9') { |
|
586 for (min = 0; *s >= '0' && *s <= '9'; s++) |
|
587 min = (min * 10) + (int) STOUC(*s) - '0'; |
|
588 } |
|
589 |
|
590 /* Ternary expressions */ |
|
591 testit = (STOUC(*s) == '('); |
|
592 if (testit && s[1] == '-') |
|
593 { |
|
594 /* Allow %(-1... etc. */ |
|
595 right = 1; |
|
596 s++; |
|
597 } |
|
598 if ((*s == '.' || testit) && s[1] >= '0' && s[1] <= '9') { |
|
599 for (max = 0, s++; *s >= '0' && *s <= '9'; s++) |
|
600 max = (max * 10) + (int) STOUC(*s) - '0'; |
|
601 } |
|
602 else if (testit) |
|
603 s++; |
|
604 |
|
605 if (testit && STOUC(*s)) { |
|
606 int actval, testval, endcharl; |
|
607 |
|
608 /* |
|
609 * One one number is useful for ternary expressions. |
|
610 * Remember to put the sign back. |
|
611 */ |
|
612 testval = (min >= 0) ? min : (max >= 0) ? max : 0; |
|
613 if (right) |
|
614 testval *= -1; |
|
615 |
|
616 if (specs[STOUC(*s)]) |
|
617 actval = (int)mathevali(specs[STOUC(*s)]); |
|
618 else |
|
619 actval = 0; |
|
620 /* zero means values are equal, i.e. true */ |
|
621 actval -= testval; |
|
622 |
|
623 /* careful about premature end of string */ |
|
624 if (!(endcharl = *++s)) |
|
625 return NULL; |
|
626 |
|
627 /* |
|
628 * Either skip true text and output false text, or |
|
629 * vice versa... unless we are already skipping. |
|
630 */ |
|
631 if (!(s = zformat_substring(s+1, specs, outp, ousedp, |
|
632 olenp, endcharl, skip || actval))) |
|
633 return NULL; |
|
634 if (!(s = zformat_substring(s+1, specs, outp, ousedp, |
|
635 olenp, ')', skip || !actval))) |
|
636 return NULL; |
|
637 } else if (skip) { |
|
638 continue; |
|
639 } else if ((spec = specs[STOUC(*s)])) { |
|
640 int len; |
|
641 |
|
642 if ((len = strlen(spec)) > max && max >= 0) |
|
643 len = max; |
|
644 outl = (min >= 0 ? (min > len ? min : len) : len); |
|
645 |
|
646 if (*ousedp + outl >= *olenp) { |
|
647 int nlen = *olenp + outl + 128; |
|
648 char *tmp = (char *) zhalloc(nlen); |
|
649 |
|
650 memcpy(tmp, *outp, *olenp); |
|
651 *olenp = nlen; |
|
652 *outp = tmp; |
|
653 } |
|
654 if (len >= outl) { |
|
655 memcpy(*outp + *ousedp, spec, outl); |
|
656 *ousedp += outl; |
|
657 } else { |
|
658 int diff = outl - len; |
|
659 |
|
660 if (right) { |
|
661 while (diff--) |
|
662 (*outp)[(*ousedp)++] = ' '; |
|
663 memcpy(*outp + *ousedp, spec, len); |
|
664 *ousedp += len; |
|
665 } else { |
|
666 memcpy(*outp + *ousedp, spec, len); |
|
667 *ousedp += len; |
|
668 while (diff--) |
|
669 (*outp)[(*ousedp)++] = ' '; |
|
670 } |
|
671 } |
|
672 } else { |
|
673 int len = s - start + 1; |
|
674 |
|
675 if (*ousedp + len >= *olenp) { |
|
676 int nlen = *olenp + len + 128; |
|
677 char *tmp = (char *) zhalloc(nlen); |
|
678 |
|
679 memcpy(tmp, *outp, *olenp); |
|
680 *olenp = nlen; |
|
681 *outp = tmp; |
|
682 } |
|
683 memcpy(*outp + *ousedp, start, len); |
|
684 *ousedp += len; |
|
685 } |
|
686 } else { |
|
687 if (skip) |
|
688 continue; |
|
689 if (*ousedp + 1 >= *olenp) { |
|
690 char *tmp = (char *) zhalloc((*olenp) << 1); |
|
691 |
|
692 memcpy(tmp, *outp, *olenp); |
|
693 *olenp <<= 1; |
|
694 *outp = tmp; |
|
695 } |
|
696 (*outp)[(*ousedp)++] = *s; |
|
697 } |
|
698 } |
|
699 |
|
700 return s; |
|
701 } |
|
702 |
|
703 static int |
|
704 bin_zformat(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) |
|
705 { |
|
706 char opt; |
|
707 |
|
708 if (args[0][0] != '-' || !(opt = args[0][1]) || args[0][2]) { |
|
709 zwarnnam(nam, "invalid argument: %s", args[0], 0); |
|
710 return 1; |
|
711 } |
|
712 args++; |
|
713 |
|
714 switch (opt) { |
|
715 case 'f': |
|
716 { |
|
717 char **ap, *specs[256], *out; |
|
718 int olen, oused = 0; |
|
719 |
|
720 memset(specs, 0, 256 * sizeof(char *)); |
|
721 |
|
722 specs['%'] = "%"; |
|
723 specs[')'] = ")"; |
|
724 for (ap = args + 2; *ap; ap++) { |
|
725 if (!ap[0][0] || ap[0][0] == '-' || ap[0][0] == '.' || |
|
726 (ap[0][0] >= '0' && ap[0][0] <= '9') || |
|
727 ap[0][1] != ':') { |
|
728 zwarnnam(nam, "invalid argument: %s", *ap, 0); |
|
729 return 1; |
|
730 } |
|
731 specs[STOUC(ap[0][0])] = ap[0] + 2; |
|
732 } |
|
733 out = (char *) zhalloc(olen = 128); |
|
734 |
|
735 zformat_substring(args[1], specs, &out, &oused, &olen, '\0', 0); |
|
736 out[oused] = '\0'; |
|
737 |
|
738 setsparam(args[0], ztrdup(out)); |
|
739 return 0; |
|
740 } |
|
741 break; |
|
742 case 'a': |
|
743 { |
|
744 char **ap, *cp; |
|
745 int nbc = 0, colon = 0, pre = 0, suf = 0; |
|
746 |
|
747 for (ap = args + 2; *ap; ap++) { |
|
748 for (nbc = 0, cp = *ap; *cp && *cp != ':'; cp++) |
|
749 if (*cp == '\\' && cp[1]) |
|
750 cp++, nbc++; |
|
751 if (*cp == ':' && cp[1]) { |
|
752 int d; |
|
753 |
|
754 colon++; |
|
755 if ((d = cp - *ap - nbc) > pre) |
|
756 pre = d; |
|
757 if ((d = strlen(cp + 1)) > suf) |
|
758 suf = d; |
|
759 } |
|
760 } |
|
761 { |
|
762 int sl = strlen(args[1]); |
|
763 VARARR(char, buf, pre + suf + sl + 1); |
|
764 char **ret, **rp, *copy, *cpp, oldc; |
|
765 |
|
766 ret = (char **) zalloc((arrlen(args + 2) + 1) * |
|
767 sizeof(char *)); |
|
768 |
|
769 memcpy(buf + pre, args[1], sl); |
|
770 suf = pre + sl; |
|
771 |
|
772 for (rp = ret, ap = args + 2; *ap; ap++) { |
|
773 copy = dupstring(*ap); |
|
774 for (cp = cpp = copy; *cp && *cp != ':'; cp++) { |
|
775 if (*cp == '\\' && cp[1]) |
|
776 cp++; |
|
777 *cpp++ = *cp; |
|
778 } |
|
779 oldc = *cpp; |
|
780 *cpp = '\0'; |
|
781 if (((cpp == cp && oldc == ':') || *cp == ':') && cp[1]) { |
|
782 memset(buf, ' ', pre); |
|
783 memcpy(buf, copy, (cpp - copy)); |
|
784 strcpy(buf + suf, cp + 1); |
|
785 *rp++ = ztrdup(buf); |
|
786 } else |
|
787 *rp++ = ztrdup(copy); |
|
788 } |
|
789 *rp = NULL; |
|
790 |
|
791 setaparam(args[0], ret); |
|
792 return 0; |
|
793 } |
|
794 } |
|
795 break; |
|
796 } |
|
797 zwarnnam(nam, "invalid option: -%c", 0, opt); |
|
798 return 1; |
|
799 } |
|
800 |
|
801 /* Zregexparse stuff. */ |
|
802 |
|
803 typedef struct { |
|
804 char **match; |
|
805 char **mbegin; |
|
806 char **mend; |
|
807 } MatchData; |
|
808 |
|
809 static void |
|
810 savematch(MatchData *m) |
|
811 { |
|
812 char **a; |
|
813 |
|
814 queue_signals(); |
|
815 a = getaparam("match"); |
|
816 m->match = a ? zarrdup(a) : NULL; |
|
817 a = getaparam("mbegin"); |
|
818 m->mbegin = a ? zarrdup(a) : NULL; |
|
819 a = getaparam("mend"); |
|
820 m->mend = a ? zarrdup(a) : NULL; |
|
821 unqueue_signals(); |
|
822 } |
|
823 |
|
824 static void |
|
825 restorematch(MatchData *m) |
|
826 { |
|
827 if (m->match) |
|
828 setaparam("match", m->match); |
|
829 else |
|
830 unsetparam("match"); |
|
831 if (m->mbegin) |
|
832 setaparam("mbegin", m->mbegin); |
|
833 else |
|
834 unsetparam("mbegin"); |
|
835 if (m->mend) |
|
836 setaparam("mend", m->mend); |
|
837 else |
|
838 unsetparam("mend"); |
|
839 } |
|
840 |
|
841 static void |
|
842 freematch(MatchData *m) |
|
843 { |
|
844 if (m->match) |
|
845 freearray(m->match); |
|
846 if (m->mbegin) |
|
847 freearray(m->mbegin); |
|
848 if (m->mend) |
|
849 freearray(m->mend); |
|
850 } |
|
851 |
|
852 typedef struct { |
|
853 int cutoff; |
|
854 char *pattern; |
|
855 Patprog patprog; |
|
856 char *guard; |
|
857 char *action; |
|
858 LinkList branches; |
|
859 } RParseState; |
|
860 |
|
861 typedef struct { |
|
862 RParseState *state; |
|
863 LinkList actions; |
|
864 } RParseBranch; |
|
865 |
|
866 typedef struct { |
|
867 LinkList nullacts; |
|
868 LinkList in; |
|
869 LinkList out; |
|
870 } RParseResult; |
|
871 |
|
872 static char **rparseargs; |
|
873 static LinkList rparsestates; |
|
874 |
|
875 static int rparsealt(RParseResult *result, jmp_buf *perr); |
|
876 |
|
877 static void |
|
878 connectstates(LinkList out, LinkList in) |
|
879 { |
|
880 LinkNode outnode, innode, ln; |
|
881 |
|
882 for (outnode = firstnode(out); outnode; outnode = nextnode(outnode)) { |
|
883 RParseBranch *outbranch = getdata(outnode); |
|
884 |
|
885 for (innode = firstnode(in); innode; innode = nextnode(innode)) { |
|
886 RParseBranch *inbranch = getdata(innode); |
|
887 RParseBranch *br = hcalloc(sizeof(*br)); |
|
888 |
|
889 br->state = inbranch->state; |
|
890 br->actions = newlinklist(); |
|
891 for (ln = firstnode(outbranch->actions); ln; ln = nextnode(ln)) |
|
892 addlinknode(br->actions, getdata(ln)); |
|
893 for (ln = firstnode(inbranch->actions); ln; ln = nextnode(ln)) |
|
894 addlinknode(br->actions, getdata(ln)); |
|
895 addlinknode(outbranch->state->branches, br); |
|
896 } |
|
897 } |
|
898 } |
|
899 |
|
900 static int |
|
901 rparseelt(RParseResult *result, jmp_buf *perr) |
|
902 { |
|
903 int l; |
|
904 char *s = *rparseargs; |
|
905 |
|
906 if (!s) |
|
907 return 1; |
|
908 |
|
909 switch (s[0]) { |
|
910 case '/': { |
|
911 RParseState *st; |
|
912 RParseBranch *br; |
|
913 char *pattern, *lookahead; |
|
914 int patternlen, lookaheadlen = 0; |
|
915 |
|
916 l = strlen(s); |
|
917 if (!((2 <= l && s[l - 1] == '/') || |
|
918 (3 <= l && s[l - 2] == '/' && (s[l - 1] == '+' || |
|
919 s[l - 1] == '-')))) |
|
920 return 1; |
|
921 st = hcalloc(sizeof(*st)); |
|
922 st->branches = newlinklist(); |
|
923 st->cutoff = s[l - 1]; |
|
924 if (s[l - 1] == '/') { |
|
925 pattern = s + 1; |
|
926 patternlen = l - 2; |
|
927 } else { |
|
928 pattern = s + 1; |
|
929 patternlen = l - 3; |
|
930 } |
|
931 rparseargs++; |
|
932 if ((s = *rparseargs) && s[0] == '%' && |
|
933 2 <= (l = strlen(s)) && s[l - 1] == '%') { |
|
934 rparseargs++; |
|
935 lookahead = s + 1; |
|
936 lookaheadlen = l - 2; |
|
937 } else { |
|
938 lookahead = NULL; |
|
939 } |
|
940 if (patternlen == 2 && !strncmp(pattern, "[]", 2)) |
|
941 st->pattern = NULL; |
|
942 else { |
|
943 char *cp; |
|
944 int l = patternlen + 12; /* (#b)((#B)...)...* */ |
|
945 if(lookahead) |
|
946 l += lookaheadlen + 4; /* (#B)... */ |
|
947 cp = st->pattern = hcalloc(l); |
|
948 strcpy(cp, "(#b)((#B)"); |
|
949 cp += 9; |
|
950 strcpy(cp, pattern); |
|
951 cp += patternlen; |
|
952 strcpy(cp, ")"); |
|
953 cp += 1; |
|
954 if (lookahead) { |
|
955 strcpy(cp, "(#B)"); |
|
956 cp += 4; |
|
957 strcpy(cp, lookahead); |
|
958 cp += lookaheadlen; |
|
959 } |
|
960 strcpy(cp, "*"); |
|
961 } |
|
962 st->patprog = NULL; |
|
963 if ((s = *rparseargs) && *s == '-') { |
|
964 rparseargs++; |
|
965 l = strlen(s); |
|
966 st->guard = hcalloc(l); |
|
967 memcpy(st->guard, s + 1, l - 1); |
|
968 st->guard[l - 1] = '\0'; |
|
969 } else |
|
970 st->guard = NULL; |
|
971 if ((s = *rparseargs) && *s == ':') { |
|
972 rparseargs++; |
|
973 l = strlen(s); |
|
974 st->action = hcalloc(l); |
|
975 memcpy(st->action, s + 1, l - 1); |
|
976 st->action[l - 1] = '\0'; |
|
977 } else |
|
978 st->action = NULL; |
|
979 result->nullacts = NULL; |
|
980 result->in = newlinklist(); |
|
981 br = hcalloc(sizeof(*br)); |
|
982 br->state = st; |
|
983 br->actions = newlinklist(); |
|
984 addlinknode(result->in, br); |
|
985 result->out = newlinklist(); |
|
986 br = hcalloc(sizeof(*br)); |
|
987 br->state = st; |
|
988 br->actions = newlinklist(); |
|
989 addlinknode(result->out, br); |
|
990 break; |
|
991 } |
|
992 case '(': |
|
993 if (s[1]) |
|
994 return 1; |
|
995 rparseargs++; |
|
996 if (rparsealt(result, perr)) |
|
997 longjmp(*perr, 2); |
|
998 s = *rparseargs; |
|
999 if (!s || s[0] != ')' || s[1] != '\0') |
|
1000 longjmp(*perr, 2); |
|
1001 rparseargs++; |
|
1002 break; |
|
1003 default: |
|
1004 return 1; |
|
1005 } |
|
1006 |
|
1007 return 0; |
|
1008 } |
|
1009 |
|
1010 static int |
|
1011 rparseclo(RParseResult *result, jmp_buf *perr) |
|
1012 { |
|
1013 if (rparseelt(result, perr)) |
|
1014 return 1; |
|
1015 |
|
1016 if (*rparseargs && !strcmp(*rparseargs, "#")) { |
|
1017 rparseargs++; |
|
1018 while (*rparseargs && !strcmp(*rparseargs, "#")) |
|
1019 rparseargs++; |
|
1020 |
|
1021 connectstates(result->out, result->in); |
|
1022 result->nullacts = newlinklist(); |
|
1023 } |
|
1024 return 0; |
|
1025 } |
|
1026 |
|
1027 static void |
|
1028 prependactions(LinkList acts, LinkList branches) |
|
1029 { |
|
1030 LinkNode aln, bln; |
|
1031 |
|
1032 for (bln = firstnode(branches); bln; bln = nextnode(bln)) { |
|
1033 RParseBranch *br = getdata(bln); |
|
1034 |
|
1035 for (aln = lastnode(acts); aln != (LinkNode)acts; aln = prevnode(aln)) |
|
1036 pushnode(br->actions, getdata(aln)); |
|
1037 } |
|
1038 } |
|
1039 |
|
1040 static void |
|
1041 appendactions(LinkList acts, LinkList branches) |
|
1042 { |
|
1043 LinkNode aln, bln; |
|
1044 for (bln = firstnode(branches); bln; bln = nextnode(bln)) { |
|
1045 RParseBranch *br = getdata(bln); |
|
1046 |
|
1047 for (aln = firstnode(acts); aln; aln = nextnode(aln)) |
|
1048 addlinknode(br->actions, getdata(aln)); |
|
1049 } |
|
1050 } |
|
1051 |
|
1052 static int |
|
1053 rparseseq(RParseResult *result, jmp_buf *perr) |
|
1054 { |
|
1055 int l; |
|
1056 char *s; |
|
1057 RParseResult sub; |
|
1058 |
|
1059 result->nullacts = newlinklist(); |
|
1060 result->in = newlinklist(); |
|
1061 result->out = newlinklist(); |
|
1062 |
|
1063 while (1) { |
|
1064 if ((s = *rparseargs) && s[0] == '{' && s[(l = strlen(s)) - 1] == '}') { |
|
1065 char *action = hcalloc(l - 1); |
|
1066 LinkNode ln; |
|
1067 |
|
1068 rparseargs++; |
|
1069 memcpy(action, s + 1, l - 2); |
|
1070 action[l - 2] = '\0'; |
|
1071 if (result->nullacts) |
|
1072 addlinknode(result->nullacts, action); |
|
1073 for (ln = firstnode(result->out); ln; ln = nextnode(ln)) { |
|
1074 RParseBranch *br = getdata(ln); |
|
1075 addlinknode(br->actions, action); |
|
1076 } |
|
1077 } |
|
1078 else if (!rparseclo(&sub, perr)) { |
|
1079 connectstates(result->out, sub.in); |
|
1080 |
|
1081 if (result->nullacts) { |
|
1082 prependactions(result->nullacts, sub.in); |
|
1083 insertlinklist(sub.in, lastnode(result->in), result->in); |
|
1084 } |
|
1085 if (sub.nullacts) { |
|
1086 appendactions(sub.nullacts, result->out); |
|
1087 insertlinklist(sub.out, lastnode(result->out), result->out); |
|
1088 } else |
|
1089 result->out = sub.out; |
|
1090 |
|
1091 if (result->nullacts && sub.nullacts) |
|
1092 insertlinklist(sub.nullacts, lastnode(result->nullacts), |
|
1093 result->nullacts); |
|
1094 else |
|
1095 result->nullacts = NULL; |
|
1096 } |
|
1097 else |
|
1098 break; |
|
1099 } |
|
1100 return 0; |
|
1101 } |
|
1102 |
|
1103 static int |
|
1104 rparsealt(RParseResult *result, jmp_buf *perr) |
|
1105 { |
|
1106 RParseResult sub; |
|
1107 |
|
1108 if (rparseseq(result, perr)) |
|
1109 return 1; |
|
1110 |
|
1111 while (*rparseargs && !strcmp(*rparseargs, "|")) { |
|
1112 rparseargs++; |
|
1113 if (rparseseq(&sub, perr)) |
|
1114 longjmp(*perr, 2); |
|
1115 if (!result->nullacts && sub.nullacts) |
|
1116 result->nullacts = sub.nullacts; |
|
1117 |
|
1118 insertlinklist(sub.in, lastnode(result->in), result->in); |
|
1119 insertlinklist(sub.out, lastnode(result->out), result->out); |
|
1120 } |
|
1121 return 0; |
|
1122 } |
|
1123 |
|
1124 static int |
|
1125 rmatch(RParseResult *sm, char *subj, char *var1, char *var2, int comp) |
|
1126 { |
|
1127 LinkNode ln, lnn; |
|
1128 LinkList nexts; |
|
1129 LinkList nextslist; |
|
1130 RParseBranch *br; |
|
1131 RParseState *st = NULL; |
|
1132 int point1 = 0, point2 = 0; |
|
1133 |
|
1134 setiparam(var1, point1); |
|
1135 setiparam(var2, point2); |
|
1136 |
|
1137 if (!comp && !*subj && sm->nullacts) { |
|
1138 for (ln = firstnode(sm->nullacts); ln; ln = nextnode(ln)) { |
|
1139 char *action = getdata(ln); |
|
1140 |
|
1141 if (action) |
|
1142 execstring(action, 1, 0); |
|
1143 } |
|
1144 return 0; |
|
1145 } |
|
1146 |
|
1147 nextslist = newlinklist(); |
|
1148 nexts = sm->in; |
|
1149 addlinknode(nextslist, nexts); |
|
1150 do { |
|
1151 MatchData match1, match2; |
|
1152 |
|
1153 savematch(&match1); |
|
1154 |
|
1155 for (ln = firstnode(nexts); ln; ln = nextnode(ln)) { |
|
1156 int i; |
|
1157 RParseState *next; |
|
1158 |
|
1159 br = getdata(ln); |
|
1160 next = br->state; |
|
1161 if (next->pattern && !next->patprog) { |
|
1162 tokenize(next->pattern); |
|
1163 if (!(next->patprog = patcompile(next->pattern, 0, NULL))) |
|
1164 return 3; |
|
1165 } |
|
1166 if (next->pattern && pattry(next->patprog, subj) && |
|
1167 (!next->guard || (execstring(next->guard, 1, 0), !lastval))) { |
|
1168 LinkNode aln; |
|
1169 char **mend; |
|
1170 int len; |
|
1171 |
|
1172 queue_signals(); |
|
1173 mend = getaparam("mend"); |
|
1174 len = atoi(mend[0]); |
|
1175 unqueue_signals(); |
|
1176 |
|
1177 for (i = len; i; i--) |
|
1178 if (*subj++ == Meta) |
|
1179 subj++; |
|
1180 |
|
1181 savematch(&match2); |
|
1182 restorematch(&match1); |
|
1183 |
|
1184 for (aln = firstnode(br->actions); aln; aln = nextnode(aln)) { |
|
1185 char *action = getdata(aln); |
|
1186 |
|
1187 if (action) |
|
1188 execstring(action, 1, 0); |
|
1189 } |
|
1190 restorematch(&match2); |
|
1191 |
|
1192 point2 += len; |
|
1193 setiparam(var2, point2); |
|
1194 st = br->state; |
|
1195 nexts = st->branches; |
|
1196 if (next->cutoff == '-' || (next->cutoff == '/' && len)) { |
|
1197 nextslist = newlinklist(); |
|
1198 point1 = point2; |
|
1199 setiparam(var1, point1); |
|
1200 } |
|
1201 addlinknode(nextslist, nexts); |
|
1202 break; |
|
1203 } |
|
1204 } |
|
1205 if (!ln) |
|
1206 freematch(&match1); |
|
1207 } while (ln); |
|
1208 |
|
1209 if (!comp && !*subj) |
|
1210 for (ln = firstnode(sm->out); ln; ln = nextnode(ln)) { |
|
1211 br = getdata(ln); |
|
1212 if (br->state == st) { |
|
1213 for (ln = firstnode(br->actions); ln; ln = nextnode(ln)) { |
|
1214 char *action = getdata(ln); |
|
1215 |
|
1216 if (action) |
|
1217 execstring(action, 1, 0); |
|
1218 } |
|
1219 return 0; |
|
1220 } |
|
1221 } |
|
1222 |
|
1223 for (lnn = firstnode(nextslist); lnn; lnn = nextnode(lnn)) { |
|
1224 nexts = getdata(lnn); |
|
1225 for (ln = firstnode(nexts); ln; ln = nextnode(ln)) { |
|
1226 br = getdata(ln); |
|
1227 if (br->state->action) |
|
1228 execstring(br->state->action, 1, 0); |
|
1229 } |
|
1230 } |
|
1231 return empty(nexts) ? 2 : 1; |
|
1232 } |
|
1233 |
|
1234 /* |
|
1235 usage: zregexparse [-c] var1 var2 string regex... |
|
1236 status: |
|
1237 0: matched |
|
1238 1: unmatched (all next state candidates are failed) |
|
1239 2: unmatched (there is no next state candidates) |
|
1240 3: regex parse error |
|
1241 */ |
|
1242 |
|
1243 static int |
|
1244 bin_zregexparse(char *nam, char **args, Options ops, UNUSED(int func)) |
|
1245 { |
|
1246 int oldextendedglob = opts[EXTENDEDGLOB]; |
|
1247 char *var1 = args[0]; |
|
1248 char *var2 = args[1]; |
|
1249 char *subj = args[2]; |
|
1250 int ret; |
|
1251 jmp_buf rparseerr; |
|
1252 RParseResult result; |
|
1253 |
|
1254 opts[EXTENDEDGLOB] = 1; |
|
1255 |
|
1256 rparseargs = args + 3; |
|
1257 |
|
1258 pushheap(); |
|
1259 rparsestates = newlinklist(); |
|
1260 if (setjmp(rparseerr) || rparsealt(&result, &rparseerr) || *rparseargs) { |
|
1261 if (*rparseargs) |
|
1262 zwarnnam(nam, "invalid regex : %s", *rparseargs, 0); |
|
1263 else |
|
1264 zwarnnam(nam, "not enough regex arguments", NULL, 0); |
|
1265 ret = 3; |
|
1266 } else |
|
1267 ret = 0; |
|
1268 |
|
1269 if (!ret) |
|
1270 ret = rmatch(&result, subj, var1, var2, OPT_ISSET(ops,'c')); |
|
1271 popheap(); |
|
1272 |
|
1273 opts[EXTENDEDGLOB] = oldextendedglob; |
|
1274 return ret; |
|
1275 } |
|
1276 |
|
1277 typedef struct zoptdesc *Zoptdesc; |
|
1278 typedef struct zoptarr *Zoptarr; |
|
1279 typedef struct zoptval *Zoptval; |
|
1280 |
|
1281 struct zoptdesc { |
|
1282 Zoptdesc next; |
|
1283 char *name; |
|
1284 int flags; |
|
1285 Zoptarr arr; |
|
1286 Zoptval vals, last; |
|
1287 }; |
|
1288 |
|
1289 #define ZOF_ARG 1 |
|
1290 #define ZOF_OPT 2 |
|
1291 #define ZOF_MULT 4 |
|
1292 #define ZOF_SAME 8 |
|
1293 |
|
1294 struct zoptarr { |
|
1295 Zoptarr next; |
|
1296 char *name; |
|
1297 Zoptval vals, last; |
|
1298 int num; |
|
1299 }; |
|
1300 |
|
1301 struct zoptval { |
|
1302 Zoptval next, onext; |
|
1303 char *name; |
|
1304 char *arg; |
|
1305 char *str; |
|
1306 }; |
|
1307 |
|
1308 static Zoptdesc opt_descs; |
|
1309 static Zoptarr opt_arrs; |
|
1310 |
|
1311 static Zoptdesc |
|
1312 get_opt_desc(char *name) |
|
1313 { |
|
1314 Zoptdesc p; |
|
1315 |
|
1316 for (p = opt_descs; p; p = p->next) |
|
1317 if (!strcmp(name, p->name)) |
|
1318 return p; |
|
1319 |
|
1320 return NULL; |
|
1321 } |
|
1322 |
|
1323 static Zoptdesc |
|
1324 lookup_opt(char *str) |
|
1325 { |
|
1326 Zoptdesc p; |
|
1327 |
|
1328 for (p = opt_descs; p; p = p->next) { |
|
1329 if ((p->flags & ZOF_ARG) ? strpfx(p->name, str) : !strcmp(p->name, str)) |
|
1330 return p; |
|
1331 } |
|
1332 return NULL; |
|
1333 } |
|
1334 |
|
1335 static Zoptarr |
|
1336 get_opt_arr(char *name) |
|
1337 { |
|
1338 Zoptarr p; |
|
1339 |
|
1340 for (p = opt_arrs; p; p = p->next) |
|
1341 if (!strcmp(name, p->name)) |
|
1342 return p; |
|
1343 |
|
1344 return NULL; |
|
1345 } |
|
1346 |
|
1347 static void |
|
1348 add_opt_val(Zoptdesc d, char *arg) |
|
1349 { |
|
1350 Zoptval v = NULL; |
|
1351 char *n = dyncat("-", d->name); |
|
1352 int new = 0; |
|
1353 |
|
1354 if (!(d->flags & ZOF_MULT)) |
|
1355 v = d->vals; |
|
1356 if (!v) { |
|
1357 v = (Zoptval) zhalloc(sizeof(*v)); |
|
1358 v->next = v->onext = NULL; |
|
1359 v->name = n; |
|
1360 new = 1; |
|
1361 } |
|
1362 v->arg = arg; |
|
1363 if ((d->flags & ZOF_ARG) && !(d->flags & (ZOF_OPT | ZOF_SAME))) { |
|
1364 v->str = NULL; |
|
1365 if (d->arr) |
|
1366 d->arr->num += (arg ? 2 : 1); |
|
1367 } else if (arg) { |
|
1368 char *s = (char *) zhalloc(strlen(d->name) + strlen(arg) + 2); |
|
1369 |
|
1370 *s = '-'; |
|
1371 strcpy(s + 1, d->name); |
|
1372 strcat(s, arg); |
|
1373 v->str = s; |
|
1374 if (d->arr) |
|
1375 d->arr->num += 1; |
|
1376 } else { |
|
1377 v->str = NULL; |
|
1378 if (d->arr) |
|
1379 d->arr->num += 1; |
|
1380 } |
|
1381 if (new) { |
|
1382 if (d->arr) { |
|
1383 if (d->arr->last) |
|
1384 d->arr->last->next = v; |
|
1385 else |
|
1386 d->arr->vals = v; |
|
1387 d->arr->last = v; |
|
1388 } |
|
1389 if (d->last) |
|
1390 d->last->onext = v; |
|
1391 else |
|
1392 d->vals = v; |
|
1393 d->last = v; |
|
1394 } |
|
1395 } |
|
1396 |
|
1397 static int |
|
1398 bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) |
|
1399 { |
|
1400 char *o, *p, *n, **pp, **aval, **ap, *assoc = NULL, **cp, **np; |
|
1401 int del = 0, f, extract = 0, keep = 0; |
|
1402 Zoptdesc sopts[256], d; |
|
1403 Zoptarr a, defarr = NULL; |
|
1404 Zoptval v; |
|
1405 |
|
1406 opt_descs = NULL; |
|
1407 opt_arrs = NULL; |
|
1408 memset(sopts, 0, 256 * sizeof(Zoptdesc)); |
|
1409 |
|
1410 while ((o = *args++)) { |
|
1411 if (*o == '-') { |
|
1412 switch (o[1]) { |
|
1413 case '\0': |
|
1414 o = NULL; |
|
1415 break; |
|
1416 case '-': |
|
1417 if (o[2]) |
|
1418 args--; |
|
1419 o = NULL; |
|
1420 break; |
|
1421 case 'D': |
|
1422 if (o[2]) { |
|
1423 args--; |
|
1424 o = NULL; |
|
1425 break; |
|
1426 } |
|
1427 del = 1; |
|
1428 break; |
|
1429 case 'E': |
|
1430 if (o[2]) { |
|
1431 args--; |
|
1432 o = NULL; |
|
1433 break; |
|
1434 } |
|
1435 extract = 1; |
|
1436 break; |
|
1437 case 'K': |
|
1438 if (o[2]) { |
|
1439 args--; |
|
1440 o = NULL; |
|
1441 break; |
|
1442 } |
|
1443 keep = 1; |
|
1444 break; |
|
1445 case 'a': |
|
1446 if (defarr) { |
|
1447 zwarnnam(nam, "default array given more than once", NULL, 0); |
|
1448 return 1; |
|
1449 } |
|
1450 if (o[2]) |
|
1451 n = o + 2; |
|
1452 else if (*args) |
|
1453 n = *args++; |
|
1454 else { |
|
1455 zwarnnam(nam, "missing array name", NULL, 0); |
|
1456 return 1; |
|
1457 } |
|
1458 defarr = (Zoptarr) zhalloc(sizeof(*defarr)); |
|
1459 defarr->name = n; |
|
1460 defarr->num = 0; |
|
1461 defarr->vals = defarr->last = NULL; |
|
1462 defarr->next = NULL; |
|
1463 opt_arrs = defarr; |
|
1464 break; |
|
1465 case 'A': |
|
1466 if (o[2]) |
|
1467 assoc = o + 2; |
|
1468 else if (*args) |
|
1469 assoc = *args++; |
|
1470 else { |
|
1471 zwarnnam(nam, "missing array name", NULL, 0); |
|
1472 return 1; |
|
1473 } |
|
1474 break; |
|
1475 } |
|
1476 if (!o) { |
|
1477 o = ""; |
|
1478 break; |
|
1479 } |
|
1480 } else { |
|
1481 args--; |
|
1482 break; |
|
1483 } |
|
1484 } |
|
1485 if (!o) { |
|
1486 zwarnnam(nam, "missing option descriptions", NULL, 0); |
|
1487 return 1; |
|
1488 } |
|
1489 while ((o = dupstring(*args++))) { |
|
1490 if (!*o) { |
|
1491 zwarnnam(nam, "invalid option description: %s", o, 0); |
|
1492 return 1; |
|
1493 } |
|
1494 f = 0; |
|
1495 for (p = o; *p; p++) { |
|
1496 if (*p == '\\' && p[1]) |
|
1497 p++; |
|
1498 else if (*p == '+') { |
|
1499 f |= ZOF_MULT; |
|
1500 *p = '\0'; |
|
1501 p++; |
|
1502 break; |
|
1503 } else if (*p == ':' || *p == '=') |
|
1504 break; |
|
1505 } |
|
1506 if (*p == ':') { |
|
1507 f |= ZOF_ARG; |
|
1508 *p = '\0'; |
|
1509 if (*++p == ':') { |
|
1510 p++; |
|
1511 f |= ZOF_OPT; |
|
1512 } |
|
1513 if (*p == '-') { |
|
1514 p++; |
|
1515 f |= ZOF_SAME; |
|
1516 } |
|
1517 } |
|
1518 a = NULL; |
|
1519 if (*p == '=') { |
|
1520 *p++ = '\0'; |
|
1521 if (!(a = get_opt_arr(p))) { |
|
1522 a = (Zoptarr) zhalloc(sizeof(*a)); |
|
1523 a->name = p; |
|
1524 a->num = 0; |
|
1525 a->vals = a->last = NULL; |
|
1526 a->next = opt_arrs; |
|
1527 opt_arrs = a; |
|
1528 } |
|
1529 } else if (*p) { |
|
1530 zwarnnam(nam, "invalid option description: %s", args[-1], 0); |
|
1531 return 1; |
|
1532 } else if (!(a = defarr) && !assoc) { |
|
1533 zwarnnam(nam, "no default array defined: %s", args[-1], 0); |
|
1534 return 1; |
|
1535 } |
|
1536 for (p = n = o; *p; p++) { |
|
1537 if (*p == '\\' && p[1]) |
|
1538 p++; |
|
1539 *n++ = *p; |
|
1540 } |
|
1541 if (get_opt_desc(o)) { |
|
1542 zwarnnam(nam, "option defined more than once: %s", o, 0); |
|
1543 return 1; |
|
1544 } |
|
1545 d = (Zoptdesc) zhalloc(sizeof(*d)); |
|
1546 d->name = o; |
|
1547 d->flags = f; |
|
1548 d->arr = a; |
|
1549 d->next = opt_descs; |
|
1550 d->vals = d->last = NULL; |
|
1551 opt_descs = d; |
|
1552 if (!o[1]) |
|
1553 sopts[STOUC(*o)] = d; |
|
1554 } |
|
1555 np = cp = pp = ((extract && del) ? arrdup(pparams) : pparams); |
|
1556 for (; (o = *pp); pp++) { |
|
1557 if (*o != '-') { |
|
1558 if (extract) { |
|
1559 if (del) |
|
1560 *cp++ = o; |
|
1561 continue; |
|
1562 } else |
|
1563 break; |
|
1564 } |
|
1565 if (!o[1] || (o[1] == '-' && !o[2])) { |
|
1566 if (del && extract) |
|
1567 *cp++ = o; |
|
1568 pp++; |
|
1569 break; |
|
1570 } |
|
1571 if (!(d = lookup_opt(o + 1))) { |
|
1572 while (*++o) { |
|
1573 if (!(d = sopts[STOUC(*o)])) { |
|
1574 o = NULL; |
|
1575 break; |
|
1576 } |
|
1577 if (d->flags & ZOF_ARG) { |
|
1578 if (o[1]) { |
|
1579 add_opt_val(d, o + 1); |
|
1580 break; |
|
1581 } else if (!(d->flags & ZOF_OPT)) { |
|
1582 if (!pp[1]) { |
|
1583 zwarnnam(nam, "missing argument for option: %s", |
|
1584 d->name, 0); |
|
1585 return 1; |
|
1586 } |
|
1587 add_opt_val(d, *++pp); |
|
1588 } else |
|
1589 add_opt_val(d, NULL); |
|
1590 } else |
|
1591 add_opt_val(d, NULL); |
|
1592 } |
|
1593 if (!o) { |
|
1594 if (extract) { |
|
1595 if (del) |
|
1596 *cp++ = *pp; |
|
1597 continue; |
|
1598 } else |
|
1599 break; |
|
1600 } |
|
1601 } else { |
|
1602 if (d->flags & ZOF_ARG) { |
|
1603 char *e = o + strlen(d->name) + 1; |
|
1604 |
|
1605 if (*e) |
|
1606 add_opt_val(d, e); |
|
1607 else if (!(d->flags & ZOF_OPT)) { |
|
1608 if (!pp[1]) { |
|
1609 zwarnnam(nam, "missing argument for option: %s", |
|
1610 d->name, 0); |
|
1611 return 1; |
|
1612 } |
|
1613 add_opt_val(d, *++pp); |
|
1614 } else |
|
1615 add_opt_val(d, NULL); |
|
1616 } else |
|
1617 add_opt_val(d, NULL); |
|
1618 } |
|
1619 } |
|
1620 if (extract && del) |
|
1621 while (*pp) |
|
1622 *cp++ = *pp++; |
|
1623 |
|
1624 for (a = opt_arrs; a; a = a->next) { |
|
1625 if (!keep || a->num) { |
|
1626 aval = (char **) zalloc((a->num + 1) * sizeof(char *)); |
|
1627 for (ap = aval, v = a->vals; v; ap++, v = v->next) { |
|
1628 if (v->str) |
|
1629 *ap = ztrdup(v->str); |
|
1630 else { |
|
1631 *ap = ztrdup(v->name); |
|
1632 if (v->arg) |
|
1633 *++ap = ztrdup(v->arg); |
|
1634 } |
|
1635 } |
|
1636 *ap = NULL; |
|
1637 setaparam(a->name, aval); |
|
1638 } |
|
1639 } |
|
1640 if (assoc) { |
|
1641 int num; |
|
1642 |
|
1643 for (num = 0, d = opt_descs; d; d = d->next) |
|
1644 if (d->vals) |
|
1645 num++; |
|
1646 |
|
1647 if (!keep || num) { |
|
1648 aval = (char **) zalloc(((num * 2) + 1) * sizeof(char *)); |
|
1649 for (ap = aval, d = opt_descs; d; d = d->next) { |
|
1650 if (d->vals) { |
|
1651 *ap++ = n = (char *) zalloc(strlen(d->name) + 2); |
|
1652 *n = '-'; |
|
1653 strcpy(n + 1, d->name); |
|
1654 |
|
1655 for (num = 1, v = d->vals; v; v = v->onext) { |
|
1656 num += (v->arg ? strlen(v->arg) : 0); |
|
1657 if (v->next) |
|
1658 num++; |
|
1659 } |
|
1660 *ap++ = n = (char *) zalloc(num); |
|
1661 for (v = d->vals; v; v = v->onext) { |
|
1662 if (v->arg) { |
|
1663 strcpy(n, v->arg); |
|
1664 n += strlen(v->arg); |
|
1665 } |
|
1666 *n = ' '; |
|
1667 } |
|
1668 *n = '\0'; |
|
1669 } |
|
1670 } |
|
1671 *ap = NULL; |
|
1672 sethparam(assoc, aval); |
|
1673 } |
|
1674 } |
|
1675 if (del) { |
|
1676 if (extract) { |
|
1677 *cp = NULL; |
|
1678 freearray(pparams); |
|
1679 pparams = zarrdup(np); |
|
1680 } else { |
|
1681 pp = zarrdup(pp); |
|
1682 freearray(pparams); |
|
1683 pparams = pp; |
|
1684 } |
|
1685 } |
|
1686 return 0; |
|
1687 } |
|
1688 |
|
1689 static struct builtin bintab[] = { |
|
1690 BUILTIN("zstyle", 0, bin_zstyle, 0, -1, 0, NULL, NULL), |
|
1691 BUILTIN("zformat", 0, bin_zformat, 3, -1, 0, NULL, NULL), |
|
1692 BUILTIN("zregexparse", 0, bin_zregexparse, 3, -1, 0, "c", NULL), |
|
1693 BUILTIN("zparseopts", 0, bin_zparseopts, 1, -1, 0, NULL, NULL), |
|
1694 }; |
|
1695 |
|
1696 |
|
1697 /**/ |
|
1698 int |
|
1699 setup_(UNUSED(Module m)) |
|
1700 { |
|
1701 zstyles = zlstyles = NULL; |
|
1702 |
|
1703 return 0; |
|
1704 } |
|
1705 |
|
1706 /**/ |
|
1707 int |
|
1708 boot_(Module m) |
|
1709 { |
|
1710 return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); |
|
1711 } |
|
1712 |
|
1713 /**/ |
|
1714 int |
|
1715 cleanup_(Module m) |
|
1716 { |
|
1717 deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); |
|
1718 return 0; |
|
1719 } |
|
1720 |
|
1721 /**/ |
|
1722 int |
|
1723 finish_(UNUSED(Module m)) |
|
1724 { |
|
1725 freeallstyles(); |
|
1726 |
|
1727 return 0; |
|
1728 } |
|
1729 |
|
1730 #endif //__SYMBIAN32__ |