From: Lukas Krickl Date: Sun, 22 Mar 2026 06:07:17 +0000 (+0100) Subject: chore: removed some posix string functions with custom implementations X-Git-Url: https://git.krickl.dev/?a=commitdiff_plain;h=196ebc1fc35f9a374bde49af765a397c3841a6a2;p=ulas%2F.git chore: removed some posix string functions with custom implementations This will eventually allow us to move to -std=c99 without posix extensions. --- diff --git a/makefile b/makefile index 82ed687..9a4b779 100644 --- a/makefile +++ b/makefile @@ -11,7 +11,7 @@ OBJS:= CCOBJ=$(CC) -c -o $@ $< $(CFLAGS) $(LDFLAGS) -all: bin test +all: bin btest release: make DBGCFLAGS="" DBGLDFLAGS="" @@ -26,9 +26,18 @@ test.o: src/test.c bin: main.o $(OBJS) $(CC) -o $(NAME) main.o $(OBJS) $(CFLAGS) $(LDFLAGS) -test: test.o $(OBJS) +btest: test.o $(OBJS) $(CC) -o $(TEST_NAME) test.o $(OBJS) $(CFLAGS) $(LDFLAGS) +.PHONY: test +test: $(TEST_NAME) + ./$(TEST_NAME) + + +.PHONY: run +run: $(NAME) + ./$(NAME) + .PHONY: clean clean: rm -f ./*.o diff --git a/src/main.c b/src/main.c index 9e7aadd..95ab531 100644 --- a/src/main.c +++ b/src/main.c @@ -37,20 +37,20 @@ void ulas_getopt(int argc, char **argv, struct ulas_config *cfg) { cfg->verbose = 1; break; case 'o': - cfg->output_path = strndup(optarg, ULAS_PATHMAX); + cfg->output_path = ulas_strndup(optarg, ULAS_PATHMAX); break; case 'p': cfg->preproc_only = 1; break; case 's': - cfg->sym_path = strndup(optarg, ULAS_PATHMAX); + cfg->sym_path = ulas_strndup(optarg, ULAS_PATHMAX); break; case 'l': - cfg->lst_path = strndup(optarg, ULAS_PATHMAX); + cfg->lst_path = ulas_strndup(optarg, ULAS_PATHMAX); break; case 'I': assert(incpathslen < ULAS_INCPATHSMAX); - incpaths[incpathslen++] = strndup(optarg, ULAS_PATHMAX); + incpaths[incpathslen++] = ulas_strndup(optarg, ULAS_PATHMAX); break; case 'a': cfg->org = strtol(optarg, NULL, 0); @@ -66,7 +66,7 @@ void ulas_getopt(int argc, char **argv, struct ulas_config *cfg) { break; case 'D': assert(defslen < ULAS_DEFSMAX); - defs[defslen++] = strndup(optarg, ULAS_PATHMAX); + defs[defslen++] = ulas_strndup(optarg, ULAS_PATHMAX); break; case 'S': if (strcmp("ulas", optarg) == 0) { diff --git a/src/ulas.c b/src/ulas.c index 9f1d3d8..3e14725 100644 --- a/src/ulas.c +++ b/src/ulas.c @@ -105,6 +105,39 @@ void ulas_free(void) { ulas_preprocfree(&ulas.pp); } +char *ulas_strdup(const char *s) { + int len = strlen(s); + return ulas_strndup(s, len); +} + +char *ulas_strndup(const char *s, unsigned int max) { + int len = ulas_strnlen(s, max); + char *dup = malloc(len+1); + memcpy(dup, s, len+1); + return dup; +} + +unsigned int ulas_strnlen(const char *s, unsigned int max) { + unsigned int i = 0; + while (i < max && s[i]) { + i++; + } + return i; +} + +unsigned int ulas_strlcat(char *dst, const char *src, unsigned int max) { + unsigned int dst_len = ulas_strnlen(dst, max); + unsigned int src_len = ulas_strnlen(src, max); + + for (int i = 0; i < src_len; i++) { + dst[dst_len+i] = src[i]; + } + + dst[src_len + dst_len] = '\0'; + + return src_len + dst_len; +} + FILE *ulas_incpathfopen(const char *path, const char *mode) { char pathbuf[ULAS_PATHMAX]; memset(pathbuf, 0, ULAS_PATHMAX); @@ -119,11 +152,11 @@ FILE *ulas_incpathfopen(const char *path, const char *mode) { continue; } - strlcat(pathbuf, ip, ULAS_PATHMAX); + ulas_strlcat(pathbuf, ip, ULAS_PATHMAX); if (ip[len - 1] != ULAS_PATHSEP[0]) { - strlcat(pathbuf, ULAS_PATHSEP, ULAS_PATHMAX); + ulas_strlcat(pathbuf, ULAS_PATHSEP, ULAS_PATHMAX); } - strlcat(pathbuf, path, ULAS_PATHMAX); + ulas_strlcat(pathbuf, path, ULAS_PATHMAX); FILE *f = fopen(pathbuf, mode); if (f != NULL) { @@ -345,7 +378,7 @@ int ulas_symbolset(const char *cname, int scope, struct ulas_tok tok, if (!existing || (name[0] == '\0' && len == 1)) { // def new symbol - struct ulas_sym new_sym = {strndup(name, len), tok, scope, ulas.pass, + struct ulas_sym new_sym = {ulas_strndup(name, len), tok, scope, ulas.pass, constant}; ulas_symbufpush(&ulas.syms, new_sym); @@ -765,7 +798,7 @@ struct ulas_tok ulas_totok(char *buf, unsigned long n, int *rc) { // literal token // we resolve it later, will need to malloc here for now tok.type = ULAS_SYMBOL; - tok.val.strv = strndup(buf - 1, n); + tok.val.strv = ulas_strndup(buf - 1, n); buf += n - 1; } else { ULASERR("Unexpected token: %s\n", buf); @@ -807,7 +840,7 @@ struct ulas_str ulas_strensr(struct ulas_str *s, unsigned long maxlen) { } struct ulas_str ulas_strreq(struct ulas_str *s, unsigned long n) { - return ulas_strensr(s, strnlen(s->buf, s->maxlen) + n); + return ulas_strensr(s, ulas_strnlen(s->buf, s->maxlen) + n); } void ulas_strfree(struct ulas_str *s) { @@ -842,7 +875,7 @@ int ulas_preproclws(struct ulas_preproc *pp, const char *praw_line, } void ulas_trimend(char c, char *buf, unsigned long n) { - unsigned long buflen = strnlen(buf, n); + unsigned long buflen = ulas_strnlen(buf, n); if (buflen == 0) { return; } @@ -984,7 +1017,7 @@ char *ulas_preprocexpand2(struct ulas_preproc *pp, const char *raw_line, // to ensure expansion are separated if we are in a recursive call // this fixes new lines in recursive macros being consumed if (recursive) { - int len = strnlen(pp->line.buf, pp->line.maxlen) + 1; + int len = ulas_strnlen(pp->line.buf, pp->line.maxlen) + 1; ulas_strensr(&pp->line, len + 1); strncat(pp->line.buf, "\n", len); @@ -1003,8 +1036,8 @@ char *ulas_preprocexpand2(struct ulas_preproc *pp, const char *raw_line, const char *name = macro_argname[mi]; if (pp->macroparam[mi].buf[0] && strncmp((name), pp->macrobuf.buf, pp->macrobuf.maxlen) == 0) { - ulas_strensr(&pp->line, strnlen(pp->line.buf, pp->line.maxlen) + - strnlen(pp->macroparam[mi].buf, + ulas_strensr(&pp->line, ulas_strnlen(pp->line.buf, pp->line.maxlen) + + ulas_strnlen(pp->macroparam[mi].buf, pp->macroparam[mi].maxlen) + 1); @@ -1018,7 +1051,7 @@ char *ulas_preprocexpand2(struct ulas_preproc *pp, const char *raw_line, if (linelen && strncmp("$0", pp->macrobuf.buf, pp->macrobuf.maxlen) == 0) { ulas_strensr(&pp->line, - strnlen(pp->line.buf, pp->line.maxlen) + linelen + 1); + ulas_strnlen(pp->line.buf, pp->line.maxlen) + linelen + 1); if (linelen > 1) { // this skips the separating token which is usually a space @@ -1034,7 +1067,7 @@ char *ulas_preprocexpand2(struct ulas_preproc *pp, const char *raw_line, pp->macrobuf.maxlen) == 0) { sprintf(numbuf, "%x", ulas_icntr()); ulas_strensr(&pp->line, - strnlen(pp->line.buf, pp->line.maxlen) + 128 + 1); + ulas_strnlen(pp->line.buf, pp->line.maxlen) + 128 + 1); tocat = numbuf; tocatlen = 128; } @@ -1045,7 +1078,7 @@ char *ulas_preprocexpand2(struct ulas_preproc *pp, const char *raw_line, } else { // make sure to include leading white space int wsi = ulas_preproclws(pp, val - valread, vallen); - ulas_strensr(&pp->line, strnlen(pp->line.buf, pp->line.maxlen) + + ulas_strensr(&pp->line, ulas_strnlen(pp->line.buf, pp->line.maxlen) + tocatlen + wsi + 1); strncat(pp->line.buf, tocat, tocatlen); } @@ -1135,7 +1168,8 @@ found: return -1; } - struct ulas_ppdef def = {ULAS_PPDEF, strdup(pp->tok.buf), strdup(pline), + struct ulas_ppdef def = {ULAS_PPDEF, ulas_strdup(pp->tok.buf), + ulas_strdup(pline), 0}; ulas_preprocdef(pp, def); // define short-circuits the rest of the logic @@ -1154,7 +1188,7 @@ found: ULASERR("'%s' is not a valid #macro name!\n", pp->tok.buf); return -1; } - char *name = strdup(pp->tok.buf); + char *name = ulas_strdup(pp->tok.buf); struct ulas_str val = ulas_str(32); memset(val.buf, 0, 32); @@ -1175,8 +1209,8 @@ found: break; } - unsigned long len = strnlen(pp->line.buf, pp->line.maxlen); - ulas_strensr(&val, strnlen(val.buf, val.maxlen) + len + 1); + unsigned long len = ulas_strnlen(pp->line.buf, pp->line.maxlen); + ulas_strensr(&val, ulas_strnlen(val.buf, val.maxlen) + len + 1); strncat(val.buf, pp->line.buf, val.maxlen); } @@ -1258,7 +1292,7 @@ found: char *prev_path = ulas.filename; unsigned long prev_lines = ulas.line; - ulas.filename = strdup(path); + ulas.filename = ulas_strdup(path); ulas.line = 0; FILE *tmp = tmpfile(); @@ -1295,7 +1329,7 @@ found: int ulas_last_print_is_escape(char *buf, int n) { int found_escape = 0; // check if last printable char is an escape char - unsigned int buf_len = strnlen(buf, n); + unsigned int buf_len = ulas_strnlen(buf, n); if (buf_len == 0) { return 0; } @@ -1366,7 +1400,8 @@ struct ulas_preproc ulas_preprocinit(void) { // set up initial defs for (int i = 0; i < ulascfg.defslen; i++) { - struct ulas_ppdef def = {ULAS_PPDEF, strdup(ulascfg.defs[i]), strdup(""), + struct ulas_ppdef def = {ULAS_PPDEF, ulas_strdup(ulascfg.defs[i]), + ulas_strdup(""), 0}; ulas_preprocdef(&pp, def); } @@ -1613,7 +1648,7 @@ void ulas_symbuffree(struct ulas_symbuf *sb) { */ int ulas_istokend(struct ulas_str *tok) { - long len = (int)strnlen(tok->buf, tok->maxlen); + long len = (int)ulas_strnlen(tok->buf, tok->maxlen); // skip comments though, they are not trailing tokens! if (len > 0 && tok->buf[0] != ULAS_TOK_COMMENT) { return 0; @@ -1633,13 +1668,13 @@ int ulas_tokexpr(const char **line, unsigned long n) { } // empty tokens are going to be ignored - if (strnlen(ulas.tok.buf, ulas.tok.maxlen) == 0) { + if (ulas_strnlen(ulas.tok.buf, ulas.tok.maxlen) == 0) { continue; } // interpret the token struct ulas_tok tok = ulas_totok( - ulas.tok.buf, strnlen(ulas.tok.buf, ulas.tok.maxlen), &tokrc); + ulas.tok.buf, ulas_strnlen(ulas.tok.buf, ulas.tok.maxlen), &tokrc); if (tokrc == -1) { goto end; } @@ -2194,7 +2229,7 @@ int ulas_asmdirbyte(FILE *dst, const char **line, unsigned long n, int *rc) { written++; if (ulas_tok(&ulas.tok, line, n) > 0) { - t = ulas_totok(ulas.tok.buf, strnlen(ulas.tok.buf, ulas.tok.maxlen), rc); + t = ulas_totok(ulas.tok.buf, ulas_strnlen(ulas.tok.buf, ulas.tok.maxlen), rc); } else { break; } @@ -2338,7 +2373,7 @@ int ulas_asmdirfill(FILE *dst, const char **line, unsigned long n, int *rc) { ulas_tok(&ulas.tok, line, n); struct ulas_tok t = - ulas_totok(ulas.tok.buf, strnlen(ulas.tok.buf, ulas.tok.maxlen), rc); + ulas_totok(ulas.tok.buf, ulas_strnlen(ulas.tok.buf, ulas.tok.maxlen), rc); if (*rc == -1 || t.type != ',') { ULASERR("Expected ,\n"); @@ -2387,7 +2422,7 @@ int ulas_asmdirstr(FILE *dst, const char **line, unsigned long n, int *rc) { written += len; if (ulas_tok(&ulas.tok, line, n) > 0) { - t = ulas_totok(ulas.tok.buf, strnlen(ulas.tok.buf, ulas.tok.maxlen), rc); + t = ulas_totok(ulas.tok.buf, ulas_strnlen(ulas.tok.buf, ulas.tok.maxlen), rc); } else { break; } @@ -2420,12 +2455,12 @@ int ulas_asmdirincbin(FILE *dst, const char **line, unsigned long n, int *rc) { } int ulas_asmdiradv(FILE *dst, const char **line, unsigned long n, int *rc) { - ULAS_EVALEXPRS(ulas.address += ulas_intexpr(line, strnlen(*line, n), rc)); + ULAS_EVALEXPRS(ulas.address += ulas_intexpr(line, ulas_strnlen(*line, n), rc)); return 0; } int ulas_asmdirsetenum(FILE *dst, const char **line, unsigned long n, int *rc) { - ULAS_EVALEXPRS(ulas.enumv = ulas_intexpr(line, strnlen(*line, n), rc)); + ULAS_EVALEXPRS(ulas.enumv = ulas_intexpr(line, ulas_strnlen(*line, n), rc)); return 0; } @@ -2438,7 +2473,7 @@ int ulas_asmdirsetcharcode(const char **line, unsigned long n) { ulas_tok(&ulas.tok, line, n); struct ulas_tok t = - ulas_totok(ulas.tok.buf, strnlen(ulas.tok.buf, ulas.tok.maxlen), &rc); + ulas_totok(ulas.tok.buf, ulas_strnlen(ulas.tok.buf, ulas.tok.maxlen), &rc); if (rc == -1 || t.type != '=') { ULASERR("Expected =\n"); @@ -2525,7 +2560,7 @@ int ulas_asmdirrep(FILE *dst, FILE *src, const char **line, unsigned long n) { ULAS_EVALEXPRS(repval = ulas_intexpr(line, n, &rc)); ulas_tok(&ulas.tok, line, n); struct ulas_tok t = - ulas_totok(ulas.tok.buf, strnlen(ulas.tok.buf, ulas.tok.maxlen), &rc); + ulas_totok(ulas.tok.buf, ulas_strnlen(ulas.tok.buf, ulas.tok.maxlen), &rc); if (rc == -1 || t.type != ',') { ULASERR("Expected ,\n"); return 0; @@ -2534,7 +2569,7 @@ int ulas_asmdirrep(FILE *dst, FILE *src, const char **line, unsigned long n) { int step = 0; ULAS_EVALEXPRS(step = ulas_intexpr(line, n, &rc)); ulas_tok(&ulas.tok, line, n); - t = ulas_totok(ulas.tok.buf, strnlen(ulas.tok.buf, ulas.tok.maxlen), &rc); + t = ulas_totok(ulas.tok.buf, ulas_strnlen(ulas.tok.buf, ulas.tok.maxlen), &rc); if (rc == -1 || t.type != ',') { ULASERR("Expected ,\n"); return 0; @@ -2569,7 +2604,7 @@ int ulas_asmdirsection(FILE *dst, FILE *src, const char **line, int ulas_asmdirbank(FILE *dst, FILE *src, const char **line, unsigned long n, int *rc) { - ULAS_EVALEXPRS(ulas.bank = ulas_intexpr(line, strnlen(*line, n), rc)); + ULAS_EVALEXPRS(ulas.bank = ulas_intexpr(line, ulas_strnlen(*line, n), rc)); return *rc; } @@ -2649,7 +2684,7 @@ int ulas_asmline(FILE *dst, FILE *src, const char *line, unsigned long n) { switch (dir) { case ULAS_ASMDIR_ORG: { ULAS_EVALEXPRS(ulas.address = - ulas_intexpr(&line, strnlen(start, n), &rc)); + ulas_intexpr(&line, ulas_strnlen(start, n), &rc)); break; } case ULAS_ASMDIR_DEF: diff --git a/src/ulas.h b/src/ulas.h index 4fcb0fb..c0bd764 100644 --- a/src/ulas.h +++ b/src/ulas.h @@ -515,7 +515,6 @@ FILE *ulas_incpathfopen(const char *path, const char *mode); int ulas_main(struct ulas_config cfg); -char *ulas_strndup(const char *src, unsigned long n); // resolve a symbol until an actual literal token (str, int) is found // returns NULL if the symbol cannot be resolved @@ -658,10 +657,21 @@ int ulas_asm(FILE *dst, FILE *src); int ulas_asmline(FILE *dst, FILE *src, const char *line, unsigned long n); const char *ulas_asmregstr(unsigned int reg); -// parses and executes a 32 bit signed int math expressions +/* parses and executes a 32 bit signed int math expressions */ int ulas_intexpr(const char **line, unsigned long n, int *rc); char *ulas_strexpr(const char **line, unsigned long n, int *rc); +/* ulas string functions */ + +/* + * duplicates a string + */ +char *ulas_strdup(const char *s); +char *ulas_strndup(const char *s, unsigned int max); +unsigned int ulas_strnlen(const char *s, unsigned int max); +unsigned int ulas_strlcat(char *dst, const char *src, unsigned int max); + + void ulas_help(void); void ulas_version(void);