History

20090417-2329

Charles.Forsyth committed 17 years ago

Commit cef63c51 parent 391d9036 files · +1141 −2Browse files

Unified · Split

6 files
  1. CHANGES +2 −0
  2. appl/cmd/m4.b +899 −0
  3. appl/cmd/mkfile +6 −1
  4. dis/m4.dis +0 −0
  5. lib/proto/inferno +2 −2
  6. man/1/m4 +233 −0
CHANGES+2−0
@@ -1,3 +1,5 @@
120090417
2 add m4(1) in its initial form (might split the macro processing proper off into a library module)
120090409320090409
2 tools/odbc/odbc.c data read should return 0 if no columns or rows (issue 170)4 tools/odbc/odbc.c data read should return 0 if no columns or rows (issue 170)
320090408520090408
appl/cmd/m4.b+899−0
@@ -0,0 +1,899 @@
1implement M4;
2
3include "sys.m";
4 sys: Sys;
5
6include "draw.m";
7
8include "bufio.m";
9 bufio: Bufio;
10 Iobuf: import bufio;
11
12include "arg.m";
13
14M4: module
15{
16 init: fn(nil: ref Draw->Context, nil: list of string);
17};
18
19NHASH: con 131;
20
21Name: adt {
22 name: string;
23 repl: string;
24 impl: ref fn(nil: array of string);
25 dol: int; # repl contains $[0-9]
26
27 text: fn(n: self ref Name): string;
28};
29
30names := array[NHASH] of list of ref Name;
31
32File: adt {
33 name: string;
34 line: int;
35 fp: ref Iobuf;
36};
37
38Param: adt {
39 s: string;
40};
41
42pushedback: string;
43pushedp := 0; # next available index in pushedback
44diverted := array[10] of string;
45curdiv := 0;
46curarg: ref Param; # non-nil if collecting argument string
47instack: list of ref File;
48lquote := '`';
49rquote := '\'';
50initcom := "#";
51endcom := "\n";
52bout: ref Iobuf;
53
54init(nil: ref Draw->Context, args: list of string)
55{
56 sys = load Sys Sys->PATH;
57 bufio = load Bufio Bufio->PATH;
58
59 bout = bufio->fopen(sys->fildes(1), Sys->OWRITE);
60
61 define("inferno", "inferno");
62
63 builtin("changecom", dochangecom);
64 builtin("changequote", dochangequote);
65 builtin("define", dodefine);
66 builtin("divert", dodivert);
67 builtin("divnum", dodivnum);
68 builtin("dnl", dodnl);
69 builtin("dumpdef", dodumpdef);
70 builtin("errprint", doerrprint);
71 builtin("eval", doeval);
72 builtin("ifdef", doifdef);
73 builtin("ifelse", doifelse);
74 builtin("include", doinclude);
75 builtin("incr", doincr);
76 builtin("index", doindex);
77 builtin("len", dolen);
78 builtin("maketemp", domaketemp);
79 builtin("sinclude", dosinclude);
80 builtin("substr", dosubstr);
81 builtin("translit", dotranslit);
82 builtin("undefine", doundefine);
83 builtin("undivert", doundivert);
84
85 arg := load Arg Arg->PATH;
86 arg->setusage("m4 [-Dname[=value]] [-Uname] [file ...]");
87 arg->init(args);
88
89 while((o := arg->opt()) != 0){
90 case o {
91 'D' =>
92 s := arg->earg();
93 for(i := 0; i < len s; i++)
94 if(s[i] == '='){
95 define(s[0: i], s[i+1:]);
96 break;
97 }
98 if(i == len s)
99 define(s[0: i], "");
100 'U' =>
101 undefine(arg->earg());
102 * =>
103 arg->usage();
104 }
105 }
106 args = arg->argv();
107 arg = nil;
108
109 if(args != nil){
110 for(; args != nil; args = tl args){
111 f := bufio->open(hd args, Sys->OREAD);
112 if(f == nil)
113 error(sys->sprint("can't open %s: %r", hd args));
114 pushfile(hd args, f);
115 scan();
116 }
117 }else{
118 pushfile("standard input", bufio->fopen(sys->fildes(0), Sys->OREAD));
119 scan();
120 }
121 bout.flush();
122}
123
124scan()
125{
126 while((c := getc()) >= 0){
127 if(isalpha(c))
128 called(c);
129 else if(c == lquote)
130 quoted();
131 else if(initcom != nil && initcom[0] == c)
132 comment();
133 else
134 putc(c);
135 }
136}
137
138error(s: string)
139{
140 where := "";
141 if(instack != nil){
142 ios := hd instack;
143 where = sys->sprint(" %s:%d:", ios.name, ios.line);
144 }
145 sys->fprint(sys->fildes(2), "m4:%s %s\n", where, s);
146 raise "fail:error";
147}
148
149pushfile(name: string, fp: ref Iobuf)
150{
151 instack = ref File(name, 1, fp) :: instack;
152}
153
154called(c: int)
155{
156 tok: string;
157 do{
158 tok[len tok] = c;
159 c = getc();
160 }while(isalpha(c) || c >= '0' && c <= '9');
161 def := lookup(tok);
162 if(def == nil){
163 pushc(c);
164 puts(tok);
165 return;
166 }
167 if(c != '('){ # no parameters
168 pushc(c);
169 expand(def, array[] of {tok});
170 return;
171 }
172 # collect arguments, allowing for nested parentheses;
173 # on ')' expand definition, further expanding $n references therein
174 argstack := def.name :: nil; # $0
175 savearg := curarg; # save parameter (if any) for outer call
176 curarg = ref Param("");
177 nesting := 0; # () depth
178 skipws();
179 for(;;){
180 if((c = getc()) < 0)
181 error("EOF in parameters");
182 if(isalpha(c))
183 called(c);
184 else if(c == lquote)
185 quoted();
186 else{
187 if(c == '(')
188 nesting++;
189 if(nesting > 0){
190 if(c == ')')
191 nesting--;
192 putc(c);
193 }else if(c == ','){
194 argstack = curarg.s :: argstack;
195 curarg = ref Param("");
196 skipws();
197 }else if(c == ')')
198 break;
199 else
200 putc(c);
201 }
202 }
203 argstack = curarg.s :: argstack;
204 curarg = savearg; # restore outer parameter (if any)
205 # build arguments
206 narg := len argstack;
207 args := array[narg] of string;
208 for(; argstack != nil; argstack = tl argstack)
209 args[--narg] = hd argstack;
210 expand(def, args);
211}
212
213quoted()
214{
215 nesting :=0;
216 while((c := getc()) != rquote || nesting > 0){
217 if(c < 0)
218 error("EOF in string");
219 if(c == rquote)
220 nesting--;
221 else if(c == lquote)
222 nesting++;
223 putc(c);
224 }
225}
226
227comment()
228{
229 for(i := 1; i < len initcom; i++){
230 if((c := getc()) != initcom[i]){
231 if(c < 0)
232 error("EOF in comment");
233 pushc(c);
234 pushs(initcom[1: i]);
235 putc(initcom[0]);
236 return;
237 }
238 }
239 puts(initcom);
240 for(i = 0; i < len endcom;){
241 c := getc();
242 if(c < 0)
243 error("EOF in comment");
244 putc(c);
245 if(c == endcom[i])
246 i++;
247 else
248 i = c == endcom[0];
249 }
250}
251
252skipws()
253{
254 while(isspace(c := getc()))
255 {}
256 pushc(c);
257}
258
259isspace(c: int): int
260{
261 return c == ' ' || c == '\t' || c == '\n' || c == '\r';
262}
263
264isname(s: string): int
265{
266 if(s == nil || !isalpha(s[0]))
267 return 0;
268 for(i := 1; i < len s; i++)
269 if(!(isalpha(s[i]) || s[i]>='0' && s[i]<='9'))
270 return 0;
271 return 1;
272}
273
274isalpha(c: int): int
275{
276 return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_' || c > 16r80;
277}
278
279hash(name: string): int
280{
281 h := 0;
282 for(i := 0; i < len name; i++)
283 h = h*65599 + name[i];
284 return (h & ~(1<<31)) % NHASH;
285}
286
287builtin(name: string, impl: ref fn(nil: array of string))
288{
289 h := hash(name);
290 n := ref Name(name, nil, impl, 0);
291 names[h] = n :: names[h];
292}
293
294define(name: string, repl: string)
295{
296 h := hash(name);
297 dol := hasdol(repl);
298 for(l := names[h]; l != nil; l = tl l){
299 n := hd l;
300 if(n.name == name){
301 n.impl = nil;
302 n.repl = repl;
303 n.dol = dol;
304 return;
305 }
306 }
307 n := ref Name(name, repl, nil, dol);
308 names[h] = n :: names[h];
309}
310
311lookup(name: string): ref Name
312{
313 h := hash(name);
314 for(l := names[h]; l != nil; l = tl l)
315 if((hd l).name == name)
316 return hd l;
317 return nil;
318}
319
320undefine(name: string)
321{
322 h := hash(name);
323 rl: list of ref Name;
324 for(l := names[h]; l != nil; l = tl l){
325 if((hd l).name == name){
326 l = tl l;
327 for(; rl != nil; rl = tl rl)
328 l = hd rl :: l;
329 names[h] = l;
330 return;
331 }else
332 rl = hd l :: rl;
333 }
334}
335
336Name.text(n: self ref Name): string
337{
338 if(n.impl != nil)
339 return sys->sprint("builtin %q", n.name);
340 return sys->sprint("%c%s%c", lquote, n.repl, rquote);
341}
342
343dodumpdef(args: array of string)
344{
345 if(len args > 1){
346 for(i := 1; i < len args; i++)
347 if((n := lookup(args[i])) != nil)
348 sys->fprint(sys->fildes(2), "%q %s\n", n.name, n.text());
349 }else{
350 for(i := 0; i < len names; i++)
351 for(l := names[i]; l != nil; l = tl l)
352 sys->fprint(sys->fildes(2), "%q %s\n", (hd l).name, (hd l).text());
353 }
354}
355
356pushs(s: string)
357{
358 for(i := len s; --i >= 0;)
359 pushedback[pushedp++] = s[i];
360}
361
362pushc(c: int)
363{
364 if(c >= 0)
365 pushedback[pushedp++] = c;
366}
367
368getc(): int
369{
370 if(pushedp > 0)
371 return pushedback[--pushedp];
372 for(; instack != nil; instack = tl instack){
373 ios := hd instack;
374 c := ios.fp.getc();
375 if(c >= 0){
376 if(c == '\n')
377 ios.line++;
378 return c;
379 }
380 }
381 return -1;
382}
383
384puts(s: string)
385{
386 if(curarg != nil)
387 curarg.s += s;
388 else if(curdiv > 0)
389 diverted[curdiv] += s;
390 else if(curdiv == 0)
391 bout.puts(s);
392}
393
394putc(c: int)
395{
396 if(curarg != nil){
397 # stow in argument collection buffer
398 curarg.s[len curarg.s] = c;
399 }else if(curdiv > 0){
400 l := len diverted[curdiv];
401 diverted[curdiv][l] = c;
402 }else if(curdiv == 0)
403 bout.putc(c);
404}
405
406expand(def: ref Name, args: array of string)
407{
408 if(def.impl != nil){
409 def.impl(args);
410 return;
411 }
412 if(def.repl == def.name || def.repl == "$0"){
413 puts(def.name);
414 return;
415 }
416 if(!def.dol || def.repl == nil){
417 pushs(def.repl);
418 return;
419 }
420 # expand $n
421 s := def.repl;
422 for(i := len s; --i >= 1;){
423 if(s[i-1] == '$' && (c := s[i]-'0') >= 0 && c <= 9){
424 if(c < len args)
425 pushs(args[c]);
426 i--;
427 }else
428 pushc(s[i]);
429 }
430 if(i >= 0)
431 pushc(s[0]);
432}
433
434hasdol(s: string): int
435{
436 for(i := 0; i < len s; i++)
437 if(s[i] == '$')
438 return 1;
439 return 0;
440}
441
442dodefine(args: array of string)
443{
444 if(len args > 2)
445 define(args[1], args[2]);
446 else if(len args > 1)
447 define(args[1], "");
448}
449
450doundefine(args: array of string)
451{
452 for(i := 1; i < len args; i++)
453 undefine(args[i]);
454}
455
456doeval(args: array of string)
457{
458 if(len args > 1)
459 pushs(string eval(args[1]));
460}
461
462dodivert(args: array of string)
463{
464 if(len args > 1){
465 n := int args[1];
466 if(n < 0 || n >= len diverted)
467 n = -1;
468 curdiv = n;
469 }else
470 curdiv = 0;
471}
472
473dodivnum(nil: array of string)
474{
475 pushs(string curdiv);
476}
477
478doundivert(args: array of string)
479{
480 if(len args <= 1){ # do all but current, in order
481 for(i := 1; i < len diverted; i++){
482 if(i != curdiv){
483 puts(diverted[i]);
484 diverted[i] = nil;
485 }
486 }
487 }else{ # do those specified
488 for(i := 1; i < len args; i++){
489 n := int args[i];
490 if(n > 0 && n < len diverted && n != curdiv){
491 puts(diverted[n]);
492 diverted[n] = nil;
493 }
494 }
495 }
496}
497
498doifdef(args: array of string)
499{
500 if(len args < 2)
501 return;
502 n := lookup(args[1]);
503 if(n != nil)
504 pushs(args[2]);
505 else if(len args > 2)
506 pushs(args[3]);
507}
508
509doifelse(args: array of string)
510{
511 for(i := 1; i+2 < len args; i += 3){
512 if(args[i] == args[i+1]){
513 pushs(args[i+2]);
514 return;
515 }
516 }
517 if(i > 2 && i == len args-1)
518 pushs(args[i]);
519}
520
521doincr(args: array of string)
522{
523 if(len args > 1)
524 pushs(string (int args[1] + 1));
525}
526
527doindex(args: array of string)
528{
529 if(len args > 2){
530 a := args[1];
531 b := args[2];
532 for(i := 0; i+len b <= len a; i++){
533 if(a[i: i+len b] == b){
534 pushs(string i);
535 return;
536 }
537 }
538 pushs("-1");
539 }
540}
541
542doinclude(args: array of string)
543{
544 for(i := len args; --i >= 1;){
545 fp := bufio->open(args[i], Sys->OREAD);
546 if(fp == nil)
547 error(sys->sprint("can't open %s: %r", args[i]));
548 pushfile(args[i], fp);
549 }
550}
551
552dosinclude(args: array of string)
553{
554 for(i := len args; --i >= 1;){
555 fp := bufio->open(args[i], Sys->OREAD);
556 if(fp != nil)
557 pushfile(args[i], fp);
558 }
559}
560
561clip(v, l, u: int): int
562{
563 if(v < l)
564 return l;
565 if(v > u)
566 return u;
567 return v;
568}
569
570dosubstr(args: array of string)
571{
572 if(len args > 2){
573 l := len args[1];
574 o := clip(int args[2], 0, l);
575 n := l;
576 if(len args > 3)
577 n = clip(int args[3], 0, l);
578 if((n += o) > l)
579 n = l;
580 pushs(args[1][o: n]);
581 }
582}
583
584cindex(s: string, c: int): int
585{
586 for(i := 0; i < len s; i++)
587 if(s[i] == c)
588 return i;
589 return -1;
590}
591
592dotranslit(args: array of string)
593{
594 if(len args < 3)
595 return;
596 s := args[1];
597 f := args[2];
598 t := "";
599 if(len args > 3)
600 t = args[3];
601 o := "";
602 for(i := 0; i < len s; i++){
603 if((j := cindex(f, s[i])) >= 0){
604 if(j < len t)
605 o[len o] = t[j];
606 }else
607 o[len o] = s[i];
608 }
609 pushs(o);
610}
611
612doerrprint(args: array of string)
613{
614 s := "";
615 for(i := 1; i < len args; i++)
616 s += " "+args[i];
617 if(s != nil)
618 sys->fprint(sys->fildes(2), "m4:%s\n", s);
619}
620
621dolen(args: array of string)
622{
623 if(len args > 1)
624 puts(string len args[1]);
625}
626
627dochangecom(args: array of string)
628{
629 case len args {
630 1 =>
631 initcom = "";
632 endcom = "";
633 2 =>
634 initcom = args[1];
635 endcom = "\n";
636 * =>
637 initcom = args[1];
638 endcom = args[2];
639 if(endcom == "")
640 endcom = "\n";
641 }
642}
643
644dochangequote(args: array of string)
645{
646 case len args {
647 1 =>
648 lquote = '`';
649 rquote = '\'';
650 2 =>
651 if(args[1] != nil)
652 lquote = rquote = args[1][0];
653 * =>
654 if(args[1] != nil)
655 lquote = args[1][0];
656 if(args[2] != nil)
657 rquote = args[2][0];
658 }
659}
660
661dodnl(nil: array of string)
662{
663 while((c := getc()) >= 0 && c != '\n')
664 {}
665}
666
667domaketemp(args: array of string)
668{
669 if(len args > 1)
670 pushs(mktemp(args[1]));
671}
672
673sysname: string;
674
675mktemp(s: string): string
676{
677 if(sysname == nil)
678 sysname = readfile("/dev/sysname", "m4");
679 # trim trailing X's
680 for (x := len s; --x >= 0;)
681 if(s[x] == 'X'){
682 while(x > 0 && s[x-1] == 'X')
683 x--;
684 s = s[0: x];
685 break;
686 }
687 # add system name, process ID and 'a'
688 s += sys->sprint(".%s.%.10uda", sysname, sys->pctl(0, nil));
689 while(sys->stat(s).t0 >= 0){
690 if(s[len s-1] == 'z')
691 error("out of temp files: "+s);
692 s[len s-1]++;
693 }
694 return s;
695}
696
697readfile(name: string, default: string): string
698{
699 fd := sys->open(name, Sys->OREAD);
700 if(fd == nil)
701 return default;
702 buf := array[Sys->NAMEMAX] of byte;
703 n := sys->read(fd, buf, len buf);
704 if(n <= 0)
705 return default;
706 return string buf[0: n];
707}
708
709#
710# expressions provided use Limbo operators (C with signed shift and **),
711# instead of original m4 ones (where | and & were || and &&, and ^ was power),
712# but that's true of later unix m4 implementations too
713#
714
715Oeof, Ogok, Oge, Ole, One, Oeq, Opow, Oand, Oor, Orsh, Olsh, Odigits: con 'a'+iota;
716Syntax, Badeval: exception;
717evalin: string;
718evalp := 0;
719
720eval(s: string): int
721{
722 evalin = s;
723 evalp = 0;
724 looked = -1;
725 {
726 v := expr(1);
727 if(evalp < len evalin)
728 raise Syntax;
729 return v;
730 }exception{
731 Syntax =>
732 error(sys->sprint("syntax error: %q %q", evalin[0: evalp], evalin[evalp:]));
733 return 0;
734 Badeval =>
735 error(sys->sprint("zero divide in %q", evalin));
736 return 0;
737 }
738}
739
740eval1(op: int, v1, v2: int): int raises Badeval
741{
742 case op{
743 '+' => return v1 + v2;
744 '-' => return v1 - v2;
745 '*' => return v1 * v2;
746 '%' =>
747 if(v2 == 0)
748 raise Badeval; # division by zero
749 return v1 % v2;
750 '/' =>
751 if(v2 == 0)
752 raise Badeval; # division by zero
753 return v1 / v2;
754 Opow =>
755 if(v2 < 0)
756 raise Badeval;
757 return v1 ** v2;
758 '&' => return v1 & v2;
759 '|' => return v1 | v2;
760 '^' => return v1 ^ v2;
761 Olsh => return v1 << v2;
762 Orsh => return v1 >> v2;
763 Oand => return v1 && v2;
764 Oor => return v1 || v2;
765 '<' => return v1 < v2;
766 '>' => return v1 > v2;
767 Ole => return v1 <= v2;
768 Oge => return v1 >= v2;
769 One => return v1 != v2;
770 Oeq => return v1 == v2;
771 * =>
772 sys->print("unknown op: %c\n", op); # shouldn't happen
773 raise Badeval;
774 }
775}
776
777priority(c: int): int
778{
779 case c {
780 Oor => return 1;
781 Oand => return 2;
782 '|' => return 3;
783 '^' => return 4;
784 '&' => return 5;
785 Oeq or One => return 6;
786 '<' or '>' or Oge or Ole => return 7;
787 Olsh or Orsh => return 8;
788 '+' or '-' => return 9;
789 '*' or '/' or '%' => return 10;
790 Opow => return 11;
791 * => return 0;
792 }
793}
794
795rightassoc(c: int): int
796{
797 return c == Opow;
798}
799
800expr(prec: int): int raises(Syntax, Badeval)
801{
802 {
803 v := primary();
804 while(priority(look()) >= prec){
805 op := lex();
806 r := priority(op) + !rightassoc(op);
807 v = eval1(op, v, expr(r));
808 }
809 return v;
810 }exception{
811 Syntax or Badeval =>
812 raise;
813 }
814}
815
816primary(): int raises Syntax
817{
818 {
819 case lex() {
820 '(' =>
821 v := expr(1);
822 if(lex() != ')')
823 raise Syntax;
824 return v;
825 '+' =>
826 return primary();
827 '-' =>
828 return -primary();
829 '!' =>
830 return !primary();
831 '~' =>
832 return ~primary();
833 Odigits =>
834 return yylval;
835 * =>
836 raise Syntax;
837 }
838 }exception{
839 Syntax =>
840 raise;
841 }
842}
843
844yylval := 0;
845looked := -1;
846
847look(): int
848{
849 looked = lex();
850 return looked;
851}
852
853lex(): int
854{
855 if((c := looked) >= 0){
856 looked = -1;
857 return c; # if Odigits, assumes yylval untouched
858 }
859 while(evalp < len evalin && isspace(evalin[evalp]))
860 evalp++;
861 if(evalp >= len evalin)
862 return Oeof;
863 case c = evalin[evalp++] {
864 '*' =>
865 return ifnext('*', Opow, '*');
866 '>' =>
867 return ifnext('=', Oge, ifnext('>', Orsh, '>'));
868 '<' =>
869 return ifnext('=', Ole, ifnext('<', Olsh, '<'));
870 '=' =>
871 return ifnext('=', Oeq, Oeq);
872 '!' =>
873 return ifnext('=', One, '!');
874 '|' =>
875 return ifnext('|', Oor, '|');
876 '&' =>
877 return ifnext('&', Oand, '&');
878 '0' to '9' =>
879 evalp--;
880 n := 0;
881 while(evalp < len evalin && (c = evalin[evalp]) >= '0' && c <= '9'){
882 n = n*10 + (c-'0');
883 evalp++;
884 }
885 yylval = n;
886 return Odigits;
887 * =>
888 return c;
889 }
890}
891
892ifnext(a, t, f: int): int
893{
894 if(evalp < len evalin && evalin[evalp] == a){
895 evalp++;
896 return t;
897 }
898 return f;
899}
appl/cmd/mkfile+6−1
@@ -5,6 +5,7 @@ DIRS=\ · 4 unmodified lines
5 auxi\5 auxi\
6 avr\6 avr\
7 disk\7 disk\
8 fs\
8 install\9 install\
9 ip\10 ip\
10 lego\11 lego\
@@ -13,8 +14,11 @@ DIRS=\ · 2 unmodified lines
13 mk\14 mk\
14 mpc\15 mpc\
15 ndb\16 ndb\
17 owen\
18 scheduler\
16 sh\19 sh\
17 spki\20 spki\
21 ssh\
18 usb\22 usb\
19 23
20TARG=\24TARG=\
@@ -88,6 +92,7 @@ TARG=\ · 67 unmodified lines
88 look.dis\92 look.dis\
89 ls.dis\93 ls.dis\
90 lstar.dis\94 lstar.dis\
95 m4.dis\
91 man2html.dis\96 man2html.dis\
92 man2txt.dis\97 man2txt.dis\
93 mc.dis\98 mc.dis\
@@ -153,6 +158,7 @@ TARG=\ · 59 unmodified lines
153 touchcal.dis\158 touchcal.dis\
154 tokenize.dis\159 tokenize.dis\
155 tr.dis\160 tr.dis\
161 trfs.dis\
156 tsort.dis\162 tsort.dis\
157 unicode.dis\163 unicode.dis\
158 units.dis\164 units.dis\
@@ -171,7 +177,6 @@ TARG=\ · 12 unmodified lines
171 wmimport.dis\177 wmimport.dis\
172 xargs.dis\178 xargs.dis\
173 xd.dis\179 xd.dis\
174 xmount.dis\
175 yacc.dis\180 yacc.dis\
176 zeros.dis\181 zeros.dis\
177 182
dis/m4.dis+0−0

