--- /dev/null
+/*
+ * Acess2 C Library
+ * - By John Hodge (thePowersGang)
+ *
+ * scanf.c
+ * - *scanf family of functions
+ */
+#include "lib.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <acess/sys.h> // debug!
+
+// === TYPES ===
+typedef void (*printf_putch_t)(void *h, char ch);
+
+// === PROTOTYPES ===
+void itoa(char *buf, uint64_t num, size_t base, int minLength, char pad, int bSigned);
+
+// === CODE ===
+/**
+ * \fn EXPORT void vsnprintf(char *buf, const char *format, va_list args)
+ * \brief Prints a formatted string to a buffer
+ * \param buf Pointer - Destination Buffer
+ * \param format String - Format String
+ * \param args VarArgs List - Arguments
+ */
+EXPORT int _vcprintf_int(printf_putch_t putch_cb, void *putch_h, const char *format, va_list args)
+{
+ char tmp[65];
+ int c, minSize, precision, len;
+ size_t pos = 0;
+ char *p;
+ char pad;
+ uint64_t arg;
+ int bLongLong, bPadLeft;
+
+ _SysDebug("format=%s", format);
+
+ #define _addchar(ch) do { \
+ putch_cb(putch_h, ch); \
+ pos ++; \
+ } while(0)
+
+ tmp[32] = '\0';
+
+ while((c = *format++) != 0)
+ {
+ // Non-control character
+ if (c != '%') {
+ _addchar(c);
+ continue;
+ }
+
+ // Control Character
+ c = *format++;
+ if(c == '%') { // Literal %
+ _addchar('%');
+ continue;
+ }
+
+ bPadLeft = 0;
+ bLongLong = 0;
+ minSize = 0;
+ precision = -1;
+ pad = ' ';
+
+ // Padding Character
+ if(c == '0') {
+ pad = '0';
+ c = *format++;
+ }
+ // Padding length
+ if( c == '*' ) {
+ // Variable length
+ minSize = va_arg(args, size_t);
+ c = *format++;
+ }
+ else {
+ if('1' <= c && c <= '9')
+ {
+ minSize = 0;
+ while('0' <= c && c <= '9')
+ {
+ minSize *= 10;
+ minSize += c - '0';
+ c = *format++;
+ }
+ }
+ }
+
+ // Precision
+ if(c == '.') {
+ c = *format++;
+ if(c == '*') {
+ precision = va_arg(args, size_t);
+ c = *format++;
+ }
+ else if('1' <= c && c <= '9')
+ {
+ precision = 0;
+ while('0' <= c && c <= '9')
+ {
+ precision *= 10;
+ precision += c - '0';
+ c = *format++;
+ }
+ }
+ }
+
+ // Check for long long
+ bLongLong = 0;
+ if(c == 'l')
+ {
+ c = *format++;
+ if(c == 'l') {
+ bLongLong = 1;
+ }
+ }
+
+ // Just help things along later
+ p = tmp;
+
+ // Get Type
+ switch( c )
+ {
+ // Signed Integer
+ case 'd': case 'i':
+ // Get Argument
+ if(bLongLong) arg = va_arg(args, int64_t);
+ else arg = va_arg(args, int32_t);
+ itoa(tmp, arg, 10, minSize, pad, 1);
+ precision = -1;
+ goto sprintf_puts;
+
+ // Unsigned Integer
+ case 'u':
+ // Get Argument
+ if(bLongLong) arg = va_arg(args, uint64_t);
+ else arg = va_arg(args, uint32_t);
+ itoa(tmp, arg, 10, minSize, pad, 0);
+ precision = -1;
+ goto sprintf_puts;
+
+ // Pointer
+ case 'p':
+ _addchar('*');
+ _addchar('0');
+ _addchar('x');
+ arg = va_arg(args, intptr_t);
+ itoa(tmp, arg, 16, minSize, pad, 0);
+ precision = -1;
+ goto sprintf_puts;
+ // Unsigned Hexadecimal
+ case 'x':
+ if(bLongLong) arg = va_arg(args, uint64_t);
+ else arg = va_arg(args, uint32_t);
+ itoa(tmp, arg, 16, minSize, pad, 0);
+ precision = -1;
+ goto sprintf_puts;
+
+ // Unsigned Octal
+ case 'o':
+ if(bLongLong) arg = va_arg(args, uint64_t);
+ else arg = va_arg(args, uint32_t);
+ itoa(tmp, arg, 8, minSize, pad, 0);
+ precision = -1;
+ goto sprintf_puts;
+
+ // Unsigned binary
+ case 'b':
+ if(bLongLong) arg = va_arg(args, uint64_t);
+ else arg = va_arg(args, uint32_t);
+ itoa(tmp, arg, 2, minSize, pad, 0);
+ precision = -1;
+ goto sprintf_puts;
+
+ // String
+ case 's':
+ p = va_arg(args, char*);
+ sprintf_puts:
+ if(!p) p = "(null)";
+ //_SysDebug("vsnprintf: p = '%s'", p);
+ if(precision >= 0)
+ len = strnlen(p, precision);
+ else
+ len = strlen(p);
+ if(bPadLeft) while(minSize > len++) _addchar(pad);
+ while( *p ) {
+ if(precision >= 0 && precision -- == 0)
+ break;
+ _addchar(*p++);
+ }
+ if(!bPadLeft) while(minSize > len++) _addchar(pad);
+ break;
+
+ // Unknown, just treat it as a character
+ default:
+ arg = va_arg(args, uint32_t);
+ _addchar(arg);
+ break;
+ }
+ }
+ #undef _addchar
+
+ return pos;
+}
+
+struct s_sprintf_info {
+ char *dest;
+ size_t ofs;
+ size_t maxlen;
+};
+
+void _vsnprintf_putch(void *h, char ch)
+{
+ struct s_sprintf_info *info = h;
+ if(info->ofs < info->maxlen)
+ info->dest[info->ofs++] = ch;
+}
+
+EXPORT int vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list __args)
+{
+ struct s_sprintf_info info = {__s, 0, __maxlen};
+ int ret;
+ ret = _vcprintf_int(_vsnprintf_putch, &info, __format, __args);
+ _vsnprintf_putch(&info, '\0');
+ return ret;
+}
+
+EXPORT int snprintf(char *buf, size_t maxlen, const char *format, ...)
+{
+ int ret;
+ va_list args;
+ va_start(args, format);
+ ret = vsnprintf((char*)buf, maxlen, (char*)format, args);
+ va_end(args);
+ return ret;
+}
+
+
+EXPORT int vsprintf(char * __s, const char *__format, va_list __args)
+{
+ return vsnprintf(__s, 0x7FFFFFFF, __format, __args);
+}
+EXPORT int sprintf(char *buf, const char *format, ...)
+{
+ int ret;
+ va_list args;
+ va_start(args, format);
+ ret = vsprintf((char*)buf, (char*)format, args);
+ va_end(args);
+ return ret;
+}
+
+void _vfprintf_putch(void *h, char ch)
+{
+ fputc(ch, h);
+}
+
+EXPORT int vfprintf(FILE *__fp, const char *__format, va_list __args)
+{
+ return _vcprintf_int(_vfprintf_putch, __fp, __format, __args);
+}
+
+EXPORT int fprintf(FILE *fp, const char *format, ...)
+{
+ va_list args;
+ int ret;
+
+ // Get Size
+ va_start(args, format);
+ ret = vfprintf(fp, (char*)format, args);
+ va_end(args);
+
+ return ret;
+}
+
+EXPORT int vprintf(const char *__format, va_list __args)
+{
+ return vfprintf(stdout, __format, __args);
+}
+
+EXPORT int printf(const char *format, ...)
+{
+ va_list args;
+ int ret;
+
+ // Get final size
+ va_start(args, format);
+ ret = vprintf(format, args);
+ va_end(args);
+
+ // Return
+ return ret;
+}
+
+const char cUCDIGITS[] = "0123456789ABCDEF";
+/**
+ * \brief Convert an integer into a character string
+ * \param buf Destination Buffer
+ * \param num Number to convert
+ * \param base Base-n number output
+ * \param minLength Minimum length of output
+ * \param pad Padding used to ensure minLength
+ * \param bSigned Signed number output?
+ */
+EXPORT void itoa(char *buf, uint64_t num, size_t base, int minLength, char pad, int bSigned)
+{
+ char tmpBuf[64];
+ int pos=0, i;
+
+ if(!buf) return;
+ if(base > 16 || base < 2) {
+ buf[0] = 0;
+ return;
+ }
+
+ if(bSigned && (int64_t)num < 0)
+ {
+ num = -num;
+ bSigned = 1;
+ } else
+ bSigned = 0;
+
+ // Encode into reversed string
+ while(num > base-1) {
+ tmpBuf[pos++] = cUCDIGITS[ num % base ];
+ num = (uint64_t) num / (uint64_t)base; // Shift {number} right 1 digit
+ }
+
+ tmpBuf[pos++] = cUCDIGITS[ num % base ]; // Last digit of {number}
+ if(bSigned) tmpBuf[pos++] = '-'; // Append sign symbol if needed
+
+ i = 0;
+ minLength -= pos;
+ while(minLength-- > 0) buf[i++] = pad;
+ while(pos-- > 0) buf[i++] = tmpBuf[pos]; // Reverse the order of characters
+ buf[i] = 0;
+}
return _SysSeek(fp->FD, amt, whence);\r
}\r
\r
-\r
-/**\r
- * \fn EXPORT int vfprintf(FILE *fp, const char *format, va_list args)\r
- * \brief Print to a file from a variable argument list\r
- */\r
-EXPORT int vfprintf(FILE *fp, const char *format, va_list args)\r
-{\r
- va_list tmpList;\r
- int size;\r
-\r
- if(!fp || !format) return -1;\r
-\r
- va_copy(tmpList, args);\r
- \r
- size = vsnprintf(NULL, 0, (char*)format, tmpList);\r
- char buf[size+1];\r
- vsnprintf(buf, size+1, (char*)format, args);\r
- \r
- // Write to stream\r
- fwrite(buf, size, 1, fp);\r
- \r
- // Return written byte count\r
- return size;\r
-}\r
-\r
-/**\r
- * \fn int fprintf(FILE *fp, const char *format, ...)\r
- * \brief Print a formatted string to a stream\r
- */\r
-EXPORT int fprintf(FILE *fp, const char *format, ...)\r
-{\r
- va_list args;\r
- int ret;\r
- \r
- // Get Size\r
- va_start(args, format);\r
- ret = vfprintf(fp, (char*)format, args);\r
- va_end(args);\r
- \r
- return ret;\r
-}\r
-\r
/**\r
* \fn EXPORT size_t fwrite(void *ptr, size_t size, size_t num, FILE *fp)\r
* \brief Write to a stream\r
return len;\r
}\r
\r
-EXPORT int vsprintf(char * __s, const char *__format, va_list __args)\r
-{\r
- return vsnprintf(__s, 0x7FFFFFFF, __format, __args);\r
-}\r
-\r
-\r
-/**\r
- * \fn EXPORT void vsnprintf(char *buf, const char *format, va_list args)\r
- * \brief Prints a formatted string to a buffer\r
- * \param buf Pointer - Destination Buffer\r
- * \param format String - Format String\r
- * \param args VarArgs List - Arguments\r
- */\r
-EXPORT int vsnprintf(char *buf, size_t __maxlen, const char *format, va_list args)\r
-{\r
- char tmp[65];\r
- int c, minSize, precision, len;\r
- size_t pos = 0;\r
- char *p;\r
- char pad;\r
- uint64_t arg;\r
- int bLongLong, bPadLeft;\r
-\r
- #define _addchar(ch) do { \\r
- if(buf && pos < __maxlen) buf[pos] = (ch); \\r
- else (void)(ch); \\r
- pos ++; \\r
- } while(0)\r
-\r
- tmp[32] = '\0';\r
- \r
- while((c = *format++) != 0)\r
- {\r
- // Non-control character\r
- if (c != '%') {\r
- _addchar(c);\r
- continue;\r
- }\r
- \r
- // Control Character\r
- c = *format++;\r
- if(c == '%') { // Literal %\r
- _addchar('%');\r
- continue;\r
- }\r
- \r
- bPadLeft = 0;\r
- bLongLong = 0;\r
- minSize = 0;\r
- precision = -1;\r
- pad = ' ';\r
- \r
- // Padding Character\r
- if(c == '0') {\r
- pad = '0';\r
- c = *format++;\r
- }\r
- // Padding length\r
- if( c == '*' ) {\r
- // Variable length\r
- minSize = va_arg(args, size_t);\r
- c = *format++;\r
- }\r
- else {\r
- if('1' <= c && c <= '9')\r
- {\r
- minSize = 0;\r
- while('0' <= c && c <= '9')\r
- {\r
- minSize *= 10;\r
- minSize += c - '0';\r
- c = *format++;\r
- }\r
- }\r
- }\r
-\r
- // Precision\r
- if(c == '.') {\r
- c = *format++;\r
- if(c == '*') {\r
- precision = va_arg(args, size_t);\r
- c = *format++;\r
- }\r
- else if('1' <= c && c <= '9')\r
- {\r
- precision = 0;\r
- while('0' <= c && c <= '9')\r
- {\r
- precision *= 10;\r
- precision += c - '0';\r
- c = *format++;\r
- }\r
- }\r
- }\r
- \r
- // Check for long long\r
- bLongLong = 0;\r
- if(c == 'l')\r
- {\r
- c = *format++;\r
- if(c == 'l') {\r
- bLongLong = 1;\r
- }\r
- }\r
- \r
- // Just help things along later\r
- p = tmp;\r
- \r
- // Get Type\r
- switch( c )\r
- {\r
- // Signed Integer\r
- case 'd': case 'i':\r
- // Get Argument\r
- if(bLongLong) arg = va_arg(args, int64_t);\r
- else arg = va_arg(args, int32_t);\r
- itoa(tmp, arg, 10, minSize, pad, 1);\r
- precision = -1;\r
- goto sprintf_puts;\r
- \r
- // Unsigned Integer\r
- case 'u':\r
- // Get Argument\r
- if(bLongLong) arg = va_arg(args, uint64_t);\r
- else arg = va_arg(args, uint32_t);\r
- itoa(tmp, arg, 10, minSize, pad, 0);\r
- precision = -1;\r
- goto sprintf_puts;\r
- \r
- // Pointer\r
- case 'p':\r
- _addchar('*');\r
- _addchar('0');\r
- _addchar('x');\r
- arg = va_arg(args, intptr_t);\r
- itoa(tmp, arg, 16, minSize, pad, 0);\r
- precision = -1;\r
- goto sprintf_puts;\r
- // Unsigned Hexadecimal\r
- case 'x':\r
- if(bLongLong) arg = va_arg(args, uint64_t);\r
- else arg = va_arg(args, uint32_t);\r
- itoa(tmp, arg, 16, minSize, pad, 0);\r
- precision = -1;\r
- goto sprintf_puts;\r
- \r
- // Unsigned Octal\r
- case 'o':\r
- if(bLongLong) arg = va_arg(args, uint64_t);\r
- else arg = va_arg(args, uint32_t);\r
- itoa(tmp, arg, 8, minSize, pad, 0);\r
- precision = -1;\r
- goto sprintf_puts;\r
- \r
- // Unsigned binary\r
- case 'b':\r
- if(bLongLong) arg = va_arg(args, uint64_t);\r
- else arg = va_arg(args, uint32_t);\r
- itoa(tmp, arg, 2, minSize, pad, 0);\r
- precision = -1;\r
- goto sprintf_puts;\r
-\r
- // String\r
- case 's':\r
- p = va_arg(args, char*);\r
- sprintf_puts:\r
- if(!p) p = "(null)";\r
- //_SysDebug("vsnprintf: p = '%s'", p);\r
- if(precision >= 0)\r
- len = strnlen(p, precision);\r
- else\r
- len = strlen(p);\r
- if(bPadLeft) while(minSize > len++) _addchar(pad);\r
- while( *p ) {\r
- if(precision >= 0 && precision -- == 0)\r
- break;\r
- _addchar(*p++);\r
- }\r
- if(!bPadLeft) while(minSize > len++) _addchar(pad);\r
- break;\r
-\r
- // Unknown, just treat it as a character\r
- default:\r
- arg = va_arg(args, uint32_t);\r
- _addchar(arg);\r
- break;\r
- }\r
- }\r
- _addchar('\0');\r
- pos --;\r
- #undef _addchar\r
- \r
- //_SysDebug("vsnprintf: buf = '%s'", buf);\r
- \r
- return pos;\r
-}\r
-\r
-const char cUCDIGITS[] = "0123456789ABCDEF";\r
-/**\r
- * \fn static void itoa(char *buf, uint64_t num, int base, int minLength, char pad, int bSigned)\r
- * \brief Convert an integer into a character string\r
- * \param buf Destination Buffer\r
- * \param num Number to convert\r
- * \param base Base-n number output\r
- * \param minLength Minimum length of output\r
- * \param pad Padding used to ensure minLength\r
- * \param bSigned Signed number output?\r
- */\r
-EXPORT void itoa(char *buf, uint64_t num, size_t base, int minLength, char pad, int bSigned)\r
-{\r
- char tmpBuf[64];\r
- int pos=0, i;\r
-\r
- if(!buf) return;\r
- if(base > 16 || base < 2) {\r
- buf[0] = 0;\r
- return;\r
- }\r
- \r
- if(bSigned && (int64_t)num < 0)\r
- {\r
- num = -num;\r
- bSigned = 1;\r
- } else\r
- bSigned = 0;\r
- \r
- // Encode into reversed string\r
- while(num > base-1) {\r
- tmpBuf[pos++] = cUCDIGITS[ num % base ];\r
- num = (uint64_t) num / (uint64_t)base; // Shift {number} right 1 digit\r
- }\r
-\r
- tmpBuf[pos++] = cUCDIGITS[ num % base ]; // Last digit of {number}\r
- if(bSigned) tmpBuf[pos++] = '-'; // Append sign symbol if needed\r
- \r
- i = 0;\r
- minLength -= pos;\r
- while(minLength-- > 0) buf[i++] = pad;\r
- while(pos-- > 0) buf[i++] = tmpBuf[pos]; // Reverse the order of characters\r
- buf[i] = 0;\r
-}\r
-\r
-/**\r
- * \fn EXPORT int printf(const char *format, ...)\r
- * \brief Print a string to stdout\r
- */\r
-EXPORT int printf(const char *format, ...)\r
-{\r
- int size;\r
- va_list args;\r
- \r
- // Get final size\r
- va_start(args, format);\r
- size = vsnprintf(NULL, 0, (char*)format, args);\r
- va_end(args);\r
- char buf[size+1];\r
- // Fill Buffer\r
- va_start(args, format);\r
- vsnprintf(buf, size+1, (char*)format, args);\r
- va_end(args);\r
- \r
- // Send to stdout\r
- _SysWrite(_stdout, buf, size);\r
- \r
- // Free buffer\r
- free(buf);\r
- // Return\r
- return size;\r
-}\r
-\r
-/**\r
- * \fn EXPORT int sprintf(const char *buf, char *format, ...)\r
- * \brief Print a formatted string to a buffer\r
- */\r
-EXPORT int sprintf(char *buf, const char *format, ...)\r
-{\r
- int ret;\r
- va_list args;\r
- va_start(args, format);\r
- ret = vsprintf((char*)buf, (char*)format, args);\r
- va_end(args);\r
- return ret;\r
-}\r
-\r
-/**\r
- * \fn EXPORT int snprintf(const char *buf, size_t maxlen, char *format, ...)\r
- * \brief Print a formatted string to a buffer\r
- */\r
-EXPORT int snprintf(char *buf, size_t maxlen, const char *format, ...)\r
-{\r
- int ret;\r
- va_list args;\r
- va_start(args, format);\r
- ret = vsnprintf((char*)buf, maxlen, (char*)format, args);\r
- va_end(args);\r
- return ret;\r
-}\r