├── .gitignore ├── Makefile ├── device.c ├── duration.c ├── run_shell.c ├── strarray.h ├── arg.h ├── map.h ├── file.c ├── log.h ├── crc32.c ├── utf8.c ├── llist.c ├── .clang-format ├── libphy.h ├── xatonum.c ├── log.c ├── xatonum.h ├── map.c ├── xatonum_template.c └── vector.h /.gitignore: -------------------------------------------------------------------------------- 1 | compile_commands.json 2 | *.o 3 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | 3 | SRC = device.c duration.c get_line_from_file.c xatonum.c 4 | OBJ = ${SRC:.c=.o} 5 | 6 | CC = gcc 7 | CFLAGS = -std=gnu99 -pedantic 8 | 9 | dur: 10 | ${CC} -c ${CFLAGS} duration.c 11 | 12 | all: 13 | echo 14 | 15 | %.o: %.c 16 | ${CC} -c ${CFLAGS} $< 17 | 18 | .PHONY: all 19 | -------------------------------------------------------------------------------- /device.c: -------------------------------------------------------------------------------- 1 | #include "libphy.h" 2 | #include 3 | 4 | int device_open(const char *device, int mode) 5 | { 6 | int m, f, fd = -1; 7 | 8 | m = mode | O_NONBLOCK; 9 | 10 | /* Retry 5 times */ 11 | for (f = 0; f < 5; f++) 12 | if ((fd = open(device, m, 0600)) >= 0) 13 | break; 14 | 15 | if (fd < 0) 16 | return fd; 17 | /* Reset flags */ 18 | if (m != mode) 19 | fcntl(fd, F_SETFL, mode); 20 | return fd; 21 | } 22 | -------------------------------------------------------------------------------- /duration.c: -------------------------------------------------------------------------------- 1 | #include "libphy.h" 2 | 3 | 4 | static const struct suffix_mult dur_suffixes[] = { 5 | { "s", 1 }, 6 | { "m", 60 }, 7 | { "h", 60*60 }, 8 | { "d", 24*60*60 }, 9 | { "", 0 } 10 | }; 11 | 12 | duration_t parse_duration_str(char *str) 13 | { 14 | duration_t dur; 15 | 16 | if (strchr(str, '.')) { 17 | double d; 18 | char *pp; 19 | setlocale(LC_NUMERIC, "C"); 20 | 21 | int len = strspn(str, "0123456789."); 22 | char sv = str[len]; 23 | str[len] = '\0'; 24 | errno = 0; 25 | d = strtod(str, &pp); 26 | str += len; 27 | *str-- = sv; 28 | sv = *str; 29 | *str = '1'; 30 | dur = d * xatoull_sfx(str, dur_suffixes); 31 | *str = sv; 32 | } else { 33 | dur = xatoull_sfx(str, dur_suffixes); 34 | } 35 | return dur; 36 | } 37 | -------------------------------------------------------------------------------- /run_shell.c: -------------------------------------------------------------------------------- 1 | #include "libphy.h" 2 | #include 3 | #define MIN_STR_SIZE 16 4 | 5 | void shell_run(const char *cmd, ...) 6 | { 7 | static char buf[1024]; 8 | memset(buf, 0, sizeof(buf)); 9 | va_list argptr; 10 | va_start(argptr, cmd); 11 | va_end(argptr); 12 | vsprintf(buf, cmd, argptr); 13 | 14 | system(cmd); 15 | } 16 | 17 | char *shell_run_str(const char *cmd, ...) 18 | { 19 | static char buf[1024]; 20 | memset(buf, 0, sizeof(buf)); 21 | va_list argptr; 22 | va_start(argptr, cmd); 23 | va_end(argptr); 24 | vsprintf(buf, cmd, argptr); 25 | 26 | FILE *fd = popen(buf, "r"); 27 | 28 | if (!fd) 29 | return NULL; 30 | 31 | char ch, *out = malloc(MIN_STR_SIZE); 32 | int i = 0, sz = MIN_STR_SIZE; 33 | 34 | while ((ch = getc(fd)) && ch != EOF) { 35 | out[i++] = ch; 36 | if (i >= sz - 1) { 37 | sz <<= 1; 38 | out = realloc(out, sz); 39 | } 40 | } 41 | out[i] = '\0'; 42 | pclose(fd); 43 | return out; 44 | } 45 | -------------------------------------------------------------------------------- /strarray.h: -------------------------------------------------------------------------------- 1 | #ifndef STRARRAY_H 2 | #define STRARRAY_H 3 | #include "libphy.h" 4 | #define STRA_MIN_SIZE 4 5 | 6 | 7 | static inline void 8 | stra_free(char **stra) 9 | { 10 | free((*stra)); 11 | free(stra); 12 | } 13 | 14 | static char ** 15 | stra_str_to_arr(const char *str, char delim) 16 | { 17 | int sz = STRA_MIN_SIZE, end = strlen(str), idx = 0; 18 | char *s = strdup(str); 19 | char **stra = malloc(sizeof(char *) * sz); 20 | stra[0] = s; 21 | 22 | for (int i = 0; i < end; i++) { 23 | if (s[i] == delim) { 24 | stra[++idx] = (s + i + 1); 25 | s[i] = '\0'; 26 | } 27 | 28 | if (idx >= sz - 1) { 29 | sz <<= 1; 30 | stra = realloc(stra, sizeof(char *) * sz); 31 | } 32 | } 33 | stra[++idx] = NULL; 34 | return stra; 35 | } 36 | 37 | static inline char 38 | *str_tolower(char *s) 39 | { 40 | char *p = s; 41 | do { 42 | *p = tolower(*p); 43 | } while (*(++p)); 44 | return s; 45 | } 46 | 47 | static inline char * 48 | str_toupper(char *s) 49 | { 50 | char *p = s; 51 | do { 52 | *p = toupper(*p); 53 | } while (*(++p)); 54 | return s; 55 | } 56 | #endif /* STRARRAY_H */ 57 | -------------------------------------------------------------------------------- /arg.h: -------------------------------------------------------------------------------- 1 | #ifndef ARG_H__ 2 | #define ARG_H__ 3 | 4 | extern char *argv0; 5 | 6 | /* use main(int argc, char *argv[]) */ 7 | #define ARGBEGIN for (argv0 = *argv, argv++, argc--;\ 8 | argv[0] && argv[0][0] == '-'\ 9 | && argv[0][1];\ 10 | argc--, argv++) {\ 11 | char argc_;\ 12 | char **argv_;\ 13 | int brk_;\ 14 | if (argv[0][1] == '-' && argv[0][2] == '\0') {\ 15 | argv++;\ 16 | argc--;\ 17 | break;\ 18 | }\ 19 | int i_;\ 20 | for (i_ = 1, brk_ = 0, argv_ = argv;\ 21 | argv[0][i_] && !brk_;\ 22 | i_++) {\ 23 | if (argv_ != argv)\ 24 | break;\ 25 | argc_ = argv[0][i_];\ 26 | switch (argc_) 27 | 28 | #define ARGEND }\ 29 | } 30 | 31 | #define ARGC() argc_ 32 | 33 | #define EARGF(x) ((argv[0][i_+1] == '\0' && argv[1] == NULL)?\ 34 | ((x), abort(), (char *)0) :\ 35 | (brk_ = 1, (argv[0][i_+1] != '\0')?\ 36 | (&argv[0][i_+1]) :\ 37 | (argc--, argv++, argv[0]))) 38 | 39 | #define ARGF() ((argv[0][i_+1] == '\0' && argv[1] == NULL)?\ 40 | (char *)0 :\ 41 | (brk_ = 1, (argv[0][i_+1] != '\0')?\ 42 | (&argv[0][i_+1]) :\ 43 | (argc--, argv++, argv[0]))) 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /map.h: -------------------------------------------------------------------------------- 1 | #ifndef MAP_H 2 | #define MAP_H 3 | 4 | #include 5 | 6 | typedef struct map_node_t map_node_t; 7 | 8 | typedef struct { 9 | map_node_t **buckets; 10 | unsigned nbuckets, nnodes; 11 | } map_base_t; 12 | 13 | typedef struct { 14 | unsigned bucketidx; 15 | map_node_t *node; 16 | } map_iter_t; 17 | 18 | #define map_t(type) \ 19 | struct { map_base_t base; type *ref; type tmp; } 20 | 21 | #define map_init(m) \ 22 | memset(m, 0, sizeof(*(m))) 23 | 24 | #define map_deinit(m) \ 25 | ___map_deinit(&(m)->base) 26 | 27 | #define map_get(m, key) \ 28 | ((m)->ref = ___map_get(&(m)->base, key)) 29 | 30 | #define map_set(m, key, val) \ 31 | ((m)->tmp = (val), \ 32 | ___map_set(&(m)->base, key, &(m)->tmp, sizeof((m)->tmp))) 33 | 34 | #define map_remove(m, key) \ 35 | ___map_remove(&(m)->base, key) 36 | 37 | #define map_iter(m) \ 38 | ___map_iter() 39 | 40 | #define map_next(m, iter) \ 41 | ___map_next(&(m)->base, iter) 42 | 43 | void ___map_deinit(map_base_t *m); 44 | void *___map_get(map_base_t *m, const char *key); 45 | int ___map_set(map_base_t *m, const char *key, void *val, int vsize); 46 | void ___map_remove(map_base_t *m, const char *key); 47 | map_iter_t ___map_iter(); 48 | const char *___map_next(map_base_t *m, map_iter_t *iter); 49 | 50 | #endif /* MAP_H */ 51 | -------------------------------------------------------------------------------- /file.c: -------------------------------------------------------------------------------- 1 | #include "libphy.h" 2 | 3 | int dir_iterate(const char *dir_name, 4 | int (*func) (const char *, struct dirent *, void *), void *private) 5 | { 6 | struct dirent *de; 7 | DIR *dir = opendir(dir_name); 8 | if (!dir) 9 | return -1; 10 | 11 | while ((de = readdir(dir))) 12 | func(dir_name, de, private); 13 | closedir(dir); 14 | return 0; 15 | } 16 | 17 | 18 | int dir_check(const char *file_name, int follow_links) 19 | { 20 | int status; 21 | struct stat statbuf; 22 | 23 | if (follow_links) 24 | status = stat(file_name, &statbuf); 25 | else 26 | status = lstat(file_name, &statbuf); 27 | 28 | status = (!status && S_ISDIR(statbuf.st_mode)); 29 | return status; 30 | } 31 | 32 | static char *file_get_line(FILE *file, int c) 33 | { 34 | #define GROWBY (120) 35 | 36 | int ch; 37 | int idx = 0; 38 | char *linebuf = NULL; 39 | int lbsz = 0; 40 | 41 | while ((ch = getc(file)) != EOF) { 42 | if (idx > lbsz - 2) { 43 | linebuf = realloc(linebuf, lbsz + GROWBY); 44 | } 45 | linebuf[idx++] = (char)ch; 46 | if (!ch) return linebuf; 47 | if (c < 2 && ch == '\n') { 48 | if (c) --idx; 49 | /* */ 50 | break; 51 | } 52 | } 53 | 54 | if (linebuf) { 55 | if (ferror(file)) { 56 | free(linebuf); 57 | return NULL; 58 | } 59 | linebuf[idx] = 0; 60 | } 61 | return linebuf; 62 | } 63 | -------------------------------------------------------------------------------- /log.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define LOG_USE_COLOR 9 | 10 | enum { 11 | LOG_TRACE, 12 | LOG_DEBUG, 13 | LOG_INFO, 14 | LOG_WARN, 15 | LOG_ERROR, 16 | LOG_FATAL 17 | }; 18 | 19 | typedef struct { 20 | va_list ap; 21 | const char *fmt; 22 | const char *file; 23 | struct tm *time; 24 | void *udata; 25 | int line; 26 | int level; 27 | } LogEvent; 28 | 29 | typedef void (*LogFn) (LogEvent *ev); 30 | typedef void (*LockFn) (bool lock, void *udata); 31 | 32 | #define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__) 33 | #define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) 34 | #define log_info(...) log_log(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__) 35 | #define log_warn(...) log_log(LOG_WARN, __FILE__, __LINE__, __VA_ARGS__) 36 | #define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__) 37 | #define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__) 38 | 39 | const char *log_level_str(int level); 40 | void log_set_lock(LockFn fn, void *udata); 41 | void log_set_level(int level); 42 | void log_set_quiet(bool isquiet); 43 | int log_add_callback(LogFn, void *udata, int level); 44 | int log_add_fp(FILE *fp, int level); 45 | 46 | void log_log(int level, const char *file, int line, const char *fmt, ...); 47 | -------------------------------------------------------------------------------- /crc32.c: -------------------------------------------------------------------------------- 1 | #include "libphy.h" 2 | 3 | uint32_t *global_crc32_table; 4 | 5 | 6 | uint32_t *crc32_filltable(uint32_t *crc_table, int endian) 7 | { 8 | uint32_t poly = endian ? 0x04c11db7 : 0xedb88320; 9 | 10 | if (!crc_table) 11 | crc_table = malloc(256 * sizeof(uint32_t)); 12 | 13 | uint32_t c; 14 | for (size_t i = 0; i < 256; i++) { 15 | c = endian ? (i <<24) : i; 16 | for (size_t j = 8; j; j--) { 17 | if (endian) 18 | c = (c&0x80000000) ? ((c << 1) ^ poly) : (c << 1); 19 | else 20 | c = (c&1) ? ((c >> 1) ^ poly) : (c >> 1); 21 | } 22 | *crc_table++ = c; 23 | } 24 | return crc_table - 256; 25 | } 26 | 27 | uint32_t *crc32_new_table_le() 28 | { 29 | return crc32_filltable(NULL, 0); 30 | } 31 | 32 | uint32_t *global_crc32_new_table_le() 33 | { 34 | global_crc32_table = crc32_new_table_le(); 35 | return global_crc32_table; 36 | } 37 | 38 | uint32_t crc32_block_endian1(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table) 39 | { 40 | const void *end = (uint8_t*)buf + len; 41 | 42 | while (buf != end) { 43 | val = (val << 8) ^ crc_table[(val >> 24) ^ *(uint8_t*)buf]; 44 | buf = (uint8_t*)buf + 1; 45 | } 46 | return val; 47 | } 48 | 49 | uint32_t crc32_block_endian0(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table) 50 | { 51 | const void *end = (uint8_t*)buf + len; 52 | 53 | while (buf != end) { 54 | val = crc_table[(uint8_t)val ^ *(uint8_t*)buf] ^ (val >> 8); 55 | buf = (uint8_t*)buf + 1; 56 | } 57 | return val; 58 | } 59 | -------------------------------------------------------------------------------- /utf8.c: -------------------------------------------------------------------------------- 1 | #include "libphy.h" 2 | #define UTF_INVALID 0xFFFD 3 | #define UTF_SIZ 4 4 | 5 | static u_char utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; 6 | static u_char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; 7 | static Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000}; 8 | static Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; 9 | 10 | size_t utf8decode(const char *c, Rune *u, size_t clen) 11 | { 12 | size_t i, j, len, type; 13 | Rune udecoded; 14 | 15 | *u = UTF_INVALID; 16 | if (!clen) 17 | return 0; 18 | udecoded = utf8decodebyte(c[0], &len); 19 | if (!BETWEEN(len, 1, UTF_SIZ)) 20 | return 1; 21 | for (i = 1, j = 1; i < clen && j < len; ++i, ++j) { 22 | udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type); 23 | if (type != 0) 24 | return j; 25 | } 26 | if (j < len) 27 | return 0; 28 | *u = udecoded; 29 | utf8validate(u, len); 30 | 31 | return len; 32 | } 33 | 34 | Rune utf8decodebyte(char c, size_t *i) 35 | { 36 | for (*i = 0; *i < LEN(utfmask); ++(*i)) 37 | if (((u_char)c & utfmask[*i]) == utfbyte[*i]) 38 | return (u_char)c & ~utfmask[*i]; 39 | 40 | return 0; 41 | } 42 | 43 | size_t utf8encode(Rune u, char *c) 44 | { 45 | size_t len, i; 46 | 47 | len = utf8validate(&u, 0); 48 | if (len > UTF_SIZ) 49 | return 0; 50 | 51 | for (i = len - 1; i != 0; --i) { 52 | c[i] = utf8encodebyte(u, 0); 53 | u >>= 6; 54 | } 55 | c[0] = utf8encodebyte(u, len); 56 | 57 | return len; 58 | } 59 | 60 | char utf8encodebyte(Rune u, size_t i) 61 | { 62 | return utfbyte[i] | (u & ~utfmask[i]); 63 | } 64 | 65 | size_t utf8validate(Rune *u, size_t i) 66 | { 67 | if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF)) 68 | *u = UTF_INVALID; 69 | for (i = 1; *u > utfmax[i]; ++i) 70 | ; 71 | 72 | return i; 73 | } 74 | -------------------------------------------------------------------------------- /llist.c: -------------------------------------------------------------------------------- 1 | #include "libphy.h" 2 | 3 | /* Add data to the start of the linked list. */ 4 | void llist_add_to(llist_t **old_head, void *data) 5 | { 6 | llist_t *new_head = malloc(sizeof(llist_t)); 7 | 8 | new_head->data = data; 9 | new_head->link = *old_head; 10 | *old_head = new_head; 11 | } 12 | 13 | /* Add data to the end of the linked list. */ 14 | void llist_add_to_end(llist_t **list_head, void *data) 15 | { 16 | while (*list_head) 17 | list_head = &(*list_head)->link; 18 | *list_head = calloc(sizeof(llist_t), 1); 19 | (*list_head)->data = data; 20 | /*(*list_head)->link = NULL;*/ 21 | } 22 | 23 | /* Remove first element from the list and return it */ 24 | void* llist_pop(llist_t **head) 25 | { 26 | void *data = NULL; 27 | llist_t *temp = *head; 28 | 29 | if (temp) { 30 | data = temp->data; 31 | *head = temp->link; 32 | free(temp); 33 | } 34 | return data; 35 | } 36 | 37 | /* Unlink arbitrary given element from the list */ 38 | void llist_unlink(llist_t **head, llist_t *elm) 39 | { 40 | if (!elm) 41 | return; 42 | while (*head) { 43 | if (*head == elm) { 44 | *head = (*head)->link; 45 | break; 46 | } 47 | head = &(*head)->link; 48 | } 49 | } 50 | 51 | /* Recursively free all elements in the linked list. If freeit != NULL 52 | * call it on each datum in the list */ 53 | void llist_free(llist_t *elm, void (*freeit)(void *data)) 54 | { 55 | while (elm) { 56 | void *data = llist_pop(&elm); 57 | 58 | if (freeit) 59 | freeit(data); 60 | } 61 | } 62 | 63 | /* Reverse list order. */ 64 | llist_t* llist_rev(llist_t *list) 65 | { 66 | llist_t *rev = NULL; 67 | 68 | while (list) { 69 | llist_t *next = list->link; 70 | 71 | list->link = rev; 72 | rev = list; 73 | list = next; 74 | } 75 | return rev; 76 | } 77 | 78 | llist_t* llist_find_str(llist_t *list, const char *str) 79 | { 80 | while (list) { 81 | if (strcmp(list->data, str) == 0) 82 | break; 83 | list = list->link; 84 | } 85 | return list; 86 | } 87 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | AccessModifierOffset: -4 2 | AlignAfterOpenBracket: Align 3 | AlignConsecutiveAssignments: false 4 | AlignConsecutiveDeclarations: false 5 | AlignEscapedNewlines: Left 6 | AlignOperands: true 7 | AlignTrailingComments: false 8 | AllowAllParametersOfDeclarationOnNextLine: true 9 | AllowShortBlocksOnASingleLine: false 10 | AllowShortCaseLabelsOnASingleLine: false 11 | AllowShortFunctionsOnASingleLine: None 12 | AllowShortIfStatementsOnASingleLine: true 13 | AllowShortLoopsOnASingleLine: true 14 | AlwaysBreakAfterDefinitionReturnType: None 15 | AlwaysBreakAfterReturnType: None 16 | AlwaysBreakBeforeMultilineStrings: false 17 | AlwaysBreakTemplateDeclarations: false 18 | BinPackArguments: true 19 | BinPackParameters: true 20 | BraceWrapping: 21 | AfterClass: false 22 | AfterControlStatement: false 23 | AfterEnum: false 24 | AfterFunction: true 25 | AfterNamespace: true 26 | AfterObjCDeclaration: false 27 | AfterStruct: false 28 | AfterUnion: false 29 | AfterExternBlock: false 30 | BeforeCatch: false 31 | BeforeElse: false 32 | IndentBraces: false 33 | SplitEmptyFunction: true 34 | SplitEmptyRecord: true 35 | SplitEmptyNamespace: true 36 | BreakBeforeBinaryOperators: None 37 | BreakBeforeBraces: Custom 38 | BreakBeforeInheritanceComma: false 39 | BreakBeforeTernaryOperators: false 40 | BreakConstructorInitializersBeforeComma: false 41 | BreakConstructorInitializers: BeforeComma 42 | BreakAfterJavaFieldAnnotations: false 43 | BreakStringLiterals: false 44 | ColumnLimit: 90 45 | CompactNamespaces: false 46 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 47 | ConstructorInitializerIndentWidth: 8 48 | ContinuationIndentWidth: 8 49 | Cpp11BracedListStyle: false 50 | DerivePointerAlignment: false 51 | DisableFormat: false 52 | ExperimentalAutoDetectBinPacking: false 53 | FixNamespaceComments: false 54 | IncludeBlocks: Preserve 55 | IncludeCategories: 56 | - Regex: '.*' 57 | Priority: 1 58 | PointerAlignment: Right 59 | ReflowComments: false 60 | SortIncludes: false 61 | SortUsingDeclarations: false 62 | SpaceAfterCStyleCast: false 63 | SpaceAfterTemplateKeyword: true 64 | SpaceBeforeAssignmentOperators: true 65 | SpaceBeforeCtorInitializerColon: true 66 | SpaceBeforeInheritanceColon: true 67 | SpaceBeforeParens: ControlStatementsExceptForEachMacros 68 | SpaceBeforeRangeBasedForLoopColon: true 69 | SpaceInEmptyParentheses: false 70 | SpacesBeforeTrailingComments: 1 71 | SpacesInAngles: false 72 | SpacesInContainerLiterals: false 73 | SpacesInCStyleCastParentheses: false 74 | SpacesInParentheses: false 75 | SpacesInSquareBrackets: false 76 | Standard: Cpp03 77 | TabWidth: 8 78 | IndentWidth: 8 79 | UseTab: Always 80 | -------------------------------------------------------------------------------- /libphy.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBPHY_H 2 | #define LIBPHY_H 1 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "vector.h" 14 | 15 | #include 16 | typedef double duration_t; 17 | void sleep_for_duration(duration_t duration); 18 | duration_t parse_duration_str(char *str); 19 | 20 | #define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b)) 21 | #define LEN(x) sizeof(x)/sizeof(x[0]) 22 | 23 | struct suffix_mult { 24 | char suffix[4]; 25 | uint32_t mult; 26 | }; 27 | 28 | #define UNUSED_PARAM __attribute__((__unused__)) 29 | #define NORETURN __attribute__((__noreturn__)) 30 | #define RETURNS_MALLOC __attribute__((malloc)) 31 | #define ALIGNED(m) __attribute__((__aligned__(m))) 32 | #define ALWAYS_INLINE __attribute__((always_inline)) inline 33 | #define UNUSED_PARAM_RESULT __attribute__((warn_unused_result)) 34 | 35 | /* Endian */ 36 | #include 37 | #include 38 | #include 39 | 40 | #if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN 41 | #define PHY_BIG_ENDIAN 1 42 | #define PHY_LITTLE_ENDIAN 0 43 | #elif defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN 44 | #define PHY_BIG_ENDIAN 0 45 | #define PHY_LITTLE_ENDIAN 1 46 | #endif 47 | 48 | #define ALIGN1 __attribute__((aligned(1))) 49 | #define ALIGN2 __attribute__((aligned(2))) 50 | #define ALIGN4 __attribute__((aligned(4))) 51 | #define ALIGN8 __attribute__((aligned(8))) 52 | #define ALIGN_INT __attribute__((aligned(sizeof(int)))) 53 | #define ALIGN_PTR __attribute__((aligned(sizeof(void *)))) 54 | #define ALIGN_SUFFIX ALIGN4 55 | extern const struct suffix_mult bkm_suffixes[]; 56 | #define km_suffixes (bkm_suffixes + 1) 57 | extern const struct suffix_mult cwbkMG_suffixes[]; 58 | #define kMG_suffixes (cwbkMG_suffixes + 3) 59 | extern const struct suffix_mult kmg_i_suffixes[]; 60 | #include "xatonum.h" 61 | 62 | typedef struct llist_t { 63 | struct llist_t *link; 64 | char *data; 65 | } llist_t; 66 | void llist_add_to(llist_t **old_head, void *data); 67 | void llist_add_to_end(llist_t **list_head, void *data); 68 | void *llist_pop(llist_t **elm); 69 | void llist_unlink(llist_t **head, llist_t *elm); 70 | void llist_free(llist_t *elm, void (*freeit)(void *data)); 71 | llist_t *llist_rev(llist_t *list); 72 | llist_t *llist_find_str(llist_t *first, const char *str); 73 | 74 | typedef uint_least32_t Rune; 75 | size_t utf8encode(Rune, char *); 76 | char utf8encodebyte(Rune, size_t); 77 | size_t utf8validate(Rune *, size_t); 78 | Rune utf8decodebyte(char c, size_t *i); 79 | 80 | #endif /* LIBPHY_H */ 81 | -------------------------------------------------------------------------------- /xatonum.c: -------------------------------------------------------------------------------- 1 | #include "libphy.h" 2 | #define type long long 3 | #define xstrtou(rest) xstrtoull##rest 4 | #define xstrto(rest) xstrtoll##rest 5 | #define xatou(rest) xatoull##rest 6 | #define xato(rest) xatoll##rest 7 | #define XSTR_UTYPE_MAX ULLONG_MAX 8 | #define XSTR_TYPE_MAX LLONG_MAX 9 | #define XSTR_TYPE_MIN LLONG_MIN 10 | #define XSTR_STRTOU strtoull 11 | #include "xatonum_template.c" 12 | 13 | #if ULONG_MAX != ULLONG_MAX 14 | #define type long 15 | #define xstrtou(rest) xstrtoul##rest 16 | #define xstrto(rest) xstrtol##rest 17 | #define xatou(rest) xatoul##rest 18 | #define xato(rest) xatol##rest 19 | #define XSTR_UTYPE_MAX ULONG_MAX 20 | #define XSTR_TYPE_MAX LONG_MAX 21 | #define XSTR_TYPE_MIN LONG_MIN 22 | #define XSTR_STRTOU strtoul 23 | #include "xatonum_template.c" 24 | #endif 25 | 26 | #if UINT_MAX != ULONG_MAX 27 | static ALWAYS_INLINE 28 | unsigned bb_strtoui(const char *str, char **end, int b) 29 | { 30 | unsigned long v = strtoul(str, end, b); 31 | if (v > UINT_MAX) { 32 | errno = ERANGE; 33 | return UINT_MAX; 34 | } 35 | return v; 36 | } 37 | #define type int 38 | #define xstrtou(rest) xstrtou##rest 39 | #define xstrto(rest) xstrtoi##rest 40 | #define xatou(rest) xatou##rest 41 | #define xato(rest) xatoi##rest 42 | #define XSTR_UTYPE_MAX UINT_MAX 43 | #define XSTR_TYPE_MAX INT_MAX 44 | #define XSTR_TYPE_MIN INT_MIN 45 | /* libc has no strtoui, so we need to create/use our own */ 46 | #define XSTR_STRTOU bb_strtoui 47 | #include "xatonum_template.c" 48 | #endif 49 | 50 | /* A few special cases */ 51 | 52 | int xatoi_positive(const char *numstr) 53 | { 54 | return xatou_range(numstr, 0, INT_MAX); 55 | } 56 | 57 | uint16_t xatou16(const char *numstr) 58 | { 59 | return xatou_range(numstr, 0, 0xffff); 60 | } 61 | 62 | const struct suffix_mult bkm_suffixes[] ALIGN_SUFFIX = { 63 | { "b", 512 }, 64 | { "k", 1024 }, 65 | { "m", 1024*1024 }, 66 | { "", 0 } 67 | }; 68 | 69 | const struct suffix_mult cwbkMG_suffixes[] ALIGN_SUFFIX = { 70 | { "c", 1 }, 71 | { "w", 2 }, 72 | { "b", 512 }, 73 | { "kB", 1000 }, 74 | { "kD", 1000 }, 75 | { "k", 1024 }, 76 | { "KB", 1000 }, /* compat with coreutils dd */ 77 | { "KD", 1000 }, /* compat with coreutils dd */ 78 | { "K", 1024 }, /* compat with coreutils dd */ 79 | { "MB", 1000000 }, 80 | { "MD", 1000000 }, 81 | { "M", 1024*1024 }, 82 | { "GB", 1000000000 }, 83 | { "GD", 1000000000 }, 84 | { "G", 1024*1024*1024 }, 85 | /* "D" suffix for decimal is not in coreutils manpage, looks like it's deprecated */ 86 | /* coreutils also understands TPEZY suffixes for tera- and so on, with B suffix for decimal */ 87 | { "", 0 } 88 | }; 89 | 90 | const struct suffix_mult kmg_i_suffixes[] ALIGN_SUFFIX = { 91 | { "KiB", 1024 }, 92 | { "kiB", 1024 }, 93 | { "K", 1024 }, 94 | { "k", 1024 }, 95 | { "MiB", 1048576 }, 96 | { "miB", 1048576 }, 97 | { "M", 1048576 }, 98 | { "m", 1048576 }, 99 | { "GiB", 1073741824 }, 100 | { "giB", 1073741824 }, 101 | { "G", 1073741824 }, 102 | { "g", 1073741824 }, 103 | { "KB", 1000 }, 104 | { "MB", 1000000 }, 105 | { "GB", 1000000000 }, 106 | { "", 0 } 107 | }; 108 | -------------------------------------------------------------------------------- /log.c: -------------------------------------------------------------------------------- 1 | #include "log.h" 2 | 3 | #define MAX_CALLBACKS 32 4 | 5 | typedef struct { 6 | LogFn fn; 7 | void *udata; 8 | int level; 9 | } Callback; 10 | 11 | static struct { 12 | void *udata; 13 | LockFn lock; 14 | int level; 15 | bool quiet; 16 | Callback callbacks[MAX_CALLBACKS]; 17 | } L; 18 | 19 | static const char *level_str[] = { 20 | "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL" 21 | }; 22 | 23 | #ifdef LOG_USE_COLOR 24 | static const char *level_colors[] = { 25 | "\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m" 26 | }; 27 | #endif 28 | 29 | 30 | static void stdout_callback(LogEvent *ev) 31 | { 32 | char buf[16]; 33 | buf[strftime(buf, sizeof(buf), "%H:%M:%S", ev->time)] = '\0'; 34 | #ifdef LOG_USE_COLOR 35 | fprintf( 36 | ev->udata, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ", 37 | buf, level_colors[ev->level], level_str[ev->level], 38 | ev->file, ev->line); 39 | #endif 40 | vfprintf(ev->udata, ev->fmt, ev->ap); 41 | fprintf(ev->udata, "\n"); 42 | fflush(ev->udata); 43 | } 44 | 45 | static void file_callback(LogEvent *ev) 46 | { 47 | char buf[64]; 48 | buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time)] = '\0'; 49 | fprintf( 50 | ev->udata, "%s %-5s %s:%d: ", 51 | buf, level_str[ev->level], ev->file, ev->line); 52 | vfprintf(ev->udata, ev->fmt, ev->ap); 53 | fprintf(ev->udata, "\n"); 54 | fflush(ev->udata); 55 | } 56 | 57 | static void lock() 58 | { 59 | if (L.lock) { L.lock(false, L.udata); } 60 | } 61 | 62 | static void unlock() 63 | { 64 | if (L.lock) { L.lock(false, L.udata); } 65 | } 66 | 67 | const char *log_level_str(int level) 68 | { 69 | return level_str[level]; 70 | } 71 | 72 | void log_set_lock(LockFn fn, void *udata) 73 | { 74 | L.lock = fn; 75 | L.udata = udata; 76 | } 77 | 78 | void log_set_level(int level) 79 | { 80 | L.level = level; 81 | } 82 | 83 | void log_set_quiet(bool isquiet) 84 | { 85 | L.quiet = isquiet; 86 | } 87 | 88 | int log_add_callback(LogFn fn, void *udata, int level) 89 | { 90 | for (int i = 0; i < MAX_CALLBACKS; i++) { 91 | if (!L.callbacks[i].fn) { 92 | L.callbacks[i] = (Callback) { fn, udata, level }; 93 | return 0; 94 | } 95 | } 96 | return -1; 97 | } 98 | 99 | int log_add_fp(FILE *fp, int level) 100 | { 101 | return log_add_callback(file_callback, fp, level); 102 | } 103 | 104 | static void init_event(LogEvent *ev, void *udata) 105 | { 106 | if (!ev->time) { 107 | time_t t = time(NULL); 108 | ev->time = localtime(&t); 109 | } 110 | ev->udata = udata; 111 | } 112 | 113 | void log_log(int level, const char *file, int line, const char *fmt, ...) { 114 | 115 | LogEvent ev = { 116 | .fmt = fmt, 117 | .file = file, 118 | .line = line, 119 | .level = level, 120 | }; 121 | 122 | lock(); 123 | 124 | if (!L.quiet && level >= L.level) { 125 | init_event(&ev, stderr); 126 | va_start(ev.ap, fmt); 127 | stdout_callback(&ev); 128 | va_end(ev.ap); 129 | } 130 | 131 | for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].fn; i++) { 132 | Callback *cb = &L.callbacks[i]; 133 | if (level >= cb->level) { 134 | init_event(&ev, cb->udata); 135 | va_start(ev.ap, fmt); 136 | cb->fn(&ev); 137 | va_end(ev.ap); 138 | } 139 | } 140 | unlock(); 141 | } 142 | -------------------------------------------------------------------------------- /xatonum.h: -------------------------------------------------------------------------------- 1 | /* Provides extern declarations of functions */ 2 | #define DECLARE_STR_CONV(type, T, UT) \ 3 | \ 4 | unsigned type xstrto##UT##_range_sfx(const char *str, int b, unsigned type l, unsigned type u, const struct suffix_mult *sfx) ; \ 5 | unsigned type xstrto##UT##_range(const char *str, int b, unsigned type l, unsigned type u) ; \ 6 | unsigned type xstrto##UT##_sfx(const char *str, int b, const struct suffix_mult *sfx) ; \ 7 | unsigned type xstrto##UT(const char *str, int b) ; \ 8 | unsigned type xato##UT##_range_sfx(const char *str, unsigned type l, unsigned type u, const struct suffix_mult *sfx) ; \ 9 | unsigned type xato##UT##_range(const char *str, unsigned type l, unsigned type u) ; \ 10 | unsigned type xato##UT##_sfx(const char *str, const struct suffix_mult *sfx) ; \ 11 | unsigned type xato##UT(const char *str) ; \ 12 | type xstrto##T##_range_sfx(const char *str, int b, type l, type u, const struct suffix_mult *sfx) ; \ 13 | type xstrto##T##_range(const char *str, int b, type l, type u) ; \ 14 | type xstrto##T(const char *str, int b) ; \ 15 | type xato##T##_range_sfx(const char *str, type l, type u, const struct suffix_mult *sfx) ; \ 16 | type xato##T##_range(const char *str, type l, type u) ; \ 17 | type xato##T##_sfx(const char *str, const struct suffix_mult *sfx) ; \ 18 | type xato##T(const char *str) ; \ 19 | 20 | /* Provides inline definitions of functions */ 21 | /* (useful for mapping them to the type of the same width) */ 22 | #define DEFINE_EQUIV_STR_CONV(narrow, N, W, UN, UW) \ 23 | \ 24 | static ALWAYS_INLINE \ 25 | unsigned narrow xstrto##UN##_range_sfx(const char *str, int b, unsigned narrow l, unsigned narrow u, const struct suffix_mult *sfx) \ 26 | { return xstrto##UW##_range_sfx(str, b, l, u, sfx); } \ 27 | static ALWAYS_INLINE \ 28 | unsigned narrow xstrto##UN##_range(const char *str, int b, unsigned narrow l, unsigned narrow u) \ 29 | { return xstrto##UW##_range(str, b, l, u); } \ 30 | static ALWAYS_INLINE \ 31 | unsigned narrow xstrto##UN##_sfx(const char *str, int b, const struct suffix_mult *sfx) \ 32 | { return xstrto##UW##_sfx(str, b, sfx); } \ 33 | static ALWAYS_INLINE \ 34 | unsigned narrow xstrto##UN(const char *str, int b) \ 35 | { return xstrto##UW(str, b); } \ 36 | static ALWAYS_INLINE \ 37 | unsigned narrow xato##UN##_range_sfx(const char *str, unsigned narrow l, unsigned narrow u, const struct suffix_mult *sfx) \ 38 | { return xato##UW##_range_sfx(str, l, u, sfx); } \ 39 | static ALWAYS_INLINE \ 40 | unsigned narrow xato##UN##_range(const char *str, unsigned narrow l, unsigned narrow u) \ 41 | { return xato##UW##_range(str, l, u); } \ 42 | static ALWAYS_INLINE \ 43 | unsigned narrow xato##UN##_sfx(const char *str, const struct suffix_mult *sfx) \ 44 | { return xato##UW##_sfx(str, sfx); } \ 45 | static ALWAYS_INLINE \ 46 | unsigned narrow xato##UN(const char *str) \ 47 | { return xato##UW(str); } \ 48 | static ALWAYS_INLINE \ 49 | narrow xstrto##N##_range_sfx(const char *str, int b, narrow l, narrow u, const struct suffix_mult *sfx) \ 50 | { return xstrto##W##_range_sfx(str, b, l, u, sfx); } \ 51 | static ALWAYS_INLINE \ 52 | narrow xstrto##N##_range(const char *str, int b, narrow l, narrow u) \ 53 | { return xstrto##W##_range(str, b, l, u); } \ 54 | static ALWAYS_INLINE \ 55 | narrow xstrto##N(const char *str, int b) \ 56 | { return xstrto##W(str, b); } \ 57 | static ALWAYS_INLINE \ 58 | narrow xato##N##_range_sfx(const char *str, narrow l, narrow u, const struct suffix_mult *sfx) \ 59 | { return xato##W##_range_sfx(str, l, u, sfx); } \ 60 | static ALWAYS_INLINE \ 61 | narrow xato##N##_range(const char *str, narrow l, narrow u) \ 62 | { return xato##W##_range(str, l, u); } \ 63 | static ALWAYS_INLINE \ 64 | narrow xato##N##_sfx(const char *str, const struct suffix_mult *sfx) \ 65 | { return xato##W##_sfx(str, sfx); } \ 66 | static ALWAYS_INLINE \ 67 | narrow xato##N(const char *str) \ 68 | { return xato##W(str); } 69 | -------------------------------------------------------------------------------- /map.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "map.h" 4 | 5 | 6 | struct map_node_t { 7 | unsigned hash; 8 | void *val; 9 | map_node_t *next; 10 | }; 11 | 12 | static unsigned 13 | map_hash(const char *str) 14 | { 15 | if (!str) 16 | return 0; 17 | unsigned hash = 5381; 18 | while (*str) 19 | hash = ((hash << 5) + hash) ^ *str++; 20 | return hash; 21 | } 22 | 23 | static map_node_t * 24 | map_newnode(const char *key, void *val, int vsize) 25 | { 26 | int ksize = strlen(key) + 1; 27 | int voffset = ksize + ((sizeof(void *) - ksize) % sizeof(void *)); 28 | map_node_t *node = malloc(sizeof(map_node_t) + voffset + vsize); 29 | if (!node) return NULL; 30 | memcpy(node + 1, key, ksize); 31 | node->hash = map_hash(key); 32 | node->val = ((char *) (node + 1)) + voffset; 33 | memcpy(node->val, val, vsize); 34 | return node; 35 | } 36 | 37 | static int 38 | map_bucketidx(map_base_t *m, unsigned hash) 39 | { 40 | return hash & (m->nbuckets - 1); 41 | } 42 | 43 | static void 44 | map_addnode(map_base_t *m, map_node_t *node) 45 | { 46 | int n = map_bucketidx(m, node->hash); 47 | node->next = m->buckets[n]; 48 | m->buckets[n] = node; 49 | } 50 | 51 | static int 52 | map_resize(map_base_t *m, int nbuckets) 53 | { 54 | map_node_t *nodes = NULL, *node, *next; 55 | map_node_t **buckets; 56 | int i = m->nbuckets; 57 | while (i--) { 58 | node = (m->buckets)[i]; 59 | while (node) { 60 | next = node->next; 61 | node->next = nodes; 62 | nodes = node; 63 | node = next; 64 | } 65 | } 66 | 67 | buckets = realloc(m->buckets, sizeof(map_node_t) * nbuckets); 68 | if (buckets) { 69 | m->buckets = buckets; 70 | m->nbuckets = nbuckets; 71 | } 72 | 73 | if (m->buckets) { 74 | memset( 75 | m->buckets, 76 | 0, 77 | sizeof(map_node_t) * m->nbuckets 78 | ); 79 | node = nodes; 80 | while (node) { 81 | next = node->next; 82 | map_addnode(m, node); 83 | node = next; 84 | } 85 | } 86 | return (buckets) ? 0 : -1; 87 | } 88 | 89 | static map_node_t ** 90 | map_getref(map_base_t *m, const char *key) 91 | { 92 | unsigned hash = map_hash(key); 93 | map_node_t **next; 94 | if (m->nbuckets > 0) { 95 | next = &m->buckets[map_bucketidx(m, hash)]; 96 | while (*next) { 97 | if ((*next)->hash == hash && !strcmp((char *)(*next + 1), key)) 98 | return next; 99 | } 100 | next = &(*next)->next; 101 | } 102 | return NULL; 103 | } 104 | 105 | void ___map_deinit(map_base_t *m) 106 | { 107 | map_node_t *next, *node; 108 | int i = m->nbuckets; 109 | while (i--) { 110 | node = m->buckets[i]; 111 | while (node) { 112 | next = node->next; 113 | free(node); 114 | node = next; 115 | } 116 | } 117 | free(m->buckets); 118 | } 119 | 120 | void *___map_get(map_base_t *m, const char *key) 121 | { 122 | map_node_t **next = map_getref(m, key); 123 | return next ? (*next)->val : NULL; 124 | } 125 | 126 | int ___map_set(map_base_t *m, const char *key, void *val, int vsize) 127 | { 128 | map_node_t **next, *node; 129 | next = map_getref(m, key); 130 | if (next) { 131 | memcpy((*next)->val, val, vsize); 132 | return 0; 133 | } 134 | 135 | /* Add node */ 136 | node = map_newnode(key, val, vsize); 137 | if (!node) goto error; 138 | if (m->nnodes >= m->nbuckets) { 139 | int n = (m->nbuckets > 0) ? (m->nbuckets << 1) : 1; 140 | int err = map_resize(m, n); 141 | if (err) goto error; 142 | } 143 | map_addnode(m, node); 144 | m->nnodes++; 145 | return 0; 146 | error: 147 | if (node) free(node); 148 | return -1; 149 | } 150 | 151 | void ___map_remove(map_base_t *m, const char *key) 152 | { 153 | map_node_t *node; 154 | map_node_t **next = map_getref(m, key); 155 | if (next) { 156 | node = *next; 157 | *next = (*next)->next; 158 | free(node); 159 | m->nnodes--; 160 | } 161 | } 162 | 163 | map_iter_t ___map_iter() 164 | { 165 | return (map_iter_t){ 166 | .bucketidx = -1, 167 | .node = NULL 168 | }; 169 | } 170 | 171 | const char *___map_next(map_base_t *m, map_iter_t *iter) 172 | { 173 | if (iter->node) { 174 | iter->node = iter->node->next; 175 | if (iter->node) 176 | return (char *) (iter->node + 1); 177 | } 178 | do { 179 | if (++iter->bucketidx >= m->nbuckets) 180 | return NULL; 181 | iter->node = m->buckets[iter->bucketidx]; 182 | } while (!iter->node); 183 | return (char *) (iter->node + 1); 184 | } 185 | -------------------------------------------------------------------------------- /xatonum_template.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Licensed under GPLv2, see file LICENSE in this source tree. 4 | */ 5 | /* 6 | You need to define the following (example): 7 | 8 | */ 9 | 10 | unsigned type xstrtou(_range_sfx)(const char *numstr, int base, 11 | unsigned type lower, 12 | unsigned type upper, 13 | const struct suffix_mult *suffixes) 14 | { 15 | unsigned type r; 16 | int old_errno; 17 | char *e; 18 | 19 | /* Disallow '-' and any leading whitespace. */ 20 | if (*numstr == '-' || *numstr == '+' || isspace(*numstr)) 21 | goto inval; 22 | 23 | /* Since this is a lib function, we're not allowed to reset errno to 0. 24 | * Doing so could break an app that is deferring checking of errno. 25 | * So, save the old value so that we can restore it if successful. */ 26 | old_errno = errno; 27 | errno = 0; 28 | r = XSTR_STRTOU(numstr, &e, base); 29 | /* Do the initial validity check. Note: The standards do not 30 | * guarantee that errno is set if no digits were found. So we 31 | * must test for this explicitly. */ 32 | if (errno || numstr == e) 33 | goto inval; /* error / no digits / illegal trailing chars */ 34 | 35 | errno = old_errno; /* Ok. So restore errno. */ 36 | 37 | /* Do optional suffix parsing. Allow 'empty' suffix tables. 38 | * Note that we also allow nul suffixes with associated multipliers, 39 | * to allow for scaling of the numstr by some default multiplier. */ 40 | if (suffixes) { 41 | while (suffixes->mult) { 42 | if (strcmp(suffixes->suffix, e) == 0) { 43 | if (XSTR_UTYPE_MAX / suffixes->mult < r) 44 | goto range; /* overflow! */ 45 | r *= suffixes->mult; 46 | goto chk_range; 47 | } 48 | ++suffixes; 49 | } 50 | } 51 | 52 | /* Note: trailing space is an error. 53 | * It would be easy enough to allow though if desired. */ 54 | if (*e) 55 | goto inval; 56 | chk_range: 57 | /* Finally, check for range limits. */ 58 | if (r >= lower && r <= upper) 59 | return r; 60 | range: 61 | exit(EXIT_FAILURE); 62 | inval: 63 | exit(EXIT_FAILURE); 64 | } 65 | 66 | unsigned type xstrtou(_range)(const char *numstr, int base, 67 | unsigned type lower, 68 | unsigned type upper) 69 | { 70 | return xstrtou(_range_sfx)(numstr, base, lower, upper, NULL); 71 | } 72 | 73 | unsigned type xstrtou(_sfx)(const char *numstr, int base, 74 | const struct suffix_mult *suffixes) 75 | { 76 | return xstrtou(_range_sfx)(numstr, base, 0, XSTR_UTYPE_MAX, suffixes); 77 | } 78 | 79 | unsigned type xstrtou()(const char *numstr, int base) 80 | { 81 | return xstrtou(_range_sfx)(numstr, base, 0, XSTR_UTYPE_MAX, NULL); 82 | } 83 | 84 | unsigned type xatou(_range_sfx)(const char *numstr, 85 | unsigned type lower, 86 | unsigned type upper, 87 | const struct suffix_mult *suffixes) 88 | { 89 | return xstrtou(_range_sfx)(numstr, 10, lower, upper, suffixes); 90 | } 91 | 92 | unsigned type xatou(_range)(const char *numstr, 93 | unsigned type lower, 94 | unsigned type upper) 95 | { 96 | return xstrtou(_range_sfx)(numstr, 10, lower, upper, NULL); 97 | } 98 | 99 | unsigned type xatou(_sfx)(const char *numstr, 100 | const struct suffix_mult *suffixes) 101 | { 102 | return xstrtou(_range_sfx)(numstr, 10, 0, XSTR_UTYPE_MAX, suffixes); 103 | } 104 | 105 | unsigned type xatou()(const char *numstr) 106 | { 107 | return xatou(_sfx)(numstr, NULL); 108 | } 109 | 110 | /* Signed ones */ 111 | 112 | type xstrto(_range_sfx)(const char *numstr, int base, 113 | type lower, 114 | type upper, 115 | const struct suffix_mult *suffixes) 116 | { 117 | unsigned type u = XSTR_TYPE_MAX; 118 | type r; 119 | const char *p = numstr; 120 | 121 | /* NB: if you'll decide to disallow '+': 122 | * at least renice applet needs to allow it */ 123 | if (p[0] == '+' || p[0] == '-') { 124 | ++p; 125 | if (p[0] == '-') 126 | ++u; /* = _MIN (01111... + 1 == 10000...) */ 127 | } 128 | 129 | r = xstrtou(_range_sfx)(p, base, 0, u, suffixes); 130 | 131 | if (*numstr == '-') { 132 | r = -r; 133 | } 134 | 135 | if (r < lower || r > upper) { 136 | exit(EXIT_FAILURE); 137 | } 138 | 139 | return r; 140 | } 141 | 142 | type xstrto(_range)(const char *numstr, int base, type lower, type upper) 143 | { 144 | return xstrto(_range_sfx)(numstr, base, lower, upper, NULL); 145 | } 146 | 147 | type xstrto()(const char *numstr, int base) 148 | { 149 | return xstrto(_range_sfx)(numstr, base, XSTR_TYPE_MIN, XSTR_TYPE_MAX, NULL); 150 | } 151 | 152 | type xato(_range_sfx)(const char *numstr, 153 | type lower, 154 | type upper, 155 | const struct suffix_mult *suffixes) 156 | { 157 | return xstrto(_range_sfx)(numstr, 10, lower, upper, suffixes); 158 | } 159 | 160 | type xato(_range)(const char *numstr, type lower, type upper) 161 | { 162 | return xstrto(_range_sfx)(numstr, 10, lower, upper, NULL); 163 | } 164 | 165 | type xato(_sfx)(const char *numstr, const struct suffix_mult *suffixes) 166 | { 167 | return xstrto(_range_sfx)(numstr, 10, XSTR_TYPE_MIN, XSTR_TYPE_MAX, suffixes); 168 | } 169 | 170 | type xato()(const char *numstr) 171 | { 172 | return xstrto(_range_sfx)(numstr, 10, XSTR_TYPE_MIN, XSTR_TYPE_MAX, NULL); 173 | } 174 | 175 | #undef type 176 | #undef xstrtou 177 | #undef xstrto 178 | #undef xatou 179 | #undef xato 180 | #undef XSTR_UTYPE_MAX 181 | #undef XSTR_TYPE_MAX 182 | #undef XSTR_TYPE_MIN 183 | #undef XSTR_STRTOU 184 | -------------------------------------------------------------------------------- /vector.h: -------------------------------------------------------------------------------- 1 | #ifndef VECTOR_H 2 | #define VECTOR_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | typedef void (*vector_elem_destructor_t) (void *elem); 9 | 10 | typedef struct { 11 | size_t size; 12 | size_t capacity; 13 | vector_elem_destructor_t elem_destructor; 14 | } vector_metadata_t; 15 | 16 | #define vector(type) type * 17 | 18 | #define vector_vec_to_base(vec) \ 19 | (&((vector_metadata_t *)(vec))[-1]) 20 | 21 | #define vector_base_to_vec(ptr) \ 22 | ((void *)&((vector_metadata_t *)(ptr))[-1]) 23 | 24 | #define vector_capacity(vec) \ 25 | ((vec) ? vector_vec_to_base(vec)->capacity : (size_t) 0) 26 | 27 | #define vector_size(vec) \ 28 | ((vec) ? vector_vec_to_base(vec)->size : (size_t) 0) 29 | 30 | #define vector_elem_destructor(vec) \ 31 | ((vec) ? vector_vec_to_base(vec)->elem_destructor : NULL) 32 | 33 | #define vector_empty(vec) \ 34 | (vector_size(vec) == 0) 35 | 36 | #define vector_reserve(vec, capacity) \ 37 | do { \ 38 | size_t cv_cap_ = vector_capacity(vec); \ 39 | if (cv_cap_ < (capacity)); \ 40 | vector_grow((vec), (capacity)); \ 41 | } while (0) 42 | 43 | #define vector_erase(vec, i) \ 44 | do { \ 45 | if (vec) { \ 46 | const size_t cv_sz_ = vector_size(vec); \ 47 | if ((i) < cv_sz_) { \ 48 | vector_elem_destructor_t elem_destructor_ = vector_elem_destructor(vec); \ 49 | if (elem_destructor_) \ 50 | elem_destructor_(&vec[i]); \ 51 | vector_set_size((vec), cv_sz_ - 1); \ 52 | memmove( \ 53 | (vec) + (i), \ 54 | (vec) + (i) + 1, \ 55 | sizeof(*(vec)) * (cv_sz_ - 1 - (i)) \ 56 | ); \ 57 | } \ 58 | } \ 59 | } while (0) 60 | 61 | #define vector_clear(vec) \ 62 | do { \ 63 | if (vec) { \ 64 | vector_elem_destructor_t elem_destructor_ = vector_elem_destructor(vec); \ 65 | if (elem_destructor_) { \ 66 | for (size_t i_ = 0; i_ < vector_size(vec); ++i_) \ 67 | elem_destructor_(&vec[i_]); \ 68 | } \ 69 | vector_set_size(vec, 0); \ 70 | } \ 71 | } while (0) 72 | 73 | #define vector_free(vec) \ 74 | do { \ 75 | if (vec) { \ 76 | void *p1_ = vector_vec_to_base(vec); \ 77 | vector_elem_destructor_t elem_destructor_ = vector_elem_destructor(vec); \ 78 | if (elem_destructor_) \ 79 | for (size_t i_ = 0; i_ < vector_size(vec); i_++) \ 80 | elem_destructor_(&vec[i_]); \ 81 | vector_free(vec); \ 82 | } \ 83 | } while (0) 84 | 85 | 86 | #define vector_compute_next_grow(size) \ 87 | ((size) ? ((size) << 1) : 1) 88 | 89 | #define vector_push_back(vec, value) \ 90 | do { \ 91 | size_t cv_cap_ = vector_capacity(vec); \ 92 | if (cv_cap_ <= vector_size(vec)) \ 93 | vector_grow((vec), vector_compute_next_grow(cv_cap_)); \ 94 | (vec)[vector_size(vec)] = (value); \ 95 | vector_set_size((vec), vector_size(vec) + 1); \ 96 | } while (0) 97 | 98 | #define vector_insert(vec, pos, val) \ 99 | do { \ 100 | size_t cv_cap_ = vector_capacity(vec); \ 101 | if (cv_cap_ <= vector_size(vec)) \ 102 | vector_grow((vec), vector_compute_next_grow(cv_cap_)); \ 103 | if ((pos) < vector_size(vec)) { \ 104 | memmove( \ 105 | (vec) + (pos) + 1, \ 106 | (vec) + (pos), \ 107 | sizeof(*(vec)) * ((vector_size(vec)) - (pos)); \ 108 | ); \ 109 | } \ 110 | (vec)[(pos)] = (val); \ 111 | vector_set_size((vec), vector_size(vec) + 1); \ 112 | } while (0) 113 | 114 | #define vector_pop_back(vec) \ 115 | do { \ 116 | vector_elem_destructor_t elem_destructor_ = vector_elem_destructor(vec); \ 117 | if (elem_destructor_) \ 118 | elem_destructor_(&(vec)[vector_size(vec) - 1]); \ 119 | vector_set_size((vec), vector_size(vec) - 1); \ 120 | } while (0) 121 | 122 | #define vector_copy(from, to) \ 123 | do { \ 124 | if ((from)) { \ 125 | vector_grow(to, vector_size(from)); \ 126 | vector_set_size(to, vector_size(from)); \ 127 | memcpy((to), (from), vector_size(from) * sizeof(*(from))); \ 128 | } \ 129 | } while (0) 130 | 131 | #define vector_set_capacity(vec, size) \ 132 | do { \ 133 | if (vec) \ 134 | vector_vec_to_base(vec)->capacity = (size); \ 135 | } while (0) 136 | 137 | #define vector_set_size(vec, _size) \ 138 | do { \ 139 | if (vec) \ 140 | vector_vec_to_base(vec)->size = (_size); \ 141 | } while (0) 142 | 143 | #define vector_set_elem_destructor(vec, elem_destructor_fn) \ 144 | do { \ 145 | if (vec) \ 146 | vector_vec_to_base(vec)->elem_destructor = (elem_destructor_fn); \ 147 | } while (0) 148 | 149 | #define vector_grow(vec, count) \ 150 | do { \ 151 | const size_t cv_sz_ = (count) * sizeof(*(vec)) + sizeof(vector_metadata_t); \ 152 | if (vec) { \ 153 | void *cv_p1_ = vector_vec_to_base(vec); \ 154 | void *cv_p2_ = realloc(cv_p1_, cv_sz_); \ 155 | assert(cv_p2_); \ 156 | (vec) = vector_base_to_vec(cv_p2_); \ 157 | } else { \ 158 | void *cv_p_ = malloc(cv_sz_); \ 159 | assert(cv_p_); \ 160 | (vec) = vector_base_to_vec(cv_p_); \ 161 | vector_set_size((vec), 0); \ 162 | vector_set_elem_destructor((vec), NULL); \ 163 | } \ 164 | vector_set_capacity((vec), (count)); \ 165 | } while (0) 166 | 167 | #endif /* VECTOR_H */ 168 | --------------------------------------------------------------------------------