BSD 3 development
[unix-history] / usr / src / cmd / ls / ucbls.c
CommitLineData
1217e91a
BJ
1/* Copyright (c) 1979 Regents of the University of California */
2#
3/*
4 * ls - list file or directory
5 *
6 * Modified by Bill Joy UCB May/August 1977
7 *
8 * This version of ls is designed for graphic terminals and to
9 * list directories with lots of files in them compactly.
10 * It supports three variants for listings:
11 *
12 * 1) Columnar output.
13 * 2) Stream output.
14 * 3) Old one per line format.
15 *
16 * Columnar output is the default.
17 * If, however, the standard output is not a teletype, the default
18 * is one-per-line.
19 *
20 * With columnar output, the items are sorted down the columns.
21 * We use columns only for a directory we are interpreting.
22 * Thus, in particular, we do not use columns for
23 *
24 * ls /usr/bin/p*
25 *
26 * This version of ls also prints non-printing characters as '?' if
27 * the standard output is a teletype.
28 *
29 * Flags relating to these and other new features are:
30 *
31 * -m force stream output.
32 *
33 * -1 force one entry per line, e.g. to a teletype
34 *
35 * -q force non-printings to be '?'s, e.g. to a file
36 *
37 * -c force columnar output, e.g. into a file
38 *
39 * -n like -l, but user/group id's in decimal rather than
40 * looking in /etc/passwd to save time
41 */
42
43#include <sys/param.h>
44#include <sys/stat.h>
45#include <sys/dir.h>
46#include <stdio.h>
47#include <ctype.h>
48
49
50#define NFILES 1024
51FILE *pwdf, *dirf;
52
53struct lbuf {
54 union {
55 char lname[15];
56 char *namep;
57 } ln;
58 char ltype;
59 short lnum;
60 short lflags;
61 short lnl;
62 short luid;
63 short lgid;
64 long lsize;
65 long lmtime;
66};
67
68int aflg, dflg, lflg, sflg, tflg, uflg, iflg, fflg, gflg, cflg;
69int Aflg, nflg, qflg, across;
70int nopad;
71char buff[32];
72int rflg = 1;
73long year;
74int flags;
75int lastuid = -1;
76char tbuf[16];
77long tblocks;
78int statreq;
79struct lbuf *flist[NFILES];
80struct lbuf **lastp = flist;
81struct lbuf **firstp = flist;
82char *dotp = ".";
83
84char *makename();
85struct lbuf *gstat();
86char *ctime();
87long nblock();
88
89#define ISARG 0100000
90int colwidth = 15;
91int outcol;
92
93char obuf[BUFSIZ];
94
95main(argc, argv)
96char *argv[];
97{
98 int i;
99 register struct lbuf *ep, **ep1;
100 register struct lbuf **slastp;
101 struct lbuf **epp;
102 struct lbuf lb;
103 char *t;
104 char *cp;
105 int compar();
106
107 Aflg = getuid() == 0;
108 setbuf(stdout, obuf);
109 time(&lb.lmtime);
110 year = lb.lmtime - 6L*30L*24L*60L*60L; /* 6 months ago */
111 qflg = gtty(1, buff) == 0;
112 /*
113 * If the standard output is not a teletype,
114 * then we default to one-per-line format
115 * otherwise decide between stream and
116 * columnar based on our name.
117 */
118 if (qflg) {
119 cflg = 1;
120 for (cp = argv[0]; cp[0] && cp[1]; cp++)
121 continue;
122 /*
123 * Name ends in l => stream
124 */
125 if (cp[0] == 'l')
126 nopad = 1, cflg = 0;
127 /*
128 * ... if doesn't end in l or s ==> columns sorted across
129 *
130 else if (cp[0] == 'x')
131 across = 1;
132 */
133 }
134 if (--argc > 0 && *argv[1] == '-') {
135 argv++;
136 while (*++*argv) switch (**argv) {
137 /*
138 * c - force columnar output
139 */
140 case 'c':
141 cflg = 1;
142 nopad = 0;
143 continue;
144 /*
145 * m - force stream output
146 */
147 case 'm':
148 cflg = 0;
149 nopad = 1;
150 continue;
151 /*
152 * x - force sort across
153 */
154 case 'x':
155 across = 1;
156 nopad = 0;
157 cflg = 1;
158 continue;
159 /*
160 * q - force ?'s in output
161 */
162 case 'q':
163 qflg = 1;
164 continue;
165 /*
166 * 1 - force 1/line in output
167 */
168 case '1':
169 cflg = 0;
170 nopad = 0;
171 continue;
172 /* STANDARD FLAGS */
173 case 'a':
174 aflg++;
175 continue;
176
177 case 'A':
178 Aflg = !Aflg;
179 continue;
180
181 case 's':
182 colwidth += 5;
183 sflg++;
184 statreq++;
185 continue;
186
187 case 'd':
188 dflg++;
189 continue;
190
191 /*
192 * n - don't look in password file
193 */
194 case 'n':
195 nflg++;
196 case 'l':
197 lflg++;
198 statreq++;
199 continue;
200
201 case 'r':
202 rflg = -1;
203 continue;
204
205 case 't':
206 tflg++;
207 statreq++;
208 continue;
209
210 case 'u':
211 uflg++;
212 continue;
213
214 case 'i':
215 colwidth += 5;
216 iflg++;
217 continue;
218
219 case 'f':
220 fflg++;
221 continue;
222
223 case 'g':
224 gflg++;
225 continue;
226
227 default:
228 continue;
229 }
230 argc--;
231 }
232 if (fflg) {
233 aflg++;
234 lflg = 0;
235 sflg = 0;
236 tflg = 0;
237 statreq = 0;
238 }
239 if(lflg) {
240 cflg = 0;
241 t = "/etc/passwd";
242 if (gflg)
243 t = "/etc/group";
244 nopad = 0;
245 colwidth = 70;
246 pwdf = fopen(t, "r");
247 }
248 if (argc==0) {
249 argc++;
250 argv = &dotp - 1;
251 }
252 for (i=0; i < argc; i++) {
253 if ((ep = gstat(*++argv, 1))==NULL)
254 continue;
255 ep->ln.namep = *argv;
256 ep->lflags |= ISARG;
257 }
258 qsort(firstp, lastp - firstp, sizeof *lastp, compar);
259 slastp = lastp;
260 for (epp=firstp; epp<slastp; epp++) {
261 ep = *epp;
262 if (ep->ltype=='d' && dflg==0 || fflg) {
263 if (argc>1)
264 printf("\n%s:\n", ep->ln.namep);
265 lastp = slastp;
266 readdir(ep->ln.namep);
267 if (fflg==0)
268 qsort(slastp,lastp - slastp,sizeof *lastp,compar);
269 if (lflg || sflg)
270 printf("total %D", tblocks);
271 pem(slastp, lastp);
272 newline();
273 } else
274 pentry(ep);
275 }
276 if (outcol)
277 putc('\n', stdout);
278 fflush(stdout);
279}
280
281pem(slp, lp)
282 register struct lbuf **slp, **lp;
283{
284 int ncols, nrows, row, col;
285 register struct lbuf **ep;
286
287 ncols = 80 / colwidth;
288 if (ncols == 1 || cflg == 0) {
289 for (ep = slp; ep < lp; ep++)
290 pentry(*ep);
291 return;
292 }
293 if (across) {
294 for (ep = slp; ep < lp; ep++)
295 pentry(*ep);
296 return;
297 }
298 if (statreq)
299 slp--;
300 nrows = (lp - slp - 1) / ncols + 1;
301 for (row = 0; row < nrows; row++) {
302 col = row == 0 && statreq;
303 for (; col < ncols; col++) {
304 ep = slp + (nrows * col) + row;
305 if (ep < lp)
306 pentry(*ep);
307 }
308 if (outcol)
309 printf("\n");
310 }
311}
312
313pputchar(c)
314 char c;
315{
316
317 switch (c) {
318 case '\t':
319 outcol = (outcol + 8) &~ 7;
320 break;
321 case '\n':
322 outcol = 0;
323 break;
324 default:
325 if (qflg && (c < ' ' || c >= 0177))
326 c = '?';
327 outcol++;
328 break;
329 }
330 putc(c, stdout);
331}
332
333newline()
334{
335 if (outcol)
336 putc('\n', stdout);
337 outcol = 0;
338}
339
340column()
341{
342
343 if (outcol == 0)
344 return;
345 if (nopad) {
346 putc(',', stdout);
347 outcol++;
348 if (outcol + colwidth + 2 > 80) {
349 putc('\n', stdout);
350 outcol = 0;
351 return;
352 }
353 putc(' ', stdout);
354 outcol++;
355 return;
356 }
357 if (cflg == 0) {
358 putc('\n', stdout);
359 return;
360 }
361 if ((outcol / colwidth + 2) * colwidth > 80) {
362 putc('\n', stdout);
363 outcol = 0;
364 return;
365 }
366 do {
367 outcol++;
368 putc(' ', stdout);
369 } while (outcol % colwidth);
370}
371
372
373getname(uid, buf)
374int uid;
375char buf[];
376{
377 int j, c, n, i;
378
379 if (uid==lastuid)
380 return(0);
381 if(pwdf == NULL)
382 return(-1);
383 rewind(pwdf);
384 lastuid = -1;
385 do {
386 i = 0;
387 j = 0;
388 n = 0;
389 while((c=fgetc(pwdf)) != '\n') {
390 if (c==EOF)
391 return(-1);
392 if (c==':') {
393 j++;
394 c = '0';
395 }
396 if (j==0)
397 buf[i++] = c;
398 if (j==2)
399 n = n*10 + c - '0';
400 }
401 } while (n != uid);
402 buf[i++] = '\0';
403 lastuid = uid;
404 return(0);
405}
406
407long
408nblock(size)
409long size;
410{
411 return((size+511)>>9);
412}
413
414int m1[] = { 1, S_IREAD>>0, 'r', '-' };
415int m2[] = { 1, S_IWRITE>>0, 'w', '-' };
416int m3[] = { 2, S_ISUID, 's', S_IEXEC>>0, 'x', '-' };
417int m4[] = { 1, S_IREAD>>3, 'r', '-' };
418int m5[] = { 1, S_IWRITE>>3, 'w', '-' };
419int m6[] = { 2, S_ISGID, 's', S_IEXEC>>3, 'x', '-' };
420int m7[] = { 1, S_IREAD>>6, 'r', '-' };
421int m8[] = { 1, S_IWRITE>>6, 'w', '-' };
422int m9[] = { 2, S_ISVTX, 't', S_IEXEC>>6, 'x', '-' };
423
424int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
425
426pmode(aflag)
427{
428 register int **mp;
429
430 flags = aflag;
431 for (mp = &m[0]; mp < &m[sizeof(m)/sizeof(m[0])];)
432 select(*mp++);
433}
434
435select(pairp)
436register int *pairp;
437{
438 register int n;
439
440 n = *pairp++;
441 while (--n>=0 && (flags&*pairp++)==0)
442 pairp++;
443 pputchar(*pairp);
444}
445
446char *
447makename(dir, file)
448char *dir, *file;
449{
450 static char dfile[100];
451 register char *dp, *fp;
452 register int i;
453
454 dp = dfile;
455 fp = dir;
456 while (*fp)
457 *dp++ = *fp++;
458 *dp++ = '/';
459 fp = file;
460 for (i=0; i<DIRSIZ; i++)
461 *dp++ = *fp++;
462 *dp = 0;
463 return(dfile);
464}
465
466readdir(dir)
467char *dir;
468{
469 static struct direct dentry;
470 register int j;
471 register struct lbuf *ep;
472
473 if ((dirf = fopen(dir, "r")) == NULL) {
474 printf("%s unreadable\n", dir);
475 return;
476 }
477 tblocks = 0;
478 for(;;) {
479 if (fread(&dentry, sizeof(dentry), 1, dirf) != 1)
480 break;
481 if (dentry.d_ino==0 ||
482 aflg==0 && dentry.d_name[0]=='.' && (
483 !Aflg ||
484 dentry.d_name[1]=='\0'
485 || dentry.d_name[1]=='.' && dentry.d_name[2]=='\0'))
486 continue;
487 ep = gstat(makename(dir, dentry.d_name), 0);
488 if (ep==NULL)
489 continue;
490 if (ep->lnum != -1)
491 ep->lnum = dentry.d_ino;
492 for (j=0; j<DIRSIZ; j++)
493 ep->ln.lname[j] = dentry.d_name[j];
494 }
495 fclose(dirf);
496}
497
498struct lbuf *
499gstat(file, argfl)
500char *file;
501{
502 struct stat statb;
503 register struct lbuf *rep;
504 static int nomocore;
505
506 if (nomocore)
507 return(NULL);
508 rep = (struct lbuf *)malloc(sizeof(struct lbuf));
509 if (rep==NULL) {
510 fprintf(stderr, "ls: out of memory\n");
511 nomocore = 1;
512 return(NULL);
513 }
514 if (lastp >= &flist[NFILES]) {
515 static int msg;
516 lastp--;
517 if (msg==0) {
518 fprintf(stderr, "ls: too many files\n");
519 msg++;
520 }
521 }
522 *lastp++ = rep;
523 rep->lflags = 0;
524 rep->lnum = 0;
525 rep->ltype = '-';
526 if (argfl || statreq) {
527 if (stat(file, &statb)<0) {
528 printf("%s not found\n", file);
529 statb.st_ino = -1;
530 statb.st_size = 0;
531 statb.st_mode = 0;
532 if (argfl) {
533 lastp--;
534 return(0);
535 }
536 }
537 rep->lnum = statb.st_ino;
538 rep->lsize = statb.st_size;
539 switch(statb.st_mode&S_IFMT) {
540
541 case S_IFDIR:
542 rep->ltype = 'd';
543 break;
544
545 case S_IFBLK:
546 rep->ltype = 'b';
547 rep->lsize = statb.st_rdev;
548 break;
549
550 case S_IFCHR:
551 rep->ltype = 'c';
552 rep->lsize = statb.st_rdev;
553 break;
554 }
555 rep->lflags = statb.st_mode & ~S_IFMT;
556 rep->luid = statb.st_uid;
557 rep->lgid = statb.st_gid;
558 rep->lnl = statb.st_nlink;
559 if(uflg)
560 rep->lmtime = statb.st_atime;
561 else if (cflg)
562 rep->lmtime = statb.st_ctime;
563 else
564 rep->lmtime = statb.st_mtime;
565 tblocks += nblock(statb.st_size);
566 }
567 return(rep);
568}
569
570compar(pp1, pp2)
571struct lbuf **pp1, **pp2;
572{
573 register struct lbuf *p1, *p2;
574
575 p1 = *pp1;
576 p2 = *pp2;
577 if (dflg==0) {
578 if (p1->lflags&ISARG && p1->ltype=='d') {
579 if (!(p2->lflags&ISARG && p2->ltype=='d'))
580 return(1);
581 } else {
582 if (p2->lflags&ISARG && p2->ltype=='d')
583 return(-1);
584 }
585 }
586 if (tflg) {
587 if(p2->lmtime == p1->lmtime)
588 return(0);
589 if(p2->lmtime > p1->lmtime)
590 return(rflg);
591 return(-rflg);
592 }
593 return(rflg * strcmp(p1->lflags&ISARG? p1->ln.namep: p1->ln.lname,
594 p2->lflags&ISARG? p2->ln.namep: p2->ln.lname));
595}
596pentry(ap)
597struct lbuf *ap;
598{
599 struct { char dminor, dmajor;};
600 register t;
601 register struct lbuf *p;
602 register char *cp;
603
604 p = ap;
605 if (p->lnum == -1)
606 return;
607 column();
608 if (iflg)
609 if (nopad && !lflg)
610 printf("%d ", p->lnum);
611 else
612 printf("%5d ", p->lnum);
613 if (sflg)
614 if (nopad && !lflg)
615 printf("%D ", nblock(p->lsize));
616 else
617 printf("%4D ", nblock(p->lsize));
618 if (lflg) {
619 pputchar(p->ltype);
620 pmode(p->lflags);
621 printf("%2d ", p->lnl);
622 t = p->luid;
623 if(gflg)
624 t = p->lgid;
625 if (nflg == 0 && getname(t, tbuf)==0)
626 printf("%-8.8s", tbuf);
627 else
628 printf("%-8d", t);
629 if (p->ltype=='b' || p->ltype=='c')
630 printf("%3d,%3d", major((int)p->lsize), minor((int)p->lsize));
631 else
632 printf("%7ld", p->lsize);
633 cp = ctime(&p->lmtime);
634 if(p->lmtime < year)
635 printf(" %-7.7s %-4.4s ", cp+4, cp+20); else
636 printf(" %-12.12s ", cp+4);
637 }
638 if (p->lflags&ISARG)
639 printf("%s", p->ln.namep);
640 else
641 printf("%.14s", p->ln.lname);
642}
643/* char printf_id[] = "@(#) printf.c:2.2 6/5/79";*/
644#include "varargs.h"
645/* This version of printf is compatible with the Version 7 C
646 * printf. The differences are only minor except that this
647 * printf assumes it is to print through pputchar. Version 7
648 * printf is more general (and is much larger) and includes
649 * provisions for floating point.
650 */
651
652
653#define MAXOCT 11 /* Maximum octal digits in a long */
654#define MAXINT 32767 /* largest normal length positive integer */
655#define BIG 1000000000 /* largest power of 10 less than an unsigned long */
656#define MAXDIGS 10 /* number of digits in BIG */
657
658static int width, sign, fill;
659
660char *b_dconv();
661
662printf(va_alist)
663 va_dcl
664{
665 va_list ap;
666 register char *fmt;
667 char fcode;
668 int prec;
669 int length,mask1,nbits,n;
670 long int mask2, num;
671 register char *bptr;
672 char *ptr;
673 char buf[134];
674
675 va_start(ap);
676 fmt = va_arg(ap,char *);
677 for (;;) {
678 /* process format string first */
679 while ((fcode = *fmt++)!='%') {
680 /* ordinary (non-%) character */
681 if (fcode=='\0')
682 return;
683 pputchar(fcode);
684 }
685 /* length modifier: -1 for h, 1 for l, 0 for none */
686 length = 0;
687 /* check for a leading - sign */
688 sign = 0;
689 if (*fmt == '-') {
690 sign++;
691 fmt++;
692 }
693 /* a '0' may follow the - sign */
694 /* this is the requested fill character */
695 fill = 1;
696 if (*fmt == '0') {
697 fill--;
698 fmt++;
699 }
700
701 /* Now comes a digit string which may be a '*' */
702 if (*fmt == '*') {
703 width = va_arg(ap, int);
704 if (width < 0) {
705 width = -width;
706 sign = !sign;
707 }
708 fmt++;
709 }
710 else {
711 width = 0;
712 while (*fmt>='0' && *fmt<='9')
713 width = width * 10 + (*fmt++ - '0');
714 }
715
716 /* maybe a decimal point followed by more digits (or '*') */
717 if (*fmt=='.') {
718 if (*++fmt == '*') {
719 prec = va_arg(ap, int);
720 fmt++;
721 }
722 else {
723 prec = 0;
724 while (*fmt>='0' && *fmt<='9')
725 prec = prec * 10 + (*fmt++ - '0');
726 }
727 }
728 else
729 prec = -1;
730
731 /*
732 * At this point, "sign" is nonzero if there was
733 * a sign, "fill" is 0 if there was a leading
734 * zero and 1 otherwise, "width" and "prec"
735 * contain numbers corresponding to the digit
736 * strings before and after the decimal point,
737 * respectively, and "fmt" addresses the next
738 * character after the whole mess. If there was
739 * no decimal point, "prec" will be -1.
740 */
741 switch (*fmt) {
742 case 'L':
743 case 'l':
744 length = 2;
745 /* no break!! */
746 case 'h':
747 case 'H':
748 length--;
749 fmt++;
750 break;
751 }
752
753 /*
754 * At exit from the following switch, we will
755 * emit the characters starting at "bptr" and
756 * ending at "ptr"-1, unless fcode is '\0'.
757 */
758 switch (fcode = *fmt++) {
759 /* process characters and strings first */
760 case 'c':
761 buf[0] = va_arg(ap, int);
762 ptr = bptr = &buf[0];
763 if (buf[0] != '\0')
764 ptr++;
765 break;
766 case 's':
767 bptr = va_arg(ap,char *);
768 if (bptr==0)
769 bptr = "(null pointer)";
770 if (prec < 0)
771 prec = MAXINT;
772 for (n=0; *bptr++ && n < prec; n++) ;
773 ptr = --bptr;
774 bptr -= n;
775 break;
776 case 'O':
777 length = 1;
778 fcode = 'o';
779 /* no break */
780 case 'o':
781 case 'X':
782 case 'x':
783 if (length > 0)
784 num = va_arg(ap,long);
785 else
786 num = (unsigned)va_arg(ap,int);
787 if (fcode=='o') {
788 mask1 = 0x7;
789 mask2 = 0x1fffffffL;
790 nbits = 3;
791 }
792 else {
793 mask1 = 0xf;
794 mask2 = 0x0fffffffL;
795 nbits = 4;
796 }
797 n = (num!=0);
798 bptr = buf + MAXOCT + 3;
799 /* shift and mask for speed */
800 do
801 if (((int) num & mask1) < 10)
802 *--bptr = ((int) num & mask1) + 060;
803 else
804 *--bptr = ((int) num & mask1) + 0127;
805 while (num = (num >> nbits) & mask2);
806
807 if (fcode=='o') {
808 if (n)
809 *--bptr = '0';
810 }
811 else
812 if (!sign && fill <= 0) {
813 pputchar('0');
814 pputchar(fcode);
815 width -= 2;
816 }
817 else {
818 *--bptr = fcode;
819 *--bptr = '0';
820 }
821 ptr = buf + MAXOCT + 3;
822 break;
823 case 'D':
824 case 'U':
825 case 'I':
826 length = 1;
827 fcode = fcode + 'a' - 'A';
828 /* no break */
829 case 'd':
830 case 'i':
831 case 'u':
832 if (length > 0)
833 num = va_arg(ap,long);
834 else {
835 n = va_arg(ap,int);
836 if (fcode=='u')
837 num = (unsigned) n;
838 else
839 num = (long) n;
840 }
841 if (n = (fcode != 'u' && num < 0))
842 num = -num;
843 /* now convert to digits */
844 bptr = b_dconv(num, buf);
845 if (n)
846 *--bptr = '-';
847 if (fill == 0)
848 fill = -1;
849 ptr = buf + MAXDIGS + 1;
850 break;
851 default:
852 /* not a control character,
853 * print it.
854 */
855 ptr = bptr = &fcode;
856 ptr++;
857 break;
858 }
859 if (fcode != '\0')
860 b_emit(bptr,ptr);
861 }
862 va_end(ap);
863}
864
865/* b_dconv converts the unsigned long integer "value" to
866 * printable decimal and places it in "buffer", right-justified.
867 * The value returned is the address of the first non-zero character,
868 * or the address of the last character if all are zero.
869 * The result is NOT null terminated, and is MAXDIGS characters long,
870 * starting at buffer[1] (to allow for insertion of a sign).
871 *
872 * This program assumes it is running on 2's complement machine
873 * with reasonable overflow treatment.
874 */
875char *
876b_dconv(value, buffer)
877 long value;
878 char *buffer;
879{
880 register char *bp;
881 register int svalue;
882 int n;
883 long lval;
884
885 bp = buffer;
886
887 /* zero is a special case */
888 if (value == 0) {
889 bp += MAXDIGS;
890 *bp = '0';
891 return(bp);
892 }
893
894 /* develop the leading digit of the value in "n" */
895 n = 0;
896 while (value < 0) {
897 value -= BIG; /* will eventually underflow */
898 n++;
899 }
900 while ((lval = value - BIG) >= 0) {
901 value = lval;
902 n++;
903 }
904
905 /* stash it in buffer[1] to allow for a sign */
906 bp[1] = n + '0';
907 /*
908 * Now develop the rest of the digits. Since speed counts here,
909 * we do it in two loops. The first gets "value" down until it
910 * is no larger than MAXINT. The second one uses integer divides
911 * rather than long divides to speed it up.
912 */
913 bp += MAXDIGS + 1;
914 while (value > MAXINT) {
915 *--bp = (int)(value % 10) + '0';
916 value /= 10;
917 }
918
919 /* cannot lose precision */
920 svalue = value;
921 while (svalue > 0) {
922 *--bp = (svalue % 10) + '0';
923 svalue /= 10;
924 }
925
926 /* fill in intermediate zeroes if needed */
927 if (buffer[1] != '0') {
928 while (bp > buffer + 2)
929 *--bp = '0';
930 --bp;
931 }
932 return(bp);
933}
934
935/*
936 * This program sends string "s" to pputchar. The character after
937 * the end of "s" is given by "send". This allows the size of the
938 * field to be computed; it is stored in "alen". "width" contains the
939 * user specified length. If width<alen, the width will be taken to
940 * be alen. "sign" is zero if the string is to be right-justified
941 * in the field, nonzero if it is to be left-justified. "fill" is
942 * 0 if the string is to be padded with '0', positive if it is to be
943 * padded with ' ', and negative if an initial '-' should appear before
944 * any padding in right-justification (to avoid printing "-3" as
945 * "000-3" where "-0003" was intended).
946 */
947b_emit(s, send)
948 register char *s;
949 char *send;
950{
951 char cfill;
952 register int alen;
953 int npad;
954
955 alen = send - s;
956 if (alen > width)
957 width = alen;
958 cfill = fill>0? ' ': '0';
959
960 /* we may want to print a leading '-' before anything */
961 if (*s == '-' && fill < 0) {
962 pputchar(*s++);
963 alen--;
964 width--;
965 }
966 npad = width - alen;
967
968 /* emit any leading pad characters */
969 if (!sign)
970 while (--npad >= 0)
971 pputchar(cfill);
972
973 /* emit the string itself */
974 while (--alen >= 0)
975 pputchar(*s++);
976
977 /* emit trailing pad characters */
978 if (sign)
979 while (--npad >= 0)
980 pputchar(cfill);
981}