Introduction
Introduction Statistics Contact Development Disclaimer Help
n4.c - 9base - revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log
Files
Refs
README
LICENSE
---
n4.c (12317B)
---
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 (t…
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 addres…
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], "%ld", tabtab[i] & TAB…
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]…
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",…
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(Numt…
233 0, NDELTA * sizeof(Numta…
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.esc…
559 …
560 if (frame != stk) /* uncertainty correction */
561 numtabp[CD].val--;
562 ERROR "%s", 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 && !ifnu…
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 }
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.