|
|
1.1 root 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:
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 */
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:
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 */
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.