]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/troff/n4.c
ip/ipconfig: format ipmask with %M instead of %I
[plan9front.git] / sys / src / cmd / troff / n4.c
1 /*
2  * troff4.c
3  *
4  * number registers, conversion, arithmetic
5  */
6
7 #include "tdef.h"
8 #include "fns.h"
9 #include "ext.h"
10
11
12 int     regcnt = NNAMES;
13 int     falsef  = 0;    /* on if inside false branch of if */
14
15 #define NHASHSIZE       128     /* must be 2**n */
16 #define NHASH(i)        ((i>>6)^i) & (NHASHSIZE-1)
17 Numtab  *nhash[NHASHSIZE];
18
19 Numtab *numtabp = NULL;
20 #define NDELTA 400
21 int ncnt = 0;
22
23 void setn(void)
24 {
25         int i, j, f;
26         Tchar ii;
27         Uchar *p;
28         char buf[NTM];          /* for \n(.S */
29
30         f = nform = 0;
31         if ((i = cbits(ii = getach())) == '+')
32                 f = 1;
33         else if (i == '-')
34                 f = -1;
35         else if (ii)    /* don't put it back if it's already back (thanks to jaap) */
36                 ch = ii;
37         if (falsef)
38                 f = 0;
39         if ((i = getsn()) == 0)
40                 return;
41         p = unpair(i);
42         if (p[0] == '.')
43                 switch (p[1]) {
44                 case 's':
45                         i = pts;
46                         break;
47                 case 'v':
48                         i = lss;
49                         break;
50                 case 'f':
51                         i = font;
52                         break;
53                 case 'p':
54                         i = pl;
55                         break;
56                 case 't':
57                         i = findt1();
58                         break;
59                 case 'o':
60                         i = po;
61                         break;
62                 case 'l':
63                         i = ll;
64                         break;
65                 case 'i':
66                         i = in;
67                         break;
68                 case '$':
69                         i = frame->nargs;
70                         break;
71                 case 'A':
72                         i = ascii;
73                         break;
74                 case 'c':
75                         i = numtabp[CD].val;
76                         break;
77                 case 'n':
78                         i = lastl;
79                         break;
80                 case 'a':
81                         i = ralss;
82                         break;
83                 case 'h':
84                         i = dip->hnl;
85                         break;
86                 case 'd':
87                         if (dip != d)
88                                 i = dip->dnl;
89                         else
90                                 i = numtabp[NL].val;
91                         break;
92                 case 'u':
93                         i = fi;
94                         break;
95                 case 'j':
96                         i = ad + 2 * admod;
97                         break;
98                 case 'w':
99                         i = widthp;
100                         break;
101                 case 'x':
102                         i = nel;
103                         break;
104                 case 'y':
105                         i = un;
106                         break;
107                 case 'T':
108                         i = dotT;
109                         break;   /* -Tterm used in nroff */
110                 case 'V':
111                         i = VERT;
112                         break;
113                 case 'H':
114                         i = HOR;
115                         break;
116                 case 'k':
117                         i = ne;
118                         break;
119                 case 'P':
120                         i = print;
121                         break;
122                 case 'L':
123                         i = ls;
124                         break;
125                 case 'R':       /* maximal # of regs that can be addressed */
126                         i = 255*256 - regcnt; 
127                         break;
128                 case 'z':
129                         p = unpair(dip->curd);
130                         *pbp++ = p[1];  /* watch order */
131                         *pbp++ = p[0];
132                         return;
133                 case 'b':
134                         i = bdtab[font];
135                         break;
136                 case 'F':
137                         cpushback(cfname[ifi]);
138                         return;
139                 case 'S':
140                         buf[0] = j = 0; 
141                         for( i = 0; tabtab[i] != 0 && i < NTAB; i++) {
142                                 if (i > 0)
143                                         buf[j++] = ' ';
144                                 sprintf(&buf[j], "%d", tabtab[i] & TABMASK);
145                                 j = strlen(buf);
146                                 if ( tabtab[i] & RTAB)
147                                         sprintf(&buf[j], "uR");
148                                 else if (tabtab[i] & CTAB)
149                                         sprintf(&buf[j], "uC");
150                                 else
151                                         sprintf(&buf[j], "uL");
152                                 j += 2;
153                         }
154                         cpushback(buf);
155                         return;
156                 default:
157                         goto s0;
158                 }
159         else {
160 s0:
161                 if ((j = findr(i)) == -1)
162                         i = 0;
163                 else {
164                         i = numtabp[j].val = numtabp[j].val + numtabp[j].inc * f;
165                         nform = numtabp[j].fmt;
166                 }
167         }
168         setn1(i, nform, (Tchar) 0);
169 }
170
171 Tchar   numbuf[25];
172 Tchar   *numbufp;
173
174 int wrc(Tchar i)
175 {
176         if (numbufp >= &numbuf[24])
177                 return(0);
178         *numbufp++ = i;
179         return(1);
180 }
181
182
183
184 /* insert into input number i, in format form, with size-font bits bits */
185 void setn1(int i, int form, Tchar bits)
186 {
187         numbufp = numbuf;
188         nrbits = bits;
189         nform = form;
190         fnumb(i, wrc);
191         *numbufp = 0;
192         pushback(numbuf);
193 }
194
195 void prnumtab(Numtab *p)
196 {
197         int i;
198         for (i = 0; i < ncnt; i++)
199                 if (p)
200                         if (p[i].r != 0)
201                                 fprintf(stderr, "slot %d, %s, val %d\n", i, unpair(p[i].r), p[i].val);
202                         else
203                                 fprintf(stderr, "slot %d empty\n", i);
204                 else
205                         fprintf(stderr, "slot %d empty\n", i);
206 }
207
208 void nnspace(void)
209 {
210         ncnt = sizeof(numtab)/sizeof(Numtab) + NDELTA;
211         numtabp = (Numtab *) grow((char *)numtabp, ncnt, sizeof(Numtab));
212         if (numtabp == NULL) {
213                 ERROR "not enough memory for registers (%d)", ncnt WARN;
214                 exit(1);
215         }
216         numtabp = (Numtab *) memcpy((char *)numtabp, (char *)numtab,
217                                                         sizeof(numtab));
218         if (numtabp == NULL) {
219                 ERROR "Cannot initialize registers" WARN;
220                 exit(1);
221         }
222 }
223
224 void grownumtab(void)
225 {
226         ncnt += NDELTA;
227         numtabp = (Numtab *) grow((char *) numtabp, ncnt, sizeof(Numtab));
228         if (numtabp == NULL) {
229                 ERROR "Too many number registers (%d)", ncnt WARN;
230                 done2(04);
231         } else {
232                 memset((char *)(numtabp) + (ncnt - NDELTA) * sizeof(Numtab),
233                                                 0, NDELTA * sizeof(Numtab));
234                 nrehash();
235         }
236 }
237
238 void nrehash(void)
239 {
240         Numtab *p;
241         int i;
242
243         for (i=0; i<NHASHSIZE; i++)
244                 nhash[i] = 0;
245         for (p=numtabp; p < &numtabp[ncnt]; p++)
246                 p->link = 0;
247         for (p=numtabp; p < &numtabp[ncnt]; p++) {
248                 if (p->r == 0)
249                         continue;
250                 i = NHASH(p->r);
251                 p->link = nhash[i];
252                 nhash[i] = p;
253         }
254 }
255
256 void nunhash(Numtab *rp)
257 {
258         Numtab *p;
259         Numtab **lp;
260
261         if (rp->r == 0)
262                 return;
263         lp = &nhash[NHASH(rp->r)];
264         p = *lp;
265         while (p) {
266                 if (p == rp) {
267                         *lp = p->link;
268                         p->link = 0;
269                         return;
270                 }
271                 lp = &p->link;
272                 p = p->link;
273         }
274 }
275
276 int findr(int i)
277 {
278         Numtab *p;
279         int h = NHASH(i);
280
281         if (i == 0)
282                 return(-1);
283 a0:
284         for (p = nhash[h]; p; p = p->link)
285                 if (i == p->r)
286                         return(p - numtabp);
287         for (p = numtabp; p < &numtabp[ncnt]; p++) {
288                 if (p->r == 0) {
289                         p->r = i;
290                         p->link = nhash[h];
291                         nhash[h] = p;
292                         regcnt++;
293                         return(p - numtabp);
294                 }
295         }
296         grownumtab();
297         goto a0;
298 }
299
300 int usedr(int i)        /* returns -1 if nr i has never been used */
301 {
302         Numtab *p;
303
304         if (i == 0)
305                 return(-1);
306         for (p = nhash[NHASH(i)]; p; p = p->link)
307                 if (i == p->r)
308                         return(p - numtabp);
309         return -1;
310 }
311
312
313 int fnumb(int i, int (*f)(Tchar))
314 {
315         int j;
316
317         j = 0;
318         if (i < 0) {
319                 j = (*f)('-' | nrbits);
320                 i = -i;
321         }
322         switch (nform) {
323         default:
324         case '1':
325         case 0:
326                 return decml(i, f) + j;
327         case 'i':
328         case 'I':
329                 return roman(i, f) + j;
330         case 'a':
331         case 'A':
332                 return abc(i, f) + j;
333         }
334 }
335
336
337 int decml(int i, int (*f)(Tchar))
338 {
339         int j, k;
340
341         k = 0;
342         nform--;
343         if ((j = i / 10) || (nform > 0))
344                 k = decml(j, f);
345         return(k + (*f)((i % 10 + '0') | nrbits));
346 }
347
348
349 int roman(int i, int (*f)(Tchar))
350 {
351
352         if (!i)
353                 return((*f)('0' | nrbits));
354         if (nform == 'i')
355                 return(roman0(i, f, "ixcmz", "vldw"));
356         else
357                 return(roman0(i, f, "IXCMZ", "VLDW"));
358 }
359
360
361 int roman0(int i, int (*f)(Tchar), char *onesp, char *fivesp)
362 {
363         int q, rem, k;
364
365         if (!i)
366                 return(0);
367         k = roman0(i / 10, f, onesp + 1, fivesp + 1);
368         q = (i = i % 10) / 5;
369         rem = i % 5;
370         if (rem == 4) {
371                 k += (*f)(*onesp | nrbits);
372                 if (q)
373                         i = *(onesp + 1);
374                 else
375                         i = *fivesp;
376                 return(k += (*f)(i | nrbits));
377         }
378         if (q)
379                 k += (*f)(*fivesp | nrbits);
380         while (--rem >= 0)
381                 k += (*f)(*onesp | nrbits);
382         return(k);
383 }
384
385
386 int abc(int i, int (*f)(Tchar))
387 {
388         if (!i)
389                 return((*f)('0' | nrbits));
390         else
391                 return(abc0(i - 1, f));
392 }
393
394
395 int abc0(int i, int (*f)(Tchar))
396 {
397         int j, k;
398
399         k = 0;
400         if (j = i / 26)
401                 k = abc0(j - 1, f);
402         return(k + (*f)((i % 26 + nform) | nrbits));
403 }
404
405 long atoi0(void)
406 {
407         int c, k, cnt;
408         Tchar ii;
409         long i, acc;
410
411         acc = 0;
412         nonumb = 0;
413         cnt = -1;
414 a0:
415         cnt++;
416         ii = getch();
417         c = cbits(ii);
418         switch (c) {
419         default:
420                 ch = ii;
421                 if (cnt)
422                         break;
423         case '+':
424                 i = ckph();
425                 if (nonumb)
426                         break;
427                 acc += i;
428                 goto a0;
429         case '-':
430                 i = ckph();
431                 if (nonumb)
432                         break;
433                 acc -= i;
434                 goto a0;
435         case '*':
436                 i = ckph();
437                 if (nonumb)
438                         break;
439                 acc *= i;
440                 goto a0;
441         case '/':
442                 i = ckph();
443                 if (nonumb)
444                         break;
445                 if (i == 0) {
446                         flusho();
447                         ERROR "divide by zero." WARN;
448                         acc = 0;
449                 } else
450                         acc /= i;
451                 goto a0;
452         case '%':
453                 i = ckph();
454                 if (nonumb)
455                         break;
456                 acc %= i;
457                 goto a0;
458         case '&':       /*and*/
459                 i = ckph();
460                 if (nonumb)
461                         break;
462                 if ((acc > 0) && (i > 0))
463                         acc = 1;
464                 else
465                         acc = 0;
466                 goto a0;
467         case ':':       /*or*/
468                 i = ckph();
469                 if (nonumb)
470                         break;
471                 if ((acc > 0) || (i > 0))
472                         acc = 1;
473                 else
474                         acc = 0;
475                 goto a0;
476         case '=':
477                 if (cbits(ii = getch()) != '=')
478                         ch = ii;
479                 i = ckph();
480                 if (nonumb) {
481                         acc = 0;
482                         break;
483                 }
484                 if (i == acc)
485                         acc = 1;
486                 else
487                         acc = 0;
488                 goto a0;
489         case '>':
490                 k = 0;
491                 if (cbits(ii = getch()) == '=')
492                         k++;
493                 else
494                         ch = ii;
495                 i = ckph();
496                 if (nonumb) {
497                         acc = 0;
498                         break;
499                 }
500                 if (acc > (i - k))
501                         acc = 1;
502                 else
503                         acc = 0;
504                 goto a0;
505         case '<':
506                 k = 0;
507                 if (cbits(ii = getch()) == '=')
508                         k++;
509                 else
510                         ch = ii;
511                 i = ckph();
512                 if (nonumb) {
513                         acc = 0;
514                         break;
515                 }
516                 if (acc < (i + k))
517                         acc = 1;
518                 else
519                         acc = 0;
520                 goto a0;
521         case ')':
522                 break;
523         case '(':
524                 acc = atoi0();
525                 goto a0;
526         }
527         return(acc);
528 }
529
530
531 long ckph(void)
532 {
533         Tchar i;
534         long j;
535
536         if (cbits(i = getch()) == '(')
537                 j = atoi0();
538         else {
539                 j = atoi1(i);
540         }
541         return(j);
542 }
543
544
545 /*
546  * print error about illegal numeric argument;
547  */
548 void prnumerr(void)
549 {
550         char err_buf[40];
551         static char warn[] = "Numeric argument expected";
552         int savcd = numtabp[CD].val;
553
554         if (numerr.type == RQERR)
555                 sprintf(err_buf, "%c%s: %s", nb ? cbits(c2) : cbits(cc),
556                                                 unpair(numerr.req), warn);
557         else
558                 sprintf(err_buf, "\\%c'%s': %s", numerr.esc, &numerr.escarg,
559                                                                         warn);
560         if (frame != stk)       /* uncertainty correction */
561                 numtabp[CD].val--;
562         ERROR err_buf WARN;
563         numtabp[CD].val = savcd;
564 }
565
566
567 long atoi1(Tchar ii)
568 {
569         int i, j, digits;
570         double acc;     /* this is the only double in troff! */
571         int neg, abs, field, decpnt;
572         extern int ifnum;
573
574
575         neg = abs = field = decpnt = digits = 0;
576         acc = 0;
577         for (;;) {
578                 i = cbits(ii);
579                 switch (i) {
580                 default:
581                         break;
582                 case '+':
583                         ii = getch();
584                         continue;
585                 case '-':
586                         neg = 1;
587                         ii = getch();
588                         continue;
589                 case '|':
590                         abs = 1 + neg;
591                         neg = 0;
592                         ii = getch();
593                         continue;
594                 }
595                 break;
596         }
597 a1:
598         while (i >= '0' && i <= '9') {
599                 field++;
600                 digits++;
601                 acc = 10 * acc + i - '0';
602                 ii = getch();
603                 i = cbits(ii);
604         }
605         if (i == '.' && !decpnt++) {
606                 field++;
607                 digits = 0;
608                 ii = getch();
609                 i = cbits(ii);
610                 goto a1;
611         }
612         if (!field) {
613                 ch = ii;
614                 goto a2;
615         }
616         switch (i) {
617         case 'u':
618                 i = j = 1;      /* should this be related to HOR?? */
619                 break;
620         case 'v':       /*VSs - vert spacing*/
621                 j = lss;
622                 i = 1;
623                 break;
624         case 'm':       /*Ems*/
625                 j = EM;
626                 i = 1;
627                 break;
628         case 'n':       /*Ens*/
629                 j = EM;
630                 if (TROFF)
631                         i = 2;
632                 else
633                         i = 1;  /*Same as Ems in NROFF*/
634                 break;
635         case 'p':       /*Points*/
636                 j = INCH;
637                 i = 72;
638                 break;
639         case 'i':       /*Inches*/
640                 j = INCH;
641                 i = 1;
642                 break;
643         case 'c':       /*Centimeters*/
644                 /* if INCH is too big, this will overflow */
645                 j = INCH * 50;
646                 i = 127;
647                 break;
648         case 'P':       /*Picas*/
649                 j = INCH;
650                 i = 6;
651                 break;
652         default:
653                 j = dfact;
654                 ch = ii;
655                 i = dfactd;
656         }
657         if (neg)
658                 acc = -acc;
659         if (!noscale) {
660                 acc = (acc * j) / i;
661         }
662         if (field != digits && digits > 0)
663                 while (digits--)
664                         acc /= 10;
665         if (abs) {
666                 if (dip != d)
667                         j = dip->dnl;
668                 else
669                         j = numtabp[NL].val;
670                 if (!vflag) {
671                         j = numtabp[HP].val;
672                 }
673                 if (abs == 2)
674                         j = -j;
675                 acc -= j;
676         }
677 a2:
678         nonumb = (!field || field == decpnt);
679         if (nonumb && (trace & TRNARGS) && !ismot(ii) && !nlflg && !ifnum) {
680                 if (cbits(ii) != RIGHT ) /* Too painful to do right */
681                         prnumerr();
682         }
683         return(acc);
684 }
685
686
687 void caserr(void)
688 {
689         int i, j;
690         Numtab *p;
691
692         lgf++;
693         while (!skip() && (i = getrq()) ) {
694                 j = usedr(i);
695                 if (j < 0)
696                         continue;
697                 p = &numtabp[j];
698                 nunhash(p);
699                 p->r = p->val = p->inc = p->fmt = 0;
700                 regcnt--;
701         }
702 }
703
704 /*
705  * .nr request; if tracing, don't check optional
706  * 2nd argument because tbl generates .in 1.5n
707  */
708 void casenr(void)
709 {
710         int i, j;
711         int savtr = trace;
712
713         lgf++;
714         skip();
715         if ((i = findr(getrq())) == -1)
716                 goto rtn;
717         skip();
718         j = inumb(&numtabp[i].val);
719         if (nonumb)
720                 goto rtn;
721         numtabp[i].val = j;
722         skip();
723         trace = 0;
724         j = atoi0();            /* BUG??? */
725         trace = savtr;
726         if (nonumb)
727                 goto rtn;
728         numtabp[i].inc = j;
729 rtn:
730         return;
731 }
732
733 void caseaf(void)
734 {
735         int i, k;
736         Tchar j;
737
738         lgf++;
739         if (skip() || !(i = getrq()) || skip())
740                 return;
741         k = 0;
742         j = getch();
743         if (!isalpha(cbits(j))) {
744                 ch = j;
745                 while ((j = cbits(getch())) >= '0' &&  j <= '9')
746                         k++;
747         }
748         if (!k)
749                 k = j;
750         numtabp[findr(i)].fmt = k;      /* was k & BYTEMASK */
751 }
752
753 void setaf(void)        /* return format of number register */
754 {
755         int i, j;
756
757         i = usedr(getsn());
758         if (i == -1)
759                 return;
760         if (numtabp[i].fmt > 20)        /* it was probably a, A, i or I */
761                 *pbp++ = numtabp[i].fmt;
762         else
763                 for (j = (numtabp[i].fmt ? numtabp[i].fmt : 1); j; j--)
764                         *pbp++ = '0';
765 }
766
767
768 int vnumb(int *i)
769 {
770         vflag++;
771         dfact = lss;
772         res = VERT;
773         return(inumb(i));
774 }
775
776
777 int hnumb(int *i)
778 {
779         dfact = EM;
780         res = HOR;
781         return(inumb(i));
782 }
783
784
785 int inumb(int *n)
786 {
787         int i, j, f;
788         Tchar ii;
789
790         f = 0;
791         if (n) {
792                 if ((j = cbits(ii = getch())) == '+')
793                         f = 1;
794                 else if (j == '-')
795                         f = -1;
796                 else
797                         ch = ii;
798         }
799         i = atoi0();
800         if (n && f)
801                 i = *n + f * i;
802         i = quant(i, res);
803         vflag = 0;
804         res = dfactd = dfact = 1;
805         if (nonumb)
806                 i = 0;
807         return(i);
808 }
809
810
811 int quant(int n, int m)
812 {
813         int i, neg;
814
815         neg = 0;
816         if (n < 0) {
817                 neg++;
818                 n = -n;
819         }
820         /* better as i = ((n + m/2)/m)*m */
821         i = n / m;
822         if (n - m * i > m / 2)
823                 i += 1;
824         i *= m;
825         if (neg)
826                 i = -i;
827         return(i);
828 }