diff options
author | pommicket <pommicket@gmail.com> | 2022-02-16 22:58:16 -0500 |
---|---|---|
committer | pommicket <pommicket@gmail.com> | 2022-02-16 22:58:16 -0500 |
commit | 6e1158f49aa014b801b171b358c47389e7f9964e (patch) | |
tree | 5702e0b1ce33dd58a42a0cdfa8d90267a82a6fb3 | |
parent | b1e837afb44f9053763d6a654a5f7bb2757a39d4 (diff) |
the last parts of the C standard library
-rw-r--r-- | 05/codegen.b | 10 | ||||
-rw-r--r-- | 05/errno.h | 6 | ||||
-rw-r--r-- | 05/float.h | 34 | ||||
-rw-r--r-- | 05/limits.h | 6 | ||||
-rw-r--r-- | 05/main.c | 26 | ||||
-rw-r--r-- | 05/stdio.h | 4 | ||||
-rw-r--r-- | 05/string.h | 14 | ||||
-rw-r--r-- | 05/time.h | 293 |
8 files changed, 361 insertions, 32 deletions
diff --git a/05/codegen.b b/05/codegen.b index b89ab51..46354e9 100644 --- a/05/codegen.b +++ b/05/codegen.b @@ -2352,20 +2352,26 @@ function generate_push_expression p = expr + 4 expr = generate_push_expression(statement, expr) p = types + *4p - if *2p == TYPE2_FUNCTION_POINTER goto deref_function_pointer + p += 1 + if *1p == TYPE_FUNCTION goto deref_do_nothing ; dereferencing a function pointer does nothing + if *1p == TYPE_ARRAY goto deref_do_nothing ; dereferencing a pointer to array does nothing generate_stack_dereference(statement, type) - :deref_function_pointer ; dereferencing a function pointer does NOTHING + :deref_do_nothing return expr :generate_subscript expr += 8 c = expr + 4 ; type 1 c = *4c + p = c + 1 expr = generate_push_expression(statement, expr) d = expr + 4 ; type 2 d = *4d expr = generate_push_expression(statement, expr) generate_stack_add(statement, c, d, c) + p = type_is_array(p) + if p != 0 goto subscript_is_array generate_stack_dereference(statement, type) + :subscript_is_array return expr :generate_dot_or_arrow ; @NONSTANDARD: we require that the 1st operand to . be an lvalue diff --git a/05/errno.h b/05/errno.h new file mode 100644 index 0000000..426f351 --- /dev/null +++ b/05/errno.h @@ -0,0 +1,6 @@ +#ifndef _ERRNO_H +#define _ERRNO_H + +#include <stdc_common.h> // we define all the relevant things here + +#endif // _ERRNO_H diff --git a/05/float.h b/05/float.h new file mode 100644 index 0000000..6ae607d --- /dev/null +++ b/05/float.h @@ -0,0 +1,34 @@ +#ifndef _FLOAT_H +#define _FLOAT_H + +#define DBL_DIG 15 +#define DBL_EPSILON 2.2204460492503131e-16 +#define DBL_MANT_DIG 53 +#define DBL_MAX 1.7976931348623157e+308 +#define DBL_MAX_10_EXP 308 +#define DBL_MAX_EXP 1024 +#define DBL_MIN 2.2250738585072027e-308 +#define DBL_MIN_10_EXP (-307) +#define DBL_MIN_EXP (-1021) +#define FLT_DIG 6 +#define FLT_EPSILON 1.19209290e-07 +#define FLT_MANT_DIG 24 +#define FLT_MAX 3.40282347e+38 +#define FLT_MAX_10_EXP +38 +#define FLT_MAX_EXP 128 +#define FLT_MIN 1.17549435e-38 +#define FLT_MIN_10_EXP (-37) +#define FLT_MIN_EXP (-125) +#define FLT_RADIX 2 +#define FLT_ROUNDS 1 +#define LDBL_DIG DBL_DIG +#define LDBL_EPSILON DBL_EPSILON +#define LDBL_MANT_DIG DBL_MANT_DIG +#define LDBL_MAX DBL_MAX +#define LDBL_MAX_10_EXP DBL_MAX_10_EXP +#define LDBL_MAX_EXP DBL_MAX_EXP +#define LDBL_MIN DBL_MIN +#define LDBL_MIN_10_EXP DBL_MIN_10_EXP +#define LDBL_MIN_EXP DBL_MIN_EXP + +#endif // _FLOAT_H diff --git a/05/limits.h b/05/limits.h new file mode 100644 index 0000000..633e9ff --- /dev/null +++ b/05/limits.h @@ -0,0 +1,6 @@ +#ifndef _LIMITS_H +#define _LIMITS_H + +#include <stdc_common.h> // we define all the relevant constants here + +#endif // _LIMITS_H @@ -4,30 +4,12 @@ #include <signal.h> #include <stdlib.h> #include <string.h> - -int compar(const void *a, const void *b) { - int i = *(int *)a; - int j = *(int *)b; - if (i < j) return -1; - if (i > j) return 1; - return 0; -} +#include <time.h> +#include <float.h> int main(int argc, char **argv) { - char buf[36]; - strcpy(buf, "Hello there there!"); -/* buf[36]='b'; */ - printf("%s\n",strstr(buf," ther")); - - static char str[] = "?a???b,,,#c"; - char *t; - - printf("%s\n", strtok(str, "?")); /* t points to the token "a" */ - printf("%s\n", strtok(NULL, ",")); - printf("%s\n", strtok(NULL, "#,")); - printf("%s\n", strtok(NULL, "?")); - - + srand(time(NULL)); + printf("%d\n",rand()); return 0; } @@ -1739,7 +1739,9 @@ int rename(const char *old, const char *new) { char *tmpnam(char *s) { struct timespec t = {0}; - do { + do { + // NB: we can't use rand() here because + // "The implementation shall behave as if no library function calls the rand function." C89 § 4.10.2.1 clock_gettime(CLOCK_MONOTONIC, &t); // use clock as a source of randomness sprintf(s, "/tmp/C_%06u", t.tv_nsec % 1000000); } while (access(s, F_OK) == 0); // if file exists, generate a new name diff --git a/05/string.h b/05/string.h index 02216b5..4b73101 100644 --- a/05/string.h +++ b/05/string.h @@ -163,21 +163,21 @@ char *strstr(const char *s1, const char *s2) { return NULL; } -char *_strtok_str; char *strtok(char *s1, const char *s2) { - if (s1) _strtok_str = s1; - if (!_strtok_str) return NULL; - char *p = _strtok_str + strspn(_strtok_str, s2); + static char *str; + if (s1) str = s1; + if (!str) return NULL; + char *p = str + strspn(str, s2); if (!*p) { - _strtok_str = NULL; + str = NULL; return NULL; } char *q = strpbrk(p, s2); if (q) { *q = 0; - _strtok_str = q + 1; + str = q + 1; } else { - _strtok_str = NULL; + str = NULL; } return p; } diff --git a/05/time.h b/05/time.h new file mode 100644 index 0000000..8207156 --- /dev/null +++ b/05/time.h @@ -0,0 +1,293 @@ +#ifndef _TIME_H +#define _TIME_H + +#include <stdc_common.h> +#define CLK_TCK 1000000000 // doesnt matter; clock() will always fail. + +typedef long clock_t; + +clock_t clock(void) { + // "If the processor time used is not available or its value cannot be represented, the function returns the value (clock_t)-1." C89 § 4.12.2.1 + return -1; +} + +double difftime(time_t time1, time_t time0) { + return (double)(time1 - time0); +} + +time_t time(time_t *timer) { + struct timespec ts = {0}; + if (clock_gettime(CLOCK_REALTIME, &ts) != 0) return -1; + if (timer) *timer = ts.tv_sec; + return ts.tv_sec; +} + + +// @NONSTANDARD(except in UTC+0): we don't support local time in timezones other than UTC+0. + +struct tm { + int tm_sec; /* seconds after the minute --- [0, 60] */ + int tm_min; /* minutes after the hour --- [0, 59] */ + int tm_hour; /* hours since midnight --- [0, 23] */ + int tm_mday; /* day of the month --- [1, 31] */ + int tm_mon; /* months since January --- [0, 11] */ + int tm_year; /* years since 1900 */ + int tm_wday; /* days since Sunday --- [0, 6] */ + int tm_yday; /* days since January 1 --- [0, 365] */ + int tm_isdst; /* Daylight Saving Time flag */ +}; + + +void _gmtime_r(const time_t *timer, struct tm *tm) { + time_t t = *timer; + int year = 1970; + int days = t / 86400; + int leap_year; + int month; + + tm->tm_isdst = 0; + tm->tm_wday = (4 + days) % 7; // jan 1 1970 was a thursday + while (1) { + leap_year = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); + int ydays = leap_year ? 366 : 365; + if (days < ydays) break; + days -= ydays; + ++year; + } + tm->tm_year = year - 1900; + tm->tm_yday = days; + for (month = 0; month < 12; ++month) { + int mdays; + switch (month) { + case 0: case 2: case 4: case 6: case 7: case 9: case 11: + mdays = 31; + break; + case 3: case 5: case 8: case 10: + mdays = 30; + break; + case 1: + mdays = 28 + leap_year; + break; + } + if (days < mdays) break; + days -= mdays; + } + tm->tm_mday = days + 1; + tm->tm_mon = month; + t %= 86400; + tm->tm_hour = t / 3600; + t %= 3600; + tm->tm_min = t / 60; + tm->tm_sec = t % 60; +} + +time_t mktime(struct tm *tm) { + // @NONSTANDARD-ish. + // not implementing this -- note that the implementation has to support tm_* values + // outside of their proper ranges. + return (time_t)-1; + +} + +struct tm *gmtime(const time_t *timer) { + static struct tm result; + _gmtime_r(timer, &result); + return &result; +} + +struct tm *localtime(const time_t *timer) { + static struct tm result; + _gmtime_r(timer, &result); + return &result; +} + +static const char _wday_name[7][4] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" +}; +static const char _weekday_name[7][16] = { + "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" +}; +static const char _mon_name[12][4] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; +static const char _month_name[12][16] = { + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" +}; + +char *asctime(const struct tm *timeptr) { + // lifted from the (draft of the) C standard + static char result[32]; + sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n", + _wday_name[timeptr->tm_wday], + _mon_name[timeptr->tm_mon], + timeptr->tm_mday, timeptr->tm_hour, + timeptr->tm_min, timeptr->tm_sec, + 1900 + timeptr->tm_year); + return result; +} + +char *ctime(const time_t *timer) { + return asctime(localtime(timer)); +} + +size_t strftime(char *s, size_t maxsize, const char *format, const struct tm *tm) { + size_t n = 0, l; + char *name; + + while (*format) { + if (*format == '%') { + ++format; + int c = *format++; + switch (c) { + case 'a': + if (n+4 >= maxsize) return 0; + strcpy(s, _wday_name[tm->tm_wday]); + s += 3; + n += 3; + break; + case 'A': + name = _weekday_name[tm->tm_wday]; + l = strlen(name); + if (n+l+1 >= maxsize) return 0; + strcpy(s, name); + s += l; + n += l; + break; + case 'b': + if (n+4 >= maxsize) return 0; + strcpy(s, _mon_name[tm->tm_mon]); + s += 3; + n += 3; + break; + case 'B': + name = _month_name[tm->tm_mon]; + l = strlen(name); + if (n+l+1 >= maxsize) return 0; + strcpy(s, name); + s += l; + n += l; + break; + case 'c': + if (n+32 >= maxsize) return 0; + sprintf(s, "%s %02d %s %d %02d:%02d:%02d %s UTC", + _wday_name[tm->tm_wday], tm->tm_mday, _mon_name[tm->tm_mon], + 1900+tm->tm_year, (tm->tm_hour + 11) % 12 + 1, tm->tm_min, tm->tm_sec, + tm->tm_hour >= 12 ? "PM" : "AM"); + s += 31; + n += 31; + break; + case 'd': + if (n+3 >= maxsize) return 0; + sprintf(s, "%02d", tm->tm_mday); + s += 2; + n += 2; + break; + case 'H': + if (n+3 >= maxsize) return 0; + sprintf(s, "%02d", tm->tm_hour); + s += 2; + n += 2; + break; + case 'I': + if (n+3 >= maxsize) return 0; + sprintf(s, "%02d", (tm->tm_hour + 11) % 12 + 1); + s += 2; + n += 2; + break; + case 'j': + if (n+4 >= maxsize) return 0; + sprintf(s, "%03d", tm->tm_yday + 1); + s += 3; + n += 3; + break; + case 'm': + if (n+3 >= maxsize) return 0; + sprintf(s, "%02d", tm->tm_mon + 1); + s += 2; + n += 2; + break; + case 'M': + if (n+3 >= maxsize) return 0; + sprintf(s, "%02d", tm->tm_min); + s += 2; + n += 2; + break; + case 'p': + if (n+3 >= maxsize) return 0; + sprintf(s, "%s", tm->tm_hour >= 12 ? "PM" : "AM"); + s += 2; + n += 2; + break; + case 'S': + if (n+3 >= maxsize) return 0; + sprintf(s, "%02d", tm->tm_sec); + s += 2; + n += 2; + break; + case 'w': + if (n+2 >= maxsize) return 0; + sprintf(s, "%d", tm->tm_wday); + s += 1; + n += 1; + break; + case 'x': + if (n+16 >= maxsize) return 0; + sprintf(s, "%s %02d %s %d", + _wday_name[tm->tm_wday], tm->tm_mday, _mon_name[tm->tm_mon], + 1900+tm->tm_year); + s += 15; + n += 15; + break; + case 'X': + if (n+16 >= maxsize) return 0; + sprintf(s, "%02d:%02d:%02d %s UTC", + (tm->tm_hour + 11) % 12 + 1, tm->tm_min, tm->tm_sec, + tm->tm_hour >= 12 ? "PM" : "AM"); + s += 15; + n += 15; + break; + case 'y': + if (n+3 >= maxsize) return 0; + sprintf(s, "%02d", tm->tm_year % 100); + s += 2; + n += 2; + break; + case 'Y': + if (n+5 >= maxsize) return 0; + sprintf(s, "%d", tm->tm_year + 1900); + s += 4; + n += 4; + break; + case 'Z': + if (n+4 >= maxsize) return 0; + strcpy(s, "UTC"); + s += 3; + n += 3; + break; + case '%': + if (n >= maxsize) return 0; + *s++ = '%'; + n += 1; + break; + case 'U': // WEEK NUMBER OF THE YEAR? WHO GIVES A SHIT? + case 'W': // WEEK NUMBER OF THE YEAR MONDAY-BASED EDITION. IF YOU DIDNT ALREADY GET ENOUGH WEEK NUMBERS. FUCK YOU + default: + fprintf(stderr, "Bad strftime format.\n"); + abort(); + + } + } else { + if (n >= maxsize) return 0; + *s++ = *format++; + n += 1; + } + } + if (n >= maxsize) return 0; + *s = 0; + #undef _Push_str + return n; +} + +#endif // _TIME_H |