|
|
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.