123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369 |
- /*
- * printf.c
- *
- * Copyright (C) 2018 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <monolithium.h>
- #include "io_priv.h"
- #define __CRT_PRINTF_FLAG_ALIGN_LEFT (1 << 0)
- #define __CRT_PRINTF_FLAG_PLUS (1 << 1)
- #define __CRT_PRINTF_FLAG_SPACE (1 << 2)
- #define __CRT_PRINTF_FLAG_EXTRA (1 << 3)
- #define __CRT_PRINTF_FLAG_ZERO_PAD (1 << 4)
- #define __CRT_PRINTF_FLAG_EXTERNAL_WIDTH (1 << 5)
- #define __CRT_PRINTF_FLAG_EXTERNAL_PRECISION (1 << 6)
- #define __CRT_PRINTF_FLAG_DEFAULT_WIDTH (1 << 7)
- #define __CRT_PRINTF_FLAG_DEFAULT_PRECISION (1 << 8)
- typedef struct
- {
- FILE *stream;
- char *string;
- size_t size;
- } __crt_stream_or_string_t;
- static int __crt_strputc(__crt_stream_or_string_t *str, char c)
- {
- if (str->stream)
- {
- return fputc_unlocked(c, str->stream) != EOF;
- }
- else
- {
- if (str->size > 1)
- {
- *str->string++ = c;
- str->size--;
- }
- return 1;
- }
- }
- static int __crt_strputs(__crt_stream_or_string_t *str, const char *s)
- {
- if (str->stream)
- {
- return fputs_unlocked(s, str->stream) != EOF ? strlen(s) : 0;
- }
- else
- {
- int length = strlen(s);
- if (str->size > 1)
- {
- strncpy(str->string, s, str->size - 1);
- if (length < str->size)
- {
- str->string += length;
- str->size -= length;
- }
- else
- {
- str->string += str->size - 1;
- str->size = 0;
- }
- }
- return length;
- }
- }
- static inline int __crt_vstrprintf(__crt_stream_or_string_t *str, const char *format, va_list ap)
- {
- int ret = 0;
- if (str->stream) syscall_wait_mutex(str->stream->mutex, NO_TIMEOUT);
- const char *ptr;
- for (ptr = format; *ptr; ptr++)
- {
- if (*ptr == '%')
- {
- unsigned long flags = 0;
- unsigned int width = 0, precision = 0;
- ptr++;
- while (*ptr)
- {
- if (*ptr == '-') flags |= __CRT_PRINTF_FLAG_ALIGN_LEFT;
- else if (*ptr == '+') flags |= __CRT_PRINTF_FLAG_PLUS;
- else if (*ptr == ' ') flags |= __CRT_PRINTF_FLAG_SPACE;
- else if (*ptr == '#') flags |= __CRT_PRINTF_FLAG_EXTRA;
- else if (*ptr == '0') flags |= __CRT_PRINTF_FLAG_ZERO_PAD;
- else break;
- ptr++;
- }
- if (*ptr == '*') flags |= __CRT_PRINTF_FLAG_EXTERNAL_WIDTH;
- else if (isdigit(*ptr)) width = strtoul(ptr, (char**)&ptr, 10);
- else flags |= __CRT_PRINTF_FLAG_DEFAULT_WIDTH;
- if (*ptr == '.')
- {
- ptr++;
- if (*ptr == '*') flags |= __CRT_PRINTF_FLAG_EXTERNAL_PRECISION;
- else if (isdigit(*ptr)) precision = strtoul(ptr, (char**)&ptr, 10);
- else flags |= __CRT_PRINTF_FLAG_DEFAULT_PRECISION;
- }
- else
- {
- flags |= __CRT_PRINTF_FLAG_DEFAULT_PRECISION;
- }
- int variable_size = 0;
- if (*ptr == 'h')
- {
- variable_size--;
- if (*++ptr == 'h')
- {
- variable_size--;
- ptr++;
- }
- }
- else if (*ptr == 'l')
- {
- variable_size++;
- if (*++ptr == 'l')
- {
- variable_size++;
- ptr++;
- }
- }
- const char *data = NULL;
- char buffer[512];
- int radix = 10;
- switch (*ptr)
- {
- case 's':
- data = va_arg(ap, const char*);
- break;
- case 'c':
- data = buffer;
- buffer[0] = (char)va_arg(ap, int);
- buffer[1] = '\0';
- break;
- case 'd':
- case 'i':
- if (flags & __CRT_PRINTF_FLAG_DEFAULT_WIDTH) width = 0;
- if (flags & __CRT_PRINTF_FLAG_DEFAULT_PRECISION) precision = 1;
- data = buffer;
- switch (variable_size)
- {
- case -2: itoa((char)va_arg(ap, int), buffer, 10); break;
- case -1: itoa((short)va_arg(ap, int), buffer, 10); break;
- case 0: itoa(va_arg(ap, int), buffer, 10); break;
- case 1: ltoa(va_arg(ap, long), buffer, 10); break;
- case 2: lltoa(va_arg(ap, long long), buffer, 10); break;
- }
- break;
- case 'o':
- radix = 8;
- goto read_variable;
- case 'x':
- case 'X':
- radix = 16;
- case 'u':
- read_variable:
- if (flags & __CRT_PRINTF_FLAG_DEFAULT_WIDTH) width = 0;
- if (flags & __CRT_PRINTF_FLAG_DEFAULT_PRECISION) precision = 1;
- data = buffer;
- switch (variable_size)
- {
- case -2: uitoa((unsigned char)va_arg(ap, unsigned int), buffer, radix); break;
- case -1: uitoa((unsigned short)va_arg(ap, unsigned int), buffer, radix); break;
- case 0: uitoa(va_arg(ap, unsigned int), buffer, radix); break;
- case 1: ultoa(va_arg(ap, unsigned long), buffer, radix); break;
- case 2: ulltoa(va_arg(ap, unsigned long long), buffer, radix); break;
- }
- break;
- case '%':
- data = buffer;
- strcpy(buffer, "%");
- break;
- }
- if (flags & __CRT_PRINTF_FLAG_EXTERNAL_WIDTH) width = va_arg(ap, unsigned int);
- if (flags & __CRT_PRINTF_FLAG_EXTERNAL_PRECISION) precision = va_arg(ap, unsigned int);
- int length = strlen(data);
- char padding = (flags &__CRT_PRINTF_FLAG_ZERO_PAD) ? '0' : ' ';
- switch (*ptr)
- {
- case 's':
- if (!(flags & __CRT_PRINTF_FLAG_ALIGN_LEFT))
- {
- while (length < width)
- {
- ret += __crt_strputc(str, padding);
- length++;
- }
- }
- if (precision)
- {
- while (*data && precision > 0)
- {
- ret += __crt_strputc(str, *data++);
- precision--;
- }
- }
- else
- {
- ret += __crt_strputs(str, data ? data : "(null)");
- }
- break;
- case 'd':
- case 'i':
- case 'o':
- case 'u':
- case 'x':
- case 'X':
- if (flags & (__CRT_PRINTF_FLAG_PLUS | __CRT_PRINTF_FLAG_SPACE))
- {
- if (*data == '-')
- {
- ret += __crt_strputc(str, '-');
- data++;
- }
- else
- {
- ret += __crt_strputc(str, (flags & __CRT_PRINTF_FLAG_PLUS) ? '+' : ' ');
- length++;
- }
- }
- if (!(flags & __CRT_PRINTF_FLAG_ALIGN_LEFT) && width > precision)
- {
- while (length < width - precision)
- {
- ret += __crt_strputc(str, padding);
- length++;
- }
- while (length < width)
- {
- ret += __crt_strputc(str, '0');
- length++;
- }
- }
- else
- {
- while (length < precision)
- {
- ret += __crt_strputc(str, '0');
- length++;
- }
- }
- ret += __crt_strputs(str, data);
- break;
- }
- while (length < width)
- {
- ret += __crt_strputc(str, padding);
- length++;
- }
- }
- else
- {
- ret += __crt_strputc(str, *ptr);
- }
- }
- if (str->string) *str->string = '\0';
- if (str->stream) syscall_release_mutex(str->stream->mutex);
- return ret;
- }
- int vsnprintf(char *string, size_t size, const char *format, va_list ap)
- {
- __crt_stream_or_string_t str = { .stream = NULL, .string = string, .size = size };
- return __crt_vstrprintf(&str, format, ap);
- }
- int vsprintf(char *str, const char *format, va_list ap)
- {
- return vsnprintf(str, -1, format, ap);
- }
- int vprintf(const char *format, va_list ap)
- {
- return vfprintf(stdout, format, ap);
- }
- int vfprintf(FILE *stream, const char *format, va_list ap)
- {
- __crt_stream_or_string_t str = { .stream = stream, .string = NULL, .size = 0 };
- return __crt_vstrprintf(&str, format, ap);
- }
- int fprintf(FILE *stream, const char *format, ...)
- {
- va_list ap;
- va_start(ap, format);
- int ret = vfprintf(stream, format, ap);
- va_end(ap);
- return ret;
- }
- int snprintf(char *str, size_t size, const char *format, ...)
- {
- va_list ap;
- va_start(ap, format);
- int ret = vsnprintf(str, size, format, ap);
- va_end(ap);
- return ret;
- }
- int sprintf(char *str, const char *format, ...)
- {
- va_list ap;
- va_start(ap, format);
- int ret = vsprintf(str, format, ap);
- va_end(ap);
- return ret;
- }
- int printf(const char *format, ...)
- {
- va_list ap;
- va_start(ap, format);
- int ret = vprintf(format, ap);
- va_end(ap);
- return ret;
- }
|