chore: removed some posix string functions with custom implementations
authorLukas Krickl <lukas@krickl.dev>
Sun, 22 Mar 2026 06:07:17 +0000 (07:07 +0100)
committerLukas Krickl <lukas@krickl.dev>
Sun, 22 Mar 2026 06:07:17 +0000 (07:07 +0100)
This will eventually allow us to move to -std=c99 without posix
extensions.

makefile
src/main.c
src/ulas.c
src/ulas.h

index 82ed687f503fddeafcbca03d620f46e8fb63f36c..9a4b77919d8eeb6d53892e6741aa6daf8fd2458a 100644 (file)
--- 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
index 9e7aadd4cd2b2e863d5a76cbf17b46c406c181c4..95ab531b767726d8b01561edf427818632717ea4 100644 (file)
@@ -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) {
index 9f1d3d8426057bd6bed215c5a4fc3af8f03fd78a..3e147251932333d83e0215780a95f15a6a637538 100644 (file)
@@ -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:
index 4fcb0fb794b6e388a5c6ca9a0e6a97f5df2a9f05..c0bd764fd3e24bb3b1297fa46850dd0eba677389 100644 (file)
@@ -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);