Binary file not shown.

lib/proto/inferno+2−2
@@ -614,6 +614,7 @@ appl · 613 unmodified lines
614 look.b614 look.b
615 ls.b615 ls.b
616 lstar.b616 lstar.b
617 m4.b
617 man2html.b618 man2html.b
618 man2txt.b619 man2txt.b
619 manufacture.b620 manufacture.b
@@ -1242,8 +1243,6 @@ appl · 622 unmodified lines
1242 spider.b1243 spider.b
1243 spit.b1244 spit.b
1244 whist.b1245 whist.b
1245 man
1246 +
1247 lib1246 lib
1248 allow.b1247 allow.b
1249 allow.m1248 allow.m
@@ -1755,6 +1754,7 @@ dis · 505 unmodified lines
1755 lookman1754 lookman
1756 ls.dis1755 ls.dis
1757 lstar.dis1756 lstar.dis
1757 m4.dis
1758 man1758 man
1759 man2html.dis1759 man2html.dis
1760 man2txt.dis1760 man2txt.dis
man/1/m4+233−0
@@ -0,0 +1,233 @@
1.TH M4 1
2.SH NAME
3m4 \- macro processor
4.SH SYNOPSIS
5.B m4
6[
7.BI -D name = value
8] [
9.BI -U name
10] [
11.I file
12\&...
13]
14.SH DESCRIPTION
15.I M4
16is a general-purpose macro processor.
17It copies text from each of the input
18.I files
19in order (or standard input by default), and writes the processed text to the standard output.
20.PP
21Macro calls
22have the form
23.IP
24.IB name ( arg1,\ arg2,\ ...,\ argn )
25.PP
26The `(' must immediately follow the name of the macro.
27If a defined macro name is not followed by a `(',
28it is deemed to have no arguments.
29Leading unquoted blanks, tabs, and newlines are ignored while collecting arguments.
30A comma within a nested parenthesis is part of an argument value, not an argument separator.
31Potential macro names consist of alphabetic letters, Unicode characters,
32digits, and underscore `\_', where the first character is not a digit.
33.PP
34The left and right single quotes(ie, grave and acute accents \`\|\' ) are used to quote strings.
35Because the left and right quotes are distinct, quoted strings may nest.
36The value of a quoted string is the string stripped of the outermost quotes.
37.PP
38When
39.I m4
40recognises a macro name, followed by a `(', it collects arguments up to a matching right parenthesis.
41Macro evaluation proceeds normally during this collection, and the text produced by those macro calls
42is interpreted exactly as if it had been in the original input stream (in place of the corresponding macro call).
43Thus, any commas or right parentheses within the value of a nested
44call are as effective as those in the original input text.
45(Remember however that commas within
46.I nested
47parentheses are not argument separators.)
48After argument collection,
49the value of the macro is pushed back onto the input stream
50and rescanned.
51.PP
52.I M4
53makes available the following built-in macros.
54They may be redefined, but once this is done the original meaning is lost.
55Their values are null unless otherwise stated.
56.TF changequote
57.TP
58changecom
59Change the starting and ending delimiters for subsequent comments to the first and second arguments.
60If the second argument is missing or an empty string, comments will be ended by newline.
61If there are no arguments, there are no comments.
62.TP
63changequote
64Change quote characters to the first and second arguments.
65.I Changequote
66without arguments restores the original values of
67.BR `\|' .
68.TP
69define
70The second argument is installed as the value of the macro
71whose name is the first argument.
72When the macro is later called (expanded),
73each occurrence in the replacement text of
74.BI $ n,
75where
76.I n
77is a digit,
78is replaced by the
79.IR n -th
80argument of that macro call.
81Argument 0 is the name of the macro;
82missing arguments are replaced by the null string.
83If the macro value is the same as its name, or the value is simply
84.BR $0 ,
85the result is the macro name.
86.TP
87divert
88.I M4
89maintains 10 output streams,
90numbered 0-9.
91The final output is the concatenation of the streams
92in numerical order;
93initially stream 0 is the current stream.
94The
95.I divert
96macro changes the current output stream to its (digit-string)
97argument.
98Output diverted to a stream other than 0 through 9
99is discarded.
100.TP
101divnum
102Returns the value of the current output stream.
103.TP
104dnl
105Reads and discards characters up to and including the next newline.
106.TP
107dumpdef
108Prints current names and definitions,
109for the named items, or for all if no arguments are given.
110.TP
111errprint
112Prints its argument
113on the diagnostic output file.
114.TP
115eval
116Evaluates its argument as an arithmetic expression, using 32-bit arithmetic.
117Operators are those of Limbo: the binary operators
118.BR || ,
119.BR && ,
120.BR | ,
121.BR ^ ,
122.BR & ,
123.BR "== !=" ,
124.BR "< > >= <=" ,
125.B "<< >>"
126(arithmetic shifts),
127.BR "+ -" ,
128.BR "* / %" ,
129.BR "**" " (power)";
130the unary operators
131.BR + ,
132.BR - ,
133.BR ~ ,
134.BR ! ;
135and parenthesis.
136The operator precedence is the same as in Limbo.
137Right shifts are signed.
138.TP
139ifdef
140If the first argument is defined, the value is the second argument, otherwise the third.
141If there is no third argument, the value is null.
142The word
143.B inferno
144is predefined with
145.RB ` inferno '
146as its replacement text.
147.TP
148ifelse
149Has three or more arguments.
150If the first argument is the same string as the second,
151then the value is the third argument.
152If not, the process is repeated with arguments 4, 5, 6 and so on, in groups of three.
153If no match is found, the result is the remaining argument (not part of a group of three),
154or null if none is present.
155.TP
156include
157Returns the contents of the file named in the argument.
158.TP
159incr
160Returns the value of its argument incremented by 1.
161The value of the argument is calculated
162by interpreting an initial digit-string as a decimal number.
163.TP
164index
165Returns the position in its first argument where the second argument begins (zero origin),
166or \-1 if the second argument does not occur.
167.TP
168len
169Returns the number of characters in its argument.
170.TP
171maketemp
172Returns its first argument after replacing any trailing XXXs by the current host name, process ID, and a unique letter.
173Normally used to create unique temporary file names.
174.TP
175sinclude
176The same as
177.I include,
178except that it
179says nothing if the file is inaccessible.
180.TP
181substr
182Returns a substring of its first argument.
183The second argument is a zero origin
184number selecting the first character;
185the third argument indicates the length of the substring.
186A missing third argument is taken to be large enough to extend to
187the end of the first string.
188\" .TP
189\" syscmd
190\" executes the shell command given in the first argument.
191\" No value is returned.
192.TP
193translit
194Transliterates the characters in its first argument
195from the set given by the second argument to the set given by the third.
196No abbreviations are permitted.
197.TP
198undefine
199Removes the definition of the macro named in its argument.
200.TP
201undivert
202Causes immediate output of text from diversions named as
203arguments, or all diversions if no argument.
204Text may be undiverted into another diversion.
205Undiverting discards the diverted text.
206.PD
207.PP
208.I M4
209interprets the
210.B -D
211and
212.B -U
213command line options after installing the predefined macro set.
214The
215.B -D
216option defines
217.I name
218as a macro with the given
219.IR value .
220The
221.B -U
222option
223.I undefines
224the given macro
225.IR name ,
226which may be one of the predefined macros.
227.PP
228.I M4
229in Inferno is more closely related to the original version in Seventh Edition UNIX
230than the more elaborate relatives in System V and POSIX.
231.SH "SEE ALSO"
232B. W. Kernighan and D. M. Ritchie,
233.I The M4 Macro Processor