1 /* $MirOS: src/usr.bin/oldroff/nroff/n3.c,v 1.6 2006/11/04 05:43:43 tg Exp $ */
2
3 /*-
4 * Copyright (c) 1979, 1980, 1981, 1986, 1988, 1990, 1991, 1992
5 * The Regents of the University of California.
6 * Copyright (C) Caldera International Inc. 2001-2002.
7 * Copyright (c) 2003, 2004, 2005, 2006
8 * Thorsten "mirabilos" Glaser <tg@mirbsd.org>
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms,
12 * with or without modification, are permitted provided
13 * that the following conditions are met:
14 *
15 * Redistributions of source code and documentation must retain
16 * the above copyright notice, this list of conditions and the
17 * following disclaimer. Redistributions in binary form must
18 * reproduce the above copyright notice, this list of conditions
19 * and the following disclaimer in the documentation and/or other
20 * materials provided with the distribution.
21 *
22 * All advertising materials mentioning features or use of this
23 * software must display the following acknowledgement:
24 * This product includes software developed or owned by
25 * Caldera International, Inc.
26 *
27 * Advertising materials mentioning features or use of this work must
28 * display the following acknowledgement:
29 * This product includes material provided by Thorsten Glaser.
30 *
31 * Neither the name of Caldera International, Inc. nor the names
32 * of other contributors may be used to endorse or promote products
33 * derived from this software without specific prior written permission.
34 *
35 * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
36 * INTERNATIONAL, INC. AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
37 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
38 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39 * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE
40 * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
41 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
42 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47 *
48 * Licensor offers the work "AS IS" and WITHOUT WARRANTY of any kind,
49 * express, or implied, to the maximum extent permitted by applicable
50 * law, without malicious intent or gross negligence; in no event may
51 * licensor, an author or contributor be held liable for any indirect
52 * or other damage, or direct damage except proven a consequence of a
53 * direct error of said person and intended use of this work, loss or
54 * other issues arising in any way out of its use, even if advised of
55 * the possibility of such damage or existence of a defect.
56 */
57
58 #include <stdio.h>
59 #include "tdef.h"
60 extern
61 #include "d.h"
62 extern
63 #include "v.h"
64 #ifdef NROFF
65 extern
66 #include "tw.h"
67 #endif
68 #include "sdef.h"
69
70 __SCCSID("@(#)n3.c 4.5 (Berkeley) 4/18/91");
71 __RCSID("$MirOS: src/usr.bin/oldroff/nroff/n3.c,v 1.6 2006/11/04 05:43:43 tg Exp $");
72
73 /*
74 troff3.c
75
76 macro and string routines, storage allocation
77 */
78
79 unsigned blist[NBLIST];
80 int ecskip = 0;
81 extern struct s *frame, *stk, *nxf;
82 extern filep ip;
83 extern filep offset;
84 extern filep nextb;
85 extern char *enda;
86
87 extern int ch;
88 extern int ibf;
89 extern int lgf;
90 extern int copyf;
91 extern int ch0;
92 extern int app;
93 extern int ds;
94 extern int nlflg;
95 extern int *argtop;
96 extern int *ap;
97 extern int nchar;
98 extern int pendt;
99 extern int rchar;
100 extern int dilev;
101 extern int nonumb;
102 extern int lt;
103 extern int nrbits;
104 extern int nform;
105 extern int fmt[];
106 extern int oldmn;
107 extern int newmn;
108 extern int macerr;
109 extern filep apptr;
110 extern int diflg;
111 extern filep woff;
112 extern filep roff;
113 extern int wbfi;
114 extern int po;
115 extern int *cp;
116 extern int xxx;
117 extern int groffmode;
118 int pagech = '%';
119 int strflg;
120 extern struct contab {
121 int rq;
122 union {
123 int (*f)();
124 unsigned mx;
125 }x;
126 }contab[NM];
127 #ifndef VMUNIX
128 int wbuf[BLK];
129 int rbuf[BLK];
130 #else
131 int *wbuf;
132 int *rbuf;
133 int Buf[NBLIST*BLK + NEV*EVS];
134 #endif
135
caseig()136 caseig(){
137 register i;
138
139 offset = 0;
140 if((i = copyb()) != '.')control(i,1);
141 }
casern()142 casern(){
143 register i,j;
144
145 lgf++;
146 skip();
147 if(((i=getrq())==0) || ((oldmn=findmn(i)) < 0))return;
148 skip();
149 clrmn(findmn(j=getrq()));
150 if(j)contab[oldmn].rq = (contab[oldmn].rq & MMASK) | j;
151 }
caserm()152 caserm(){
153 lgf++;
154 while(!skip()){
155 clrmn(findmn(getrq()));
156 }
157 }
caseas()158 caseas(){
159 app++;
160 caseds();
161 }
caseds()162 caseds(){
163 ds++;
164 casede();
165 }
caseam()166 caseam(){
167 app++;
168 casede();
169 }
getrq_fc(j)170 getrq_fc(j){
171 if ( ((j>='a')&&(j<='z')) || ((j>='A')&&(j<='Z')) ||
172 ((j>='0')&&(j<='9')) )
173 return (!0);
174 return 0;
175 }
casede()176 casede(){
177 register i, j, req;
178 register filep savoff;
179 extern filep finds();
180
181 if(dip != d)wbfl();
182 req = '.';
183 lgf++;
184 skip();
185 if((i=getrq())==0)goto de1;
186
187 if (ds == 0 && app == 0) {
188 register jw = 0;
189
190 while (getrq_fc((j=getch()) & CMASK)) {
191 if (jw++)
192 fprintf(stderr,
193 "warning: additional junk found!\n");
194 else fprintf(stderr,
195 "warning: roff handles only two-character"
196 " macroes, third character\n\treturned is"
197 " 0x%02X, overridden. Fix source (line"
198 " %d)!\n", j, v.cd+1);
199 }
200 if (!ch) ch=j;
201 }
202
203 if((offset=finds(i)) == 0)goto de1;
204 if(ds)copys();
205 else req = copyb();
206 wbfl();
207 clrmn(oldmn);
208 if(newmn)contab[newmn].rq = i | MMASK;
209 if(apptr){
210 savoff = offset;
211 offset = apptr;
212 wbt(IMP);
213 offset = savoff;
214 }
215 offset = dip->op;
216 if(req != '.')control(req,1);
217 de1:
218 ds = app = 0;
219 return;
220 }
findmn(i)221 findmn(i)
222 int i;
223 {
224 register j;
225
226 for(j=0;j<NM;j++){
227 if(i == (contab[j].rq & ~MMASK))break;
228 }
229 if(j==NM)j = -1;
230 return(j);
231 }
clrmn(i)232 clrmn(i)
233 int i;
234 {
235 extern filep boff();
236 if(i >= 0){
237 if(contab[i].rq & MMASK)ffree(((filep)contab[i].x.mx)<<BLKBITS);
238 contab[i].rq = 0;
239 contab[i].x.mx = 0;
240 }
241 }
finds(mn)242 filep finds(mn)
243 int mn;
244 {
245 register i;
246 extern filep boff();
247 register filep savip;
248 extern filep alloc();
249 extern filep incoff();
250
251 oldmn = findmn(mn);
252 newmn = 0;
253 apptr = (filep)0;
254 if(app && (oldmn >= 0) && (contab[oldmn].rq & MMASK)){
255 savip = ip;
256 ip = (((filep)contab[oldmn].x.mx)<<BLKBITS);
257 oldmn = -1;
258 while((i=rbf()) != 0);
259 apptr = ip;
260 if(!diflg)ip = incoff(ip);
261 nextb = ip;
262 ip = savip;
263 }else{
264 for(i=0;i<NM;i++){
265 if(contab[i].rq == 0)break;
266 }
267 if((i==NM) ||
268 (nextb = alloc()) == 0){
269 app = 0;
270 if(macerr++ > 1)done2(02);
271 prstr("Too many string/macro names.\n");
272 edone(04);
273 return(offset = 0);
274 }
275 contab[i].x.mx = (unsigned)(nextb>>BLKBITS);
276 if(!diflg){
277 newmn = i;
278 if(oldmn == -1)contab[i].rq = -1;
279 }else{
280 contab[i].rq = mn | MMASK;
281 }
282 }
283
284 app = 0;
285 return(offset = nextb);
286 }
skip()287 skip(){
288 register i;
289
290 while(((i=getch()) & CMASK) == ' ');
291 ch=i;
292 return(nlflg);
293 }
copyb()294 copyb()
295 {
296 register i, j, k;
297 int ii, req, state;
298 filep savoff;
299
300 if(skip() || !(j=getrq()))j = '.';
301 req = j;
302 k = j>>BYTE;
303 j &= BMASK;
304 copyf++;
305 flushi();
306 nlflg = 0;
307 state = 1;
308 while(1){
309 i = (ii = getch()) & CMASK;
310 if(state == 3){
311 if(i == k)break;
312 if(!k){
313 ch = ii;
314 i = getach();
315 ch = ii;
316 if(!i)break;
317 }
318 state = 0;
319 goto c0;
320 }
321 if(i == '\n'){
322 state = 1;
323 nlflg = 0;
324 goto c0;
325 }
326 if((state == 1) && (i == '.')){
327 state++;
328 savoff = offset;
329 goto c0;
330 }
331 if((state == 2) && (i == j)){
332 state++;
333 goto c0;
334 }
335 state = 0;
336 c0:
337 if(offset)wbf(ii);
338 }
339 if(offset){
340 wbfl();
341 offset = savoff;
342 wbt(0);
343 }
344 copyf--;
345 return(req);
346 }
copys()347 copys()
348 {
349 register i;
350
351 copyf++;
352 if(skip())goto c0;
353 if(((i=getch()) & CMASK) != '"')wbf(i);
354 while(((i=getch()) & CMASK) != '\n')wbf(i);
355 c0:
356 wbt(0);
357 copyf--;
358 }
alloc()359 filep alloc()
360 {
361 register i;
362 extern filep boff();
363 filep j;
364
365 for(i=0;i<NBLIST;i++){
366 if(blist[i] == 0)break;
367 }
368 if(i==NBLIST){
369 j = 0;
370 }else{
371 blist[i] = -1;
372 if((j = boff(i)) < NEV*EVS)j = 0;
373 }
374 return(nextb = j);
375 }
ffree(i)376 ffree(i)
377 filep i;
378 {
379 register j;
380
381 while((blist[j = blisti(i)]) != -1){
382 i = ((filep)blist[j])<<BLKBITS;
383 blist[j] = 0;
384 }
385 blist[j] = 0;
386 }
boff(i)387 filep boff(i)
388 int i;
389 {
390 return(((filep)i)*BLK + NEV*EVS);
391 }
wbt(i)392 wbt(i)
393 int i;
394 {
395 wbf(i);
396 wbfl();
397 }
wbf(i)398 wbf(i)
399 int i;
400 {
401 register j;
402
403 if(!offset)return;
404 if(!woff){
405 woff = offset;
406 #ifdef VMUNIX
407 wbuf = &Buf[woff];
408 #endif
409 wbfi = 0;
410 }
411 wbuf[wbfi++] = i;
412 if(!((++offset) & (BLK-1))){
413 wbfl();
414 if(blist[j = blisti(--offset)] == -1){
415 if(alloc() == 0){
416 prstr("Out of temp file space.\n");
417 done2(01);
418 }
419 blist[j] = (unsigned)(nextb>>BLKBITS);
420 }
421 offset = ((filep)blist[j])<<BLKBITS;
422 }
423 if(wbfi >= BLK)wbfl();
424 }
wbfl()425 wbfl(){
426 if(woff == 0)return;
427 #ifndef VMUNIX
428 lseek(ibf, ((long)woff) * sizeof(int), 0);
429 write(ibf, (char *)wbuf, wbfi * sizeof(int));
430 #endif
431 if((woff & (~(BLK-1))) == (roff & (~(BLK-1))))roff = -1;
432 woff = 0;
433 }
blisti(i)434 blisti(i)
435 filep i;
436 {
437 return((i-NEV*EVS)/(BLK));
438 }
rbf()439 rbf(){
440 register i;
441 extern filep incoff();
442
443 if((i=rbf0(ip)) == 0){
444 if(!app)i = popi();
445 }else{
446 ip = incoff(ip);
447 }
448 return(i);
449 }
rbf0(p)450 rbf0(p)
451 filep p;
452 {
453 register filep i;
454
455 if((i = (p & (~(BLK-1)))) != roff){
456 roff = i;
457 #ifndef VMUNIX
458 lseek(ibf, ((long)roff) * sizeof(int), 0);
459 if(read(ibf, (char *)rbuf, BLK * sizeof(int)) == 0)return(0);
460 #else
461 rbuf = &Buf[roff];
462 #endif
463 }
464 return(rbuf[p & (BLK-1)]);
465 }
incoff(p)466 filep incoff(p)
467 filep p;
468 {
469 register i;
470 register filep j;
471 if(!((j = (++p)) & (BLK-1))){
472 if((i = blist[blisti(--p)]) == -1){
473 prstr("Bad storage allocation.\n");
474 done2(-5);
475 }
476 j = ((filep)i)<<BLKBITS;
477 }
478 return(j);
479 }
popi()480 popi(){
481 register struct s *p;
482
483 if(frame == stk)return(0);
484 if(strflg)strflg--;
485 p = nxf = frame;
486 p->nargs = 0;
487 frame = p->pframe;
488 ip = p->pip;
489 nchar = p->pnchar;
490 rchar = p->prchar;
491 pendt = p->ppendt;
492 ap = p->pap;
493 cp = p->pcp;
494 ch0 = p->pch0;
495 return(p->pch);
496 }
497
498 /*
499 * test that the end of the allocation is above a certain location
500 * in memory
501 */
502 #define SPACETEST(base, size) while ((enda - (size)) <= (char *)(base)){setbrk(DELTA);}
503
pushi(newip)504 pushi(newip)
505 filep newip;
506 {
507 register struct s *p;
508 extern char *setbrk();
509
510 SPACETEST(nxf, sizeof(struct s));
511 p = nxf;
512 p->pframe = frame;
513 p->pip = ip;
514 p->pnchar = nchar;
515 p->prchar = rchar;
516 p->ppendt = pendt;
517 p->pap = ap;
518 p->pcp = cp;
519 p->pch0 = ch0;
520 p->pch = ch;
521 cp = ap = 0;
522 nchar = rchar = pendt = ch0 = ch = 0;
523 frame = nxf;
524 if (nxf->nargs == 0)
525 nxf += 1;
526 else
527 nxf = (struct s *)argtop;
528 return(ip = newip);
529 }
530
531
setbrk(x)532 char *setbrk(x)
533 int x;
534 {
535 register char *i;
536 char *sbrk();
537
538 x += sizeof(int) - 1;
539 x &= ~(sizeof(int) - 1);
540 if ((u_int)(i = sbrk(x)) == -1) {
541 prstrfl("Core limit reached.\n");
542 edone(0100);
543 } else {
544 enda = i + x;
545 }
546 return(i);
547 }
548
549
getsn()550 getsn()
551 {
552 register i;
553
554 if ((i = getach()) == 0)
555 return(0);
556 #ifdef backwards
557 if (groffmode && !copyf && (i == '['))
558 fprintf(stderr, "warning: request for long string"
559 " in line %d denied!\n", v.cd+1);
560 #else
561 if (/* groffmode && !copyf && */ !ecskip && (i == '[')) {
562 fputs("warning: request for long string [", stderr);
563 while ((i = getach())) {
564 putc(i, stderr);
565 if (i == ']')
566 break;
567 }
568 if (i != ']')
569 fputs("<NUL>]", stderr);
570 fprintf(stderr, " in line %d denied!\n", v.cd+1);
571 return (0);
572 }
573 #endif
574 if (i == '(')
575 return(getrq());
576 else
577 return(i);
578 }
579
580
setstr()581 setstr()
582 {
583 register i;
584
585 lgf++;
586 if ( ((i = getsn()) == 0)
587 || ((i = findmn(i)) == -1)
588 || !(contab[i].rq & MMASK)) {
589 lgf--;
590 return(0);
591 } else {
592 SPACETEST(nxf, sizeof(struct s));
593 nxf->nargs = 0;
594 strflg++;
595 lgf--;
596 return(pushi(((filep)contab[i].x.mx)<<BLKBITS));
597 }
598 }
599
600 typedef int tchar;
601 #define cbits(x) ((x) & CMASK)
602
collect()603 collect()
604 {
605 register j;
606 tchar i;
607 register tchar *strp;
608 tchar * lim;
609 tchar * *argpp, **argppend;
610 int quote;
611 struct s *savnxf;
612
613 copyf++;
614 nxf->nargs = 0;
615 savnxf = nxf;
616 if (skip())
617 goto rtn;
618
619 {
620 char *memp;
621 memp = (char *)savnxf;
622 /*
623 * 1 s structure for the macro descriptor
624 * APERMAC tchar *'s for pointers into the strings
625 * space for the tchar's themselves
626 */
627 memp += sizeof(struct s);
628 /*
629 * CPERMAC (the total # of characters for ALL arguments)
630 * to a macros, has been carefully chosen
631 * so that the distance between stack frames is < DELTA
632 */
633 #define CPERMAC 500
634 #define APERMAC 9
635 memp += APERMAC * sizeof(tchar *);
636 memp += CPERMAC * sizeof(tchar);
637 nxf = (struct s*)memp;
638 }
639 lim = (tchar *)nxf;
640 argpp = (tchar **)(savnxf + 1);
641 argppend = &argpp[APERMAC];
642 SPACETEST(argppend, sizeof(tchar *));
643 strp = (tchar *)argppend;
644 /*
645 * Zero out all the string pointers before filling them in.
646 */
647 for (j = 0; j < APERMAC; j++){
648 argpp[j] = (tchar *)0;
649 }
650 #if 0
651 fprintf(stderr, "savnxf=0x%x,nxf=0x%x,argpp=0x%x,strp=argppend=0x%x,lim=0x%x,enda=0x%x\n",
652 savnxf, nxf, argpp, strp, lim, enda);
653 #endif
654 strflg = 0;
655 while ((argpp != argppend) && (!skip())) {
656 *argpp++ = strp;
657 quote = 0;
658 if (cbits(i = getch()) == '"')
659 quote++;
660 else
661 ch = i;
662 while (1) {
663 i = getch();
664 if ( nlflg || (!quote && cbits(i) == ' '))
665 break;
666 if ( quote
667 && (cbits(i) == '"')
668 && (cbits(i = getch()) != '"')) {
669 ch = i;
670 break;
671 }
672 *strp++ = i;
673 if (strflg && (strp >= lim)) {
674 #if 0
675 fprintf(stderr, "strp=0x%x, lim = 0x%x\n",
676 strp, lim);
677 #endif
678 prstrfl("Macro argument too long.\n");
679 copyf--;
680 edone(004);
681 }
682 SPACETEST(strp, 3 * sizeof(tchar));
683 }
684 *strp++ = 0;
685 }
686 nxf = savnxf;
687 nxf->nargs = argpp - (tchar **)(savnxf + 1);
688 argtop = strp;
689 rtn:
690 copyf--;
691 }
692
693
seta()694 seta()
695 {
696 register i;
697
698 if(((i = (getch() & CMASK) - '0') > 0) &&
699 (i <= APERMAC) && (i <= frame->nargs))ap = *((int **)frame + i-1 + (sizeof(struct s)/sizeof(int **)));
700 }
caseda()701 caseda(){
702 app++;
703 casedi();
704 }
casedi()705 casedi(){
706 register i, j;
707 register *k;
708
709 lgf++;
710 if(skip() || ((i=getrq()) == 0)){
711 if(dip != d)wbt(0);
712 if(dilev > 0){
713 v.dn = dip->dnl;
714 v.dl = dip->maxl;
715 dip = &d[--dilev];
716 offset = dip->op;
717 }
718 goto rtn;
719 }
720 if(++dilev == NDI){
721 --dilev;
722 prstr("Cannot divert.\n");
723 edone(02);
724 }
725 if(dip != d)wbt(0);
726 diflg++;
727 dip = &d[dilev];
728 dip->op = finds(i);
729 dip->curd = i;
730 clrmn(oldmn);
731 k = (int *)&dip->dnl;
732 for(j=0; j<10; j++)k[j] = 0; /*not op and curd*/
733 rtn:
734 app = 0;
735 diflg = 0;
736 }
casedt()737 casedt(){
738 lgf++;
739 dip->dimac = dip->ditrap = dip->ditf = 0;
740 skip();
741 dip->ditrap = vnumb((int *)0);
742 if(nonumb)return;
743 skip();
744 dip->dimac = getrq();
745 }
casetl()746 casetl(){
747 register i, j;
748 int w1, w2, w3, delim;
749 filep begin;
750 extern width(), pchar();
751
752 dip->nls = 0;
753 skip();
754 if(dip != d)wbfl();
755 if((offset = begin = alloc()) == 0)return;
756 if((delim = getch()) & MOT){
757 ch = delim;
758 delim = '\'';
759 }else delim &= CMASK;
760 if(!nlflg)
761 while(((i = getch()) & CMASK) != '\n'){
762 if((i & CMASK) == delim)i = IMP;
763 wbf(i);
764 }
765 wbf(IMP);wbf(IMP);wbt(0);
766
767 w1 = hseg(width,begin);
768 w2 = hseg(width,(filep)0);
769 w3 = hseg(width,(filep)0);
770 offset = dip->op;
771 #ifdef NROFF
772 if(!offset)horiz(po);
773 #endif
774 hseg(pchar,begin);
775 if(w2 || w3)horiz(j=quant((lt - w2)/2-w1,HOR));
776 hseg(pchar,(filep)0);
777 if(w3){
778 horiz(lt-w1-w2-w3-j);
779 hseg(pchar,(filep)0);
780 }
781 newline(0);
782 if(dip != d){if(dip->dnl > dip->hnl)dip->hnl = dip->dnl;}
783 else{if(v.nl > dip->hnl)dip->hnl = v.nl;}
784 ffree(begin);
785 }
casepc()786 casepc(){
787 pagech = chget(IMP);
788 }
789 hseg(f,p)
790 int (*f)();
791 filep p;
792 {
793 register acc, i;
794 static filep q;
795
796 acc = 0;
797 if(p)q = p;
798 while(1){
799 i = rbf0(q);
800 q = incoff(q);
801 if(!i || (i == IMP))return(acc);
802 if((i & CMASK) == pagech){
803 nrbits = i & ~CMASK;
804 nform = fmt[findr('%')];
805 acc += fnumb(v.pn,f);
806 }else acc += (*f)(i);
807 }
808 }
casepm()809 casepm(){
810 register i, k;
811 register char *p;
812 int xx, cnt, kk, tot;
813 filep j;
814 char *kvt();
815 char pmline[10];
816
817 kk = cnt = 0;
818 tot = !skip();
819 for(i = 0; i<NM; i++){
820 if(!((xx = contab[i].rq) & MMASK))continue;
821 p = pmline;
822 j = (((filep)contab[i].x.mx)<<BLKBITS);
823 k = 1;
824 while((j = blist[blisti(j)]) != -1){k++; j <<= BLKBITS;}
825 cnt++;
826 kk += k;
827 if(!tot){
828 *p++ = xx & 0177;
829 if(!(*p++ = (xx >> BYTE) & 0177))*(p-1) = ' ';
830 *p++ = ' ';
831 kvt(k,p);
832 prstr(pmline);
833 }
834 }
835 if(tot || (cnt > 1)){
836 kvt(kk,pmline);
837 prstr(pmline);
838 }
839 }
kvt(k,p)840 char *kvt(k,p)
841 int k;
842 char *p;
843 {
844 if(k>=100)*p++ = k/100 + '0';
845 if(k>=10)*p++ = (k%100)/10 + '0';
846 *p++ = k%10 + '0';
847 *p++ = '\n';
848 *p = 0;
849 return(p);
850 }
dummy()851 dummy(){}
852