123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845 |
- #include <assert.h>
- #include <devutil.h>
- #include <fcntl.h>
- #include <list.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <priv-vars.h>
- static inline int __feof_or_error(FILE* stream)
- {
- return !!(stream->flags & (FILE_ERROR | FILE_EOF));
- }
- // where n is in the range of [0, 9]
- static inline char d_to_c(int32_t n)
- {
- return '0' + n;
- }
- // where n is between 0 and 15
- // base is either 'a' of 'A',
- // depending on you want capitalized
- // or not
- static inline char hex_to_c(int32_t n, char base)
- {
- if (n < 10) {
- // n belongs to [0, 9]
- return d_to_c(n);
- } else {
- // n belongs to [10, 15]
- return base + (n - 10);
- }
- }
- static inline char x_to_c(int32_t n)
- {
- return hex_to_c(n, 'a');
- }
- static inline char X_to_c(int32_t n)
- {
- return hex_to_c(n, 'A');
- }
- // this will check if there is still free space
- // in the buffer. if so, push the char into it,
- // change the value of buf_size and move pointer
- // forward
- //
- // x: char* buf
- // y: size_t buf_size
- // z: char c
- #define do_write_if_free(x, y, z) \
- if ((y) > 1) { \
- *((x)++) = (z); \
- --(y); \
- }
- static inline ssize_t
- snprint_decimal32(
- char* buf,
- size_t buf_size,
- int32_t num)
- {
- ssize_t n_write = 0;
- if (num < 0) {
- do_write_if_free(buf, buf_size, '-');
- ++n_write;
- num *= (-1);
- }
- char* orig_buf = buf;
- do {
- do_write_if_free(buf, buf_size, d_to_c(num % 10));
- num /= 10;
- ++n_write;
- } while (num != 0);
- // prepend trailing '\0'
- if (buf_size > 0)
- *buf = 0x00;
- // move buf pointer to the last digit of number
- --buf;
- // reverse output
- while (orig_buf < buf) {
- char c = *buf;
- *buf = *orig_buf;
- *orig_buf = c;
- --buf;
- ++orig_buf;
- }
- return n_write;
- }
- static inline ssize_t
- snprint_decimal64(
- char* buf,
- size_t buf_size,
- int64_t num)
- {
- ssize_t n_write = 0;
- if (num < 0) {
- do_write_if_free(buf, buf_size, '-');
- ++n_write;
- num *= (-1);
- }
- char* orig_buf = buf;
- do {
- do_write_if_free(buf, buf_size, d_to_c(num % 10));
- num /= 10;
- ++n_write;
- } while (num != 0);
- // prepend trailing '\0'
- if (buf_size > 0)
- *buf = 0x00;
- // move buf pointer to the last digit of number
- --buf;
- // reverse output
- while (orig_buf < buf) {
- char c = *buf;
- *buf = *orig_buf;
- *orig_buf = c;
- --buf;
- ++orig_buf;
- }
- return n_write;
- }
- static inline ssize_t
- snprint_hex32(
- char* buf,
- size_t buf_size,
- uint32_t num,
- int32_t capitalized)
- {
- ssize_t n_write = 0;
- do_write_if_free(buf, buf_size, '0');
- if (capitalized) {
- do_write_if_free(buf, buf_size, 'X');
- } else {
- do_write_if_free(buf, buf_size, 'x');
- }
- n_write += 2;
- char* orig_buf = buf;
- do {
- if (capitalized) {
- do_write_if_free(buf, buf_size, X_to_c(num % 16));
- } else {
- do_write_if_free(buf, buf_size, x_to_c(num % 16));
- }
- num /= 16;
- ++n_write;
- } while (num != 0);
- // prepend trailing '\0'
- if (buf_size > 0)
- *buf = 0x00;
- // move buf pointer to the last digit of number
- --buf;
- // reverse output
- while (orig_buf < buf) {
- char c = *buf;
- *buf = *orig_buf;
- *orig_buf = c;
- --buf;
- ++orig_buf;
- }
- return n_write;
- }
- static inline ssize_t
- snprint_hex64(
- char* buf,
- size_t buf_size,
- uint64_t num,
- int32_t capitalized)
- {
- ssize_t n_write = 0;
- do_write_if_free(buf, buf_size, '0');
- if (capitalized) {
- do_write_if_free(buf, buf_size, 'X');
- } else {
- do_write_if_free(buf, buf_size, 'x');
- }
- n_write += 2;
- char* orig_buf = buf;
- do {
- if (capitalized) {
- do_write_if_free(buf, buf_size, X_to_c(num % 16));
- } else {
- do_write_if_free(buf, buf_size, x_to_c(num % 16));
- }
- num /= 16;
- ++n_write;
- } while (num != 0);
- // prepend trailing '\0'
- if (buf_size > 0)
- *buf = 0x00;
- // move buf pointer to the last digit of number
- --buf;
- // reverse output
- while (orig_buf < buf) {
- char c = *buf;
- *buf = *orig_buf;
- *orig_buf = c;
- --buf;
- ++orig_buf;
- }
- return n_write;
- }
- static inline ssize_t
- snprint_char(
- char* buf,
- size_t buf_size,
- char c)
- {
- if (buf_size > 1)
- *buf = c;
- return sizeof(c);
- }
- int snprintf(char* buf, size_t bufsize, const char* fmt, ...)
- {
- va_list lst;
- va_start(lst, fmt);
- int ret = vsnprintf(buf, bufsize, fmt, lst);
- va_end(lst);
- return ret;
- }
- int vsnprintf(char* buf, size_t buf_size, const char* fmt, va_list arg)
- {
- ssize_t n_write = 0;
- for (char c; (c = *fmt) != 0x00; ++fmt) {
- if (c == '%') {
- size_t n_tmp_write = 0;
- switch (*(++fmt)) {
- // int
- case 'd':
- n_tmp_write = snprint_decimal32(buf, buf_size, va_arg(arg, int));
- break;
- case 'x':
- n_tmp_write = snprint_hex32(buf, buf_size, va_arg(arg, unsigned int), 0);
- break;
- case 'X':
- n_tmp_write = snprint_hex32(buf, buf_size, va_arg(arg, unsigned int), 1);
- break;
- // long decimal
- case 'l':
- switch (*(++fmt)) {
- // long long aka int64
- case 'l':
- switch (*(++fmt)) {
- case 'd':
- n_tmp_write = snprint_decimal64(buf, buf_size, va_arg(arg, long long));
- break;
- case 'x':
- n_tmp_write = snprint_hex64(buf, buf_size, va_arg(arg, unsigned long long), 0);
- break;
- case 'X':
- n_tmp_write = snprint_hex64(buf, buf_size, va_arg(arg, unsigned long long), 1);
- break;
- }
- break;
- // long int aka int32
- case 'd':
- n_tmp_write = snprint_decimal32(buf, buf_size, va_arg(arg, long));
- break;
- case 'x':
- n_tmp_write = snprint_hex32(buf, buf_size, va_arg(arg, unsigned long), 0);
- break;
- case 'X':
- n_tmp_write = snprint_hex32(buf, buf_size, va_arg(arg, unsigned long), 1);
- break;
- }
- break;
- // c string
- case 's':
- n_tmp_write = snprintf(buf, buf_size, va_arg(arg, const char*));
- break;
- // int8 char
- case 'c':
- n_tmp_write = snprint_char(buf, buf_size, va_arg(arg, int));
- break;
- // pointer
- case 'p':
- #ifdef __32bit_system
- n_tmp_write = snprint_hex32(buf, buf_size, va_arg(arg, size_t), 0);
- #else
- n_tmp_write = snprint_hex64(buf, buf_size, va_arg(arg, size_t), 0);
- #endif
- break;
- default:
- n_tmp_write = snprint_char(buf, buf_size, *(fmt - 1));
- break;
- }
- n_write += n_tmp_write;
- if (buf_size > 1) {
- if (buf_size > n_tmp_write) {
- buf += n_tmp_write;
- buf_size -= n_tmp_write;
- } else {
- // no enough space
- // shrink buf_size to one
- buf += (buf_size - 1);
- buf_size = 1;
- }
- }
- } else {
- ++n_write;
- do_write_if_free(buf, buf_size, c);
- }
- }
- if (buf_size > 0)
- *buf = 0x00;
- return n_write;
- }
- int sprintf(char* buf, const char* fmt, ...)
- {
- va_list lst;
- va_start(lst, fmt);
- int ret = vsnprintf(buf, __SIZE_MAX__, fmt, lst);
- va_end(lst);
- return ret;
- }
- int puts(const char* str)
- {
- return fputs(str, stdout);
- }
- char* gets(char* buf)
- {
- int c, num = 0;
- while ((c = getchar()) != EOF && c != '\n')
- buf[num++] = c;
- buf[num] = 0;
- if (c == EOF)
- return NULL;
- return buf;
- }
- int vfprintf_u32(uint32_t num, FILE* stream)
- {
- if (num <= 9) {
- fputc(d_to_c(num), stream);
- return 1;
- }
- int ret = vfprintf_u32(num / 10, stream);
- fputc(d_to_c(num % 10), stream);
- return ret + 1;
- }
- int vfprintf_d32(int32_t num, FILE* stream)
- {
- if (num < 0) {
- fputc('-', stream);
- return vfprintf_u32(-num, stream) + 1;
- }
- return vfprintf_u32(num, stream);
- }
- int vfprintf_u64(uint64_t num, FILE* stream)
- {
- if (num <= 9) {
- fputc(d_to_c(num), stream);
- return 1;
- }
- int ret = vfprintf_u64(num / 10, stream);
- fputc(d_to_c(num % 10), stream);
- return ret + 1;
- }
- int vfprintf_d64(int64_t num, FILE* stream)
- {
- if (num < 0) {
- fputc('-', stream);
- return vfprintf_u64(-num, stream) + 1;
- }
- return vfprintf_u64(num, stream);
- }
- int vfprintf_x32(uint32_t num, int off, FILE* stream)
- {
- // print leading 0x
- if (off & 1) {
- --off;
- fputc('0', stream);
- fputc('X' + off, stream);
- return vfprintf_x32(num, off, stream) + 2;
- }
- if (num <= 15) {
- fputc(X_to_c(num) + off, stream);
- return 1;
- }
- int ret = vfprintf_x32(num >> 4, off, stream);
- fputc(X_to_c(num & 0xf) + off, stream);
- return ret + 1;
- }
- int vfprintf_x64(uint64_t num, int off, FILE* stream)
- {
- // print leading 0x
- if (off & 1) {
- --off;
- fputc('0', stream);
- fputc('X' + off, stream);
- return vfprintf_x64(num, off, stream) + 2;
- }
- if (num <= 15) {
- fputc(X_to_c(num) + off, stream);
- return 1;
- }
- int ret = vfprintf_x64(num >> 4, off, stream);
- fputc(X_to_c(num & 0xf) + off, stream);
- return ret + 1;
- }
- int vfprintf(FILE* stream, const char* fmt, va_list args)
- {
- int n = 0;
- for (char c = 0; (c = *fmt) != 0x00; ++fmt) {
- if (c == '%') {
- switch (*(++fmt)) {
- // int
- case 'd':
- n += vfprintf_d32(va_arg(args, int), stream);
- break;
- case 'x':
- n += vfprintf_x32(va_arg(args, unsigned int), 'a' - 'A' + 1, stream);
- break;
- case 'X':
- n += vfprintf_x32(va_arg(args, unsigned int), 1, stream);
- break;
- // long decimal
- case 'l':
- switch (*(++fmt)) {
- // long long aka int64
- case 'l':
- switch (*(++fmt)) {
- case 'd':
- n += vfprintf_d64(va_arg(args, long long), stream);
- break;
- case 'x':
- n += vfprintf_x64(va_arg(args, unsigned long long), 'a' - 'A' + 1, stream);
- break;
- case 'X':
- n += vfprintf_x64(va_arg(args, unsigned long long), 'a' - 'A' + 1, stream);
- break;
- }
- break;
- // long int aka int32
- case 'd':
- n += vfprintf_d32(va_arg(args, int), stream);
- break;
- case 'x':
- n += vfprintf_x32(va_arg(args, unsigned int), 'a' - 'A' + 1, stream);
- break;
- case 'X':
- n += vfprintf_x32(va_arg(args, unsigned int), 1, stream);
- break;
- }
- break;
- // c string
- case 's':
- n += fprintf(stream, va_arg(args, const char*));
- break;
- // int8 char
- case 'c':
- ++n;
- fputc(va_arg(args, int), stream);
- break;
- // pointer
- case 'p':
- #ifdef __32bit_system
- n += vfprintf_x32(va_arg(args, size_t), 'a' - 'A' + 1, stream);
- #else
- n += vfprintf_x64(va_arg(args, size_t), 'a' - 'A' + 1, stream);
- #endif
- break;
- default:
- ++n;
- fputc(*(fmt - 1), stream);
- break;
- }
- } else {
- ++n;
- fputc(c, stream);
- }
- }
- return n;
- }
- int fprintf(FILE* stream, const char* fmt, ...)
- {
- va_list args;
- va_start(args, fmt);
- int ret = vfprintf(stream, fmt, args);
- va_end(args);
- return ret;
- }
- int vprintf(const char* fmt, va_list args)
- {
- return vfprintf(stdout, fmt, args);
- }
- int printf(const char* fmt, ...)
- {
- va_list args;
- va_start(args, fmt);
- int ret = vprintf(fmt, args);
- va_end(args);
- return ret;
- }
- int putchar(int c)
- {
- fputc(c, stdout);
- return c;
- }
- FILE* fopen(const char* path, const char* mode)
- {
- uint32_t flags = 0, file_flags = 0;
- if (strcmp(mode, "r") == 0)
- flags = O_RDONLY, file_flags = FILE_READ;
- if (strcmp(mode, "r+") == 0)
- flags = O_RDWR, file_flags = FILE_READ | FILE_WRITE;
- if (strcmp(mode, "w") == 0)
- flags = O_WRONLY | O_CREAT | O_TRUNC, file_flags = FILE_WRITE;
- if (strcmp(mode, "w+") == 0)
- flags = O_RDWR | O_CREAT | O_TRUNC, file_flags = FILE_READ | FILE_WRITE;
-
- assert(flags);
- int fd = open(path, flags, 0644);
- if (fd < 0)
- goto open_fail;
-
- FILE* file = malloc(sizeof(FILE));
- if (!file)
- goto file_malloc_fail;
-
- file->fd = fd;
- file->flags = file_flags;
- if (file_flags & FILE_READ) {
- file->rbuf = malloc(BUFSIZ);
- if (!file->rbuf)
- goto rbuf_malloc_fail;
- file->rbsz = BUFSIZ;
- }
- if (file_flags & FILE_WRITE) {
- file->wbuf = malloc(BUFSIZ);
- if (!file->wbuf)
- goto wbuf_malloc_fail;
- file->wbsz = BUFSIZ;
- }
- return file;
- wbuf_malloc_fail:
- free(file->rbuf);
- rbuf_malloc_fail:
- free(file);
- file_malloc_fail:
- close(fd);
- open_fail:
- return NULL;
- }
- int fflush(FILE* stream)
- {
- if (__feof_or_error(stream))
- return EOF;
- if (stream->wbuf && stream->wpos) {
- int ret = write(stream->fd, stream->wbuf, stream->wpos);
- if (ret < 0) {
- stream->flags |= FILE_ERROR;
- return EOF;
- }
- if (ret == 0) {
- stream->flags |= FILE_EOF;
- return EOF;
- }
- stream->wpos = 0;
- }
- // TODO: call flush()
- return 0;
- }
- int fclose(FILE* stream)
- {
- if (fflush(stream) == EOF)
- return EOF;
-
- free(stream->rbuf);
- free(stream->wbuf);
- stream->rbsz = 0;
- stream->wbsz = 0;
-
- if (close(stream->fd) < 0)
- return EOF;
-
- NDERASE(NDPTR(stream));
-
- return 0;
- }
- int fputc_unlocked(int c, FILE* stream)
- {
- return putc_unlocked(c, stream);
- }
- int fputs_unlocked(const char* s, FILE* stream)
- {
- // 1 is for the trailing '\n'
- int len = 1;
- for (const char* p = s; *p; ++p, ++len)
- fputc_unlocked(*p, stream);
- fputc_unlocked('\n', stream);
- return len;
- }
- int fputc(int c, FILE* stream)
- {
- // TODO: lock the stream
- return putc_unlocked(c, stream);
- }
- int fputs(const char* s, FILE* stream)
- {
- // TODO: lock the stream
- return fputs_unlocked(s, stream);
- }
- static inline int __fillbuf(FILE* stream)
- {
- if ((stream->rcnt = read(stream->fd, stream->rbuf, stream->rbsz)) >= 2147483648U) {
- stream->rcnt = 0;
- stream->flags |= FILE_ERROR;
- return EOF;
- }
- if (stream->rcnt == 0) {
- stream->flags |= FILE_EOF;
- return EOF;
- }
- stream->rpos = 0;
- return 0;
- }
- int getc_unlocked(FILE* stream)
- {
- if (__feof_or_error(stream))
- return EOF;
- if (stream->rbuf) {
- if (stream->rpos == stream->rcnt) {
- if (__fillbuf(stream) < 0)
- return EOF;
- }
- return stream->rbuf[stream->rpos++];
- } else {
- int c;
- int ret = read(stream->fd, &c, 1);
- if (ret < 0) {
- stream->flags |= FILE_ERROR;
- return EOF;
- }
- if (ret == 0) {
- stream->flags |= FILE_EOF;
- return EOF;
- }
- return c;
- }
- }
- int putc_unlocked(int c, FILE* stream)
- {
- if (__feof_or_error(stream))
- return EOF;
- if (stream->wbuf) {
- stream->wbuf[stream->wpos++] = c;
- if (stream->wpos == stream->wbsz || c == '\n')
- if (fflush(stream) == EOF)
- return EOF;
- } else {
- if (write(stream->fd, &c, 1) < 0) {
- stream->flags |= FILE_ERROR;
- return EOF;
- }
- }
- return c;
- }
- int getchar(void)
- {
- return fgetc(stdin);
- }
- int fgetc(FILE* stream)
- {
- return getc_unlocked(stream);
- }
- int ferror(FILE* stream)
- {
- // TODO: lock the stream
- return ferror_unlocked(stream);
- }
- int ferror_unlocked(FILE* stream)
- {
- return stream->flags & FILE_ERROR;
- }
- int feof(FILE* stream)
- {
- return stream->flags & FILE_EOF;
- }
- void clearerr(FILE* stream)
- {
- stream->flags &= ~FILE_ERROR;
- }
- int vasprintf(char** strp, const char* fmt, va_list args)
- {
- // TODO: this is WAY TOO SLOWWWWWWWWW
- int sz = 8, n;
- char* buf = NULL;
- do {
- buf = realloc(buf, sz *= 2);
- if (!buf)
- return -1;
-
- n = vsnprintf(buf, sz, fmt, args);
- if (sz > n)
- break;
- } while (1);
-
- *strp = buf;
- return n;
- }
- int asprintf(char** strp, const char* fmt, ...)
- {
- va_list lst;
- va_start(lst, fmt);
- int ret = vasprintf(strp, fmt, lst);
- va_end(lst);
- return ret;
- }
|