source: trunk/minix/commands/elvis/tinyprnt.c@ 15

Last change on this file since 15 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 4.7 KB
Line 
1/* tinyprnt.c */
2
3#if OSK
4#define sprintf Sprintf
5#endif
6
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.
10 *
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.
14 */
15
16/* Place-holders in format strings look like "%<pad><clip><type>".
17 *
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.
22 *
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.
28 *
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.
32 */
33
34/* NOTE: Variable argument lists are handled by direct stack-twiddling. Sorry! */
35
36static 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 */
40{
41 static char digits[] = "0123456789abcdef";
42 unsigned long tmp;
43
44 /* if the number is 0, then just stuff a "0" into the buffer */
45 if (num == 0L)
46 {
47 buf[0] = '0';
48 buf[1] = '\0';
49 return;
50 }
51
52 /* use tmp to figure out how many digits we'll need */
53 for (tmp = num; tmp > 0; tmp /= base)
54 {
55 buf++;
56 }
57
58 /* mark the spot that will be the end of the string */
59 *buf = '\0';
60
61 /* generate all digits, as needed */
62 for (tmp = num; tmp > 0; tmp /= base)
63 {
64 *--buf = digits[tmp % base];
65 }
66}
67
68int 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 */
72{
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;
79
80 /* make argptr point to the first argument after the format string */
81 argptr = (char *)&argref;
82
83 /* loop through the whole format string */
84 while (*fmt)
85 {
86 /* if not part of a place-holder, then copy it literally */
87 if (*fmt != '%')
88 {
89 *buf++ = *fmt++;
90 continue;
91 }
92
93 /* found a place-holder! Get <pad> value */
94 fmt++;
95 if ('*' == *fmt)
96 {
97 pad = *((int *)argptr)++;
98 fmt++;
99 }
100 else if (*fmt == '-' || (*fmt >= '0' && *fmt <= '9'))
101 {
102 pad = atol(fmt);
103 do
104 {
105 fmt++;
106 } while (*fmt >= '0' && *fmt <= '9');
107 }
108 else
109 {
110 pad = 0;
111 }
112
113 /* get a <clip> value */
114 if (*fmt == '.')
115 {
116 fmt++;
117 if ('*' == *fmt)
118 {
119 clip = *((int *)argptr)++;
120 fmt++;
121 }
122 else if (*fmt >= '0' && *fmt <= '9')
123 {
124 clip = atol(fmt);
125 do
126 {
127 fmt++;
128 } while (*fmt >= '0' && *fmt <= '9');
129 }
130 }
131 else
132 {
133 clip = 0;
134 }
135
136 /* handle <type>, possibly noticing <clip> */
137 switch (*fmt++)
138 {
139 case 'c':
140 buf[0] = *((int *)argptr)++;
141 buf[1] = '\0';
142 break;
143
144 case 's':
145 src = *((char **)argptr)++;
146 if (!src)
147 {
148 src = "(null)";
149 }
150 if (clip)
151 {
152 strncpy(buf, src, clip);
153 buf[clip] = '\0';
154 }
155 else
156 {
157 strcpy(buf, src);
158 }
159 break;
160
161 case 'l':
162 fmt++; /* to skip the "d" in "%ld" */
163 num = *((long *)argptr)++;
164 dst = buf;
165 if (num < 0)
166 {
167 *dst++ = '-';
168 num = -num;
169 }
170 cvtnum(dst, num, 10);
171 break;
172
173 case 'x':
174 num = *((int *)argptr)++;
175 cvtnum(buf, num, 16);
176 break;
177
178 case 'd':
179 num = *((int *)argptr)++;
180 dst = buf;
181 if (num < 0)
182 {
183 *dst++ = '-';
184 num = -num;
185 }
186 cvtnum(dst, num, 10);
187 break;
188
189 default:
190 buf[0] = fmt[-1];
191 buf[1] = '\0';
192 }
193
194 /* now fix the padding, if the value is too short */
195 clip = strlen(buf);
196 if (pad < 0)
197 {
198 /* add spaces after the value */
199 pad = -pad - clip;
200 for (buf += clip; pad > 0; pad--)
201 {
202 *buf++ = ' ';
203 }
204 *buf = '\0';
205 }
206 else
207 {
208 /* add spaces before the value */
209 pad -= clip;
210 if (pad > 0)
211 {
212 src = buf + clip;
213 dst = src + pad;
214 *dst = '\0';
215 while (src > buf)
216 {
217 *--dst = *--src;
218 }
219 while (dst > buf)
220 {
221 *--dst = ' ';
222 }
223 }
224 buf += strlen(buf);
225 }
226 }
227
228 /* mark the end of the output string */
229 *buf = '\0';
230}
Note: See TracBrowser for help on using the repository browser.