summaryrefslogtreecommitdiff
path: root/lib/sprint.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--lib/sprint.c133
1 files changed, 133 insertions, 0 deletions
diff --git a/lib/sprint.c b/lib/sprint.c
new file mode 100644
index 0000000..d2e0a7e
--- /dev/null
+++ b/lib/sprint.c
@@ -0,0 +1,133 @@
+/**
+** @file sprint.c
+**
+** @author Numerous CSCI-452 classes
+**
+** @brief C implementations of common library functions
+*/
+
+#ifndef SPRINT_SRC_INC
+#define SPRINT_SRC_INC
+
+#include <common.h>
+
+#include <lib.h>
+
+/**
+** 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