unstack, sort: cleanup and improvement
[minix.git] / commands / elvis / tinyprnt.c
blobc67add651038f8ef832e09ba7fef10df9fa1e8d7
1 /* tinyprnt.c */
3 #if OSK
4 #define sprintf Sprintf
5 #endif
7 /* This is a limited version of sprintf(). It is useful for Minix-PC and
8 * Coherent-286 because those systems are both limited to 64k+64k and the
9 * standard sprintf() is just too damn big.
11 * It should also be useful for OS-9 because OS-9's sprintf() doesn't
12 * understand the true meaning of asterisks in a format string. This one
13 * does.
16 /* Place-holders in format strings look like "%<pad><clip><type>".
18 * The <pad> adds space to the front (or, if negative, to the back) of the
19 * output value, to pad it to a given width. If <pad> is absent, then 0 is
20 * assumed. If <pad> is an asterisk, then the next argument is assumed to
21 * be an (int) which used as the pad width.
23 * The <clip> string can be absent, in which case no clipping is done.
24 * However, if it is present, then it should be either a "." followed by
25 * a number, or a "." followed by an asterisk. The asterisk means that the
26 * next argument is an (int) which should be used as the pad width. Clipping
27 * only affects strings; for other data types it is ignored.
29 * The <type> is one of "s" for strings, "c" for characters (really ints that
30 * are assumed to be legal char values), "d" for ints, "ld" for long ints, or
31 * "%" to output a percent sign.
34 /* NOTE: Variable argument lists are handled by direct stack-twiddling. Sorry! */
36 static void cvtnum(buf, num, base)
37 char *buf; /* where to store the number */
38 unsigned long num; /* the number to convert */
39 int base; /* either 8, 10, or 16 */
41 static char digits[] = "0123456789abcdef";
42 unsigned long tmp;
44 /* if the number is 0, then just stuff a "0" into the buffer */
45 if (num == 0L)
47 buf[0] = '0';
48 buf[1] = '\0';
49 return;
52 /* use tmp to figure out how many digits we'll need */
53 for (tmp = num; tmp > 0; tmp /= base)
55 buf++;
58 /* mark the spot that will be the end of the string */
59 *buf = '\0';
61 /* generate all digits, as needed */
62 for (tmp = num; tmp > 0; tmp /= base)
64 *--buf = digits[tmp % base];
68 int sprintf(buf, fmt, argref)
69 char *buf; /* where to deposit the formatted output */
70 char *fmt; /* the format string */
71 int argref; /* the first argument is located at &argref */
73 char *argptr;/* pointer to next argument on the stack */
74 int pad; /* value of the pad string */
75 int clip; /* value of the clip string */
76 long num; /* a binary number being converted to ASCII digits */
77 long digit; /* used during conversion */
78 char *src, *dst;
80 /* make argptr point to the first argument after the format string */
81 argptr = (char *)&argref;
83 /* loop through the whole format string */
84 while (*fmt)
86 /* if not part of a place-holder, then copy it literally */
87 if (*fmt != '%')
89 *buf++ = *fmt++;
90 continue;
93 /* found a place-holder! Get <pad> value */
94 fmt++;
95 if ('*' == *fmt)
97 pad = *((int *)argptr)++;
98 fmt++;
100 else if (*fmt == '-' || (*fmt >= '0' && *fmt <= '9'))
102 pad = atol(fmt);
105 fmt++;
106 } while (*fmt >= '0' && *fmt <= '9');
108 else
110 pad = 0;
113 /* get a <clip> value */
114 if (*fmt == '.')
116 fmt++;
117 if ('*' == *fmt)
119 clip = *((int *)argptr)++;
120 fmt++;
122 else if (*fmt >= '0' && *fmt <= '9')
124 clip = atol(fmt);
127 fmt++;
128 } while (*fmt >= '0' && *fmt <= '9');
131 else
133 clip = 0;
136 /* handle <type>, possibly noticing <clip> */
137 switch (*fmt++)
139 case 'c':
140 buf[0] = *((int *)argptr)++;
141 buf[1] = '\0';
142 break;
144 case 's':
145 src = *((char **)argptr)++;
146 if (!src)
148 src = "(null)";
150 if (clip)
152 strncpy(buf, src, clip);
153 buf[clip] = '\0';
155 else
157 strcpy(buf, src);
159 break;
161 case 'l':
162 fmt++; /* to skip the "d" in "%ld" */
163 num = *((long *)argptr)++;
164 dst = buf;
165 if (num < 0)
167 *dst++ = '-';
168 num = -num;
170 cvtnum(dst, num, 10);
171 break;
173 case 'x':
174 num = *((int *)argptr)++;
175 cvtnum(buf, num, 16);
176 break;
178 case 'd':
179 num = *((int *)argptr)++;
180 dst = buf;
181 if (num < 0)
183 *dst++ = '-';
184 num = -num;
186 cvtnum(dst, num, 10);
187 break;
189 default:
190 buf[0] = fmt[-1];
191 buf[1] = '\0';
194 /* now fix the padding, if the value is too short */
195 clip = strlen(buf);
196 if (pad < 0)
198 /* add spaces after the value */
199 pad = -pad - clip;
200 for (buf += clip; pad > 0; pad--)
202 *buf++ = ' ';
204 *buf = '\0';
206 else
208 /* add spaces before the value */
209 pad -= clip;
210 if (pad > 0)
212 src = buf + clip;
213 dst = src + pad;
214 *dst = '\0';
215 while (src > buf)
217 *--dst = *--src;
219 while (dst > buf)
221 *--dst = ' ';
224 buf += strlen(buf);
228 /* mark the end of the output string */
229 *buf = '\0';