/** ** @file sprint.c ** ** @author Numerous CSCI-452 classes ** ** @brief C implementations of common library functions */ #ifndef SPRINT_SRC_INC #define SPRINT_SRC_INC #include #include /** ** sprint(dst,fmt,...) - formatted output into a string buffer ** ** @param dst The string buffer ** @param fmt Format string ** ** The format string parameter is followed by zero or more additional ** parameters which are interpreted according to the format string. ** ** NOTE: assumes the buffer is large enough to hold the result string ** ** NOTE: relies heavily on the x86 parameter passing convention ** (parameters are pushed onto the stack in reverse order as ** 32-bit values). */ void sprint(char *dst, char *fmt, ...) { int32_t *ap; char buf[12]; char ch; char *str; int leftadjust; int width; int len; int padchar; /* ** Get characters from the format string and process them ** ** We use the "old-school" method of handling variable numbers ** of parameters. We assume that parameters are passed on the ** runtime stack in consecutive longwords; thus, if the first ** parameter is at location 'x', the second is at 'x+4', the ** third at 'x+8', etc. We use a pointer to a 32-bit thing ** to point to the next "thing", and interpret it according ** to the format string. */ // get the pointer to the first "value" parameter ap = (int *)(&fmt) + 1; // iterate through the format string while ((ch = *fmt++) != '\0') { /* ** Is it the start of a format code? */ if (ch == '%') { /* ** Yes, get the padding and width options (if there). ** Alignment must come at the beginning, then fill, ** then width. */ leftadjust = 0; padchar = ' '; width = 0; ch = *fmt++; if (ch == '-') { leftadjust = 1; ch = *fmt++; } if (ch == '0') { padchar = '0'; ch = *fmt++; } while (ch >= '0' && ch <= '9') { width *= 10; width += ch - '0'; ch = *fmt++; } /* ** What data type do we have? */ switch (ch) { case 'c': // characters are passed as 32-bit values ch = *ap++; buf[0] = ch; buf[1] = '\0'; dst = padstr(dst, buf, 1, width, leftadjust, padchar); break; case 'd': len = cvtdec(buf, *ap++); dst = padstr(dst, buf, len, width, leftadjust, padchar); break; case 's': str = (char *)(*ap++); dst = padstr(dst, str, -1, width, leftadjust, padchar); break; case 'x': len = cvthex(buf, *ap++); dst = padstr(dst, buf, len, width, leftadjust, padchar); break; case 'o': len = cvtoct(buf, *ap++); dst = padstr(dst, buf, len, width, leftadjust, padchar); break; case 'u': len = cvtuns(buf, *ap++); dst = padstr(dst, buf, len, width, leftadjust, padchar); break; } } else { // no, it's just an ordinary character *dst++ = ch; } } // NUL-terminate the result *dst = '\0'; } #endif