Fixed switch indentation
authorLukas Krickl <lukas@krickl.dev>
Fri, 17 Nov 2023 17:35:54 +0000 (18:35 +0100)
committerLukas Krickl <lukas@krickl.dev>
Fri, 17 Nov 2023 17:35:54 +0000 (18:35 +0100)
makefile
src/main.c
src/ulas.c

index 6c449402af1c7018ef1416c9113b26a1b13e262d..1772663e162d348a5ce4a162e4d895b51605acfd 100644 (file)
--- a/makefile
+++ b/makefile
@@ -57,7 +57,7 @@ tags:
 
 .PHONY: format
 format:
-       VERSION_CONTROL=none indent -kr -ci2 -cli2 -i2 -l80 -nut -brf -par src/*.c $(IDIR)/*.h
+       VERSION_CONTROL=none indent -kr -ci2 -cli2 -i2 -l80 -nut -brf -par -cli0 -cbi0 src/*.c $(IDIR)/*.h
 
 .PHONY: lint
 lint:
index 72dbe510dca16e4c2006a9cbf9027fe44b1e488b..d07fe3a2c8b5bc6141791e37522eb04d0a0eb80d 100644 (file)
@@ -34,30 +34,30 @@ void ulas_getopt(int argc, char **argv, struct ulas_config *cfg) {
   int c = 0;
   while ((c = getopt(argc, argv, ULAS_OPTS ULAS_OPTS_ARG)) != -1) {
     switch (c) {
-      case 'h':
-        ulas_help();
-        exit(0);
-        break;
-      case 'V':
-        ulas_version();
-        exit(0);
-        break;
-      case 'v':
-        cfg->verbose = 1;
-        break;
-      case 'o':
-        cfg->output_path = strndup(optarg, ULAS_PATHMAX);
-        break;
-      case 'p':
-        cfg->preproc_only = 1;
-        break;
-      case '?':
-        break;
-      default:
-        printf("%s: invalid option '%c'\nTry '%s -h' for more information.\n",
-               ULAS_NAME, c, ULAS_NAME);
-        exit(-1);
-        break;
+    case 'h':
+      ulas_help();
+      exit(0);
+      break;
+    case 'V':
+      ulas_version();
+      exit(0);
+      break;
+    case 'v':
+      cfg->verbose = 1;
+      break;
+    case 'o':
+      cfg->output_path = strndup(optarg, ULAS_PATHMAX);
+      break;
+    case 'p':
+      cfg->preproc_only = 1;
+      break;
+    case '?':
+      break;
+    default:
+      printf("%s: invalid option '%c'\nTry '%s -h' for more information.\n",
+             ULAS_NAME, c, ULAS_NAME);
+      exit(-1);
+      break;
     }
   }
 
index 197915d89cf01449d35056eb0cf509a7a3e6827b..a6a02ead9f6cf46ecc9bec3abbff61914f1c45e8 100644 (file)
@@ -145,37 +145,37 @@ int ulas_tok(struct ulas_str *dst, const char **out_line, unsigned long n) {
     char c = line[i];
 
     switch (c) {
-      case ',':
-      case '+':
-      case '-':
-      case '*':
-      case '/':
-      case '\\':
-      case ULAS_TOK_COMMENT:
-        if (WELD_TOKISTERM) {
-          goto tokdone;
-        }
-        // single char tokens
-        dst->buf[write++] = line[i++];
+    case ',':
+    case '+':
+    case '-':
+    case '*':
+    case '/':
+    case '\\':
+    case ULAS_TOK_COMMENT:
+      if (WELD_TOKISTERM) {
         goto tokdone;
-      case '$':
-        if (WELD_TOKISTERM) {
-          goto tokdone;
-        }
-        // special var for preprocessor
-        // make sure we have enough space in buffer
-        ulas_strensr(dst, write + 2);
-        // escape char tokens
-        dst->buf[write++] = line[i++];
-        dst->buf[write++] = line[i++];
+      }
+      // single char tokens
+      dst->buf[write++] = line[i++];
+      goto tokdone;
+    case '$':
+      if (WELD_TOKISTERM) {
         goto tokdone;
-      default:
-        if (isspace(line[i])) {
-          goto tokdone;
-        }
-        dst->buf[write] = line[i];
-        write++;
-        break;
+      }
+      // special var for preprocessor
+      // make sure we have enough space in buffer
+      ulas_strensr(dst, write + 2);
+      // escape char tokens
+      dst->buf[write++] = line[i++];
+      dst->buf[write++] = line[i++];
+      goto tokdone;
+    default:
+      if (isspace(line[i])) {
+        goto tokdone;
+      }
+      dst->buf[write] = line[i];
+      write++;
+      break;
     }
     i++;
   }
@@ -220,28 +220,28 @@ int ulas_tokuntil(struct ulas_str *dst, char c, const char **out_line,
 
 int ulas_unescape(char c, int *rc) {
   switch (c) {
-    case '\'':
-    case '\\':
-    case '"':
-      return c;
-    case 'n':
-      return '\n';
-    case 'a':
-      return '\a';
-    case 'b':
-      return '\b';
-    case 'f':
-      return '\f';
-    case 'r':
-      return '\r';
-    case '?':
-      return '\?';
-    case '0':
-      return '\0';
-    default:
-      ULASERR("Unexpected esxcape sequence: \\%c\n", c);
-      *rc = -1;
-      break;
+  case '\'':
+  case '\\':
+  case '"':
+    return c;
+  case 'n':
+    return '\n';
+  case 'a':
+    return '\a';
+  case 'b':
+    return '\b';
+  case 'f':
+    return '\f';
+  case 'r':
+    return '\r';
+  case '?':
+    return '\?';
+  case '0':
+    return '\0';
+  default:
+    ULASERR("Unexpected esxcape sequence: \\%c\n", c);
+    *rc = -1;
+    break;
   }
 
   return '\0';
@@ -260,97 +260,97 @@ struct ulas_tok ulas_totok(char *buf, unsigned long n, int *rc) {
   buf++;
 
   switch (first) {
-    case '+':
-    case '-':
-    case '*':
-    case '/':
-    case '!':
-    case '~':
-    case '|':
-    case '&':
-    case '%':
-    case '(':
-    case ')':
-    case '[':
-    case ']':
-    case ',':
-    case ';':
-      // single char tokens
-      tok.type = first;
+  case '+':
+  case '-':
+  case '*':
+  case '/':
+  case '!':
+  case '~':
+  case '|':
+  case '&':
+  case '%':
+  case '(':
+  case ')':
+  case '[':
+  case ']':
+  case ',':
+  case ';':
+    // single char tokens
+    tok.type = first;
+    goto end;
+  case '"':
+    // string
+    tok.type = ULAS_TOKLITERAL;
+    tok.lit.type = ULAS_STR;
+
+    // FIXME: this likely mallocs a few extra bytes
+    // but honestly its probably fine
+    tok.lit.val.strv = malloc(n * sizeof(char) + 1);
+    memset(tok.lit.val.strv, 0, n);
+
+    long i = 0;
+    while (*buf && *buf != '\"') {
+      if (*buf == '\\') {
+        buf++;
+        tok.lit.val.strv[i] = ulas_unescape(*buf, rc);
+      } else {
+        tok.lit.val.strv[i] = *buf;
+      }
+      i++;
+      buf++;
+    }
+    tok.lit.val.strv[i] = '\0';
+
+    if (*buf != '\"') {
+      *rc = -1;
+      ULASERR("Unterminated string sequence\n");
       goto end;
-    case '"':
-      // string
+    }
+    buf++;
+    break;
+  default:
+    if (isdigit(first)) {
+      // integer
       tok.type = ULAS_TOKLITERAL;
-      tok.lit.type = ULAS_STR;
+      tok.lit.type = ULAS_INT;
 
-      // FIXME: this likely mallocs a few extra bytes
-      // but honestly its probably fine
-      tok.lit.val.strv = malloc(n * sizeof(char) + 1);
-      memset(tok.lit.val.strv, 0, n);
-
-      long i = 0;
-      while (*buf && *buf != '\"') {
-        if (*buf == '\\') {
-          buf++;
-          tok.lit.val.strv[i] = ulas_unescape(*buf, rc);
-        } else {
-          tok.lit.val.strv[i] = *buf;
-        }
-        i++;
+      // 0b prefix is not supported in strtol... so we implement it by hand
+      if (*buf == 'b') {
         buf++;
+        tok.lit.val.intv = (int) strtol(buf, &buf, 2);
+      } else {
+        tok.lit.val.intv = (int) strtol(buf - 1, &buf, 0);
       }
-      tok.lit.val.strv[i] = '\0';
-
-      if (*buf != '\"') {
-        *rc = -1;
-        ULASERR("Unterminated string sequence\n");
-        goto end;
-      }
-      buf++;
-      break;
-    default:
-      if (isdigit(first)) {
-        // integer
-        tok.type = ULAS_TOKLITERAL;
-        tok.lit.type = ULAS_INT;
-
-        // 0b prefix is not supported in strtol... so we implement it by hand
-        if (*buf == 'b') {
-          buf++;
-          tok.lit.val.intv = (int) strtol(buf, &buf, 2);
-        } else {
-          tok.lit.val.intv = (int) strtol(buf - 1, &buf, 0);
-        }
-      } else if (first == '\'') {
-        tok.type = ULAS_TOKLITERAL;
-        tok.lit.type = ULAS_INT;
-        if (*buf == '\\') {
-          buf++;
-          tok.lit.val.intv = ulas_unescape(*buf, rc);
-        } else {
-          tok.lit.val.intv = (int) *buf;
-        }
-        buf++;
-        if (*buf != '\'') {
-          *rc = -1;
-          ULASERR("Unterminated character sequence\n");
-          goto end;
-        }
+    } else if (first == '\'') {
+      tok.type = ULAS_TOKLITERAL;
+      tok.lit.type = ULAS_INT;
+      if (*buf == '\\') {
         buf++;
-        break;
-      } else if (ulas_isname(buf, n)) {
-        // literal. we can resolve it now
-        // because literals need to be able to be resolved
-        // for every line, unless they are a label!
-        // TODO: read and unescape striing between " and "
-        tok.type = ULAS_TOKSYMBOL;
-        tok.lit.type = ULAS_STR;
+        tok.lit.val.intv = ulas_unescape(*buf, rc);
       } else {
-        ULASERR("Unexpected token: %s\n", buf);
+        tok.lit.val.intv = (int) *buf;
+      }
+      buf++;
+      if (*buf != '\'') {
         *rc = -1;
+        ULASERR("Unterminated character sequence\n");
         goto end;
       }
+      buf++;
       break;
+    } else if (ulas_isname(buf, n)) {
+      // literal. we can resolve it now
+      // because literals need to be able to be resolved
+      // for every line, unless they are a label!
+      // TODO: read and unescape striing between " and "
+      tok.type = ULAS_TOKSYMBOL;
+      tok.lit.type = ULAS_STR;
+    } else {
+      ULASERR("Unexpected token: %s\n", buf);
+      *rc = -1;
+      goto end;
+    }
+    break;
   }
 
 end:
@@ -453,130 +453,128 @@ char *ulas_preprocexpand(struct ulas_preproc *pp, const char *raw_line,
     if (def) {
       // if so... expand now and leave
       switch (def->type) {
-        case ULAS_PPDEF:{
-            unsigned long val_len = strlen(def->value);
-            int wsi = ulas_preproclws(pp, praw_line - read, *n);
-            if (val_len) {
-              // make sure to include leading white space
-              // adjust total length
-              *n -= strlen(pp->tok.buf);
-              *n += val_len;
-              ulas_strensr(&pp->line, (*n) + 1 + wsi);
-
-              // only remove the first white space char if the lenght of value
-              // is greater than 1, otherwise just leave it be...
-              if (val_len > 1) {
-                strncat(pp->line.buf, def->value + 1, val_len - 1);
-              } else {
-                strncat(pp->line.buf, def->value, val_len);
-              }
-            }
-            break;
+      case ULAS_PPDEF:{
+        unsigned long val_len = strlen(def->value);
+        int wsi = ulas_preproclws(pp, praw_line - read, *n);
+        if (val_len) {
+          // make sure to include leading white space
+          // adjust total length
+          *n -= strlen(pp->tok.buf);
+          *n += val_len;
+          ulas_strensr(&pp->line, (*n) + 1 + wsi);
+
+          // only remove the first white space char if the lenght of value
+          // is greater than 1, otherwise just leave it be...
+          if (val_len > 1) {
+            strncat(pp->line.buf, def->value + 1, val_len - 1);
+          } else {
+            strncat(pp->line.buf, def->value, val_len);
           }
-        case ULAS_PPMACRO:{
-            // TODO: i am sure we can optimize the resize of line buffers here...
-
-            // get 9 comma separated values.
-            // $1-$9 will reference the respective arg
-            // $0 will reference the entire line after the macro name
-            // there can be more than 9 args, but anything after the 9th arg can
-            // only be accessed via $0
-            const char *line = praw_line;
-            unsigned long linelen = strlen(praw_line);
-            // clear all params from previous attempt
-            for (unsigned long i = 0; i < ULAS_MACROPARAMMAX; i++) {
-              pp->macroparam[i].buf[0] = '\0';
-            }
+        }
+        break;
+      }
+      case ULAS_PPMACRO:{
+        // TODO: i am sure we can optimize the resize of line buffers here...
+
+        // get 9 comma separated values.
+        // $1-$9 will reference the respective arg
+        // $0 will reference the entire line after the macro name
+        // there can be more than 9 args, but anything after the 9th arg can
+        // only be accessed via $0
+        const char *line = praw_line;
+        unsigned long linelen = strlen(praw_line);
+        // clear all params from previous attempt
+        for (unsigned long i = 0; i < ULAS_MACROPARAMMAX; i++) {
+          pp->macroparam[i].buf[0] = '\0';
+        }
+
+        // loop until 9 args are found or the line ends
+        int paramc = 0;
+        while (paramc < ULAS_MACROPARAMMAX &&
+               ulas_tokuntil(&pp->macroparam[paramc], ',', &praw_line, *n) >
+               0) {
+          // trim new lines from the end of macro params
+          ulas_trimend('\n', pp->macroparam[paramc].buf,
+                       strlen(pp->macroparam[paramc].buf));
+          paramc++;
+        }
+        ulas_strensr(&pp->line, strlen(def->value) + 2);
+
+        const char *macro_argname[ULAS_MACROPARAMMAX] = {
+          "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9"
+        };
+
+        const char *val = def->value;
+        unsigned long vallen = strlen(def->value);
+        unsigned long valread = 0;
+
+        // the pointer to tocat will be the variable's value if any
+        // exists
+        const char *tocat = NULL;
+        unsigned long tocatlen = 0;
+
+        // now tokenize the macro's value and look for $0-$9
+        // and replace those instances
+        // eveyrthing else will just be copied as is
+        while ((valread = ulas_tok(&pp->macrobuf, &val, vallen)) > 0) {
+          tocat = NULL;
+          char numbuf[128];
+
+          // decide what tocat should be
+          for (unsigned long mi = 0; mi < ULAS_MACROPARAMMAX; mi++) {
+            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,
+                                   pp->macroparam[mi].maxlen) + 1);
+
+              tocat = pp->macroparam[mi].buf;
+              tocatlen = pp->macroparam[mi].maxlen;
 
-            // loop until 9 args are found or the line ends
-            int paramc = 0;
-            while (paramc < ULAS_MACROPARAMMAX &&
-                   ulas_tokuntil(&pp->macroparam[paramc], ',', &praw_line, *n) >
-                   0) {
-              // trim new lines from the end of macro params
-              ulas_trimend('\n', pp->macroparam[paramc].buf,
-                           strlen(pp->macroparam[paramc].buf));
-              paramc++;
+              break;
             }
-            ulas_strensr(&pp->line, strlen(def->value) + 2);
-
-            const char *macro_argname[ULAS_MACROPARAMMAX] = {
-              "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9"
-            };
-
-            const char *val = def->value;
-            unsigned long vallen = strlen(def->value);
-            unsigned long valread = 0;
-
-            // the pointer to tocat will be the variable's value if any
-            // exists
-            const char *tocat = NULL;
-            unsigned long tocatlen = 0;
-
-            // now tokenize the macro's value and look for $0-$9
-            // and replace those instances
-            // eveyrthing else will just be copied as is
-            while ((valread = ulas_tok(&pp->macrobuf, &val, vallen)) > 0) {
-              tocat = NULL;
-              char numbuf[128];
-
-              // decide what tocat should be
-              for (unsigned long mi = 0; mi < ULAS_MACROPARAMMAX; mi++) {
-                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,
-                                       pp->macroparam[mi].maxlen) + 1);
-
-                  tocat = pp->macroparam[mi].buf;
-                  tocatlen = pp->macroparam[mi].maxlen;
-
-                  break;
-                }
-              }
-
-              if (linelen &&
-                  strncmp("$0", pp->macrobuf.buf, pp->macrobuf.maxlen) == 0) {
-                ulas_strensr(&pp->line,
-                             strnlen(pp->line.buf,
-                                     pp->line.maxlen) + linelen + 1);
-
-                if (linelen > 1) {
-                  // this skips the separating token which is usually a space
-                  // all further spaces are included though!
-                  tocat = line + 1;
-                  tocatlen = linelen - 1;
-                } else {
-                  // do not do this if the line is literally empty!
-                  tocat = line;
-                  tocatlen = linelen;
-                }
-              } else if (linelen && strncmp("$$", pp->macrobuf.buf,
-                                            pp->macrobuf.maxlen) == 0) {
-                sprintf(numbuf, "%x", ulas_icntr());
-                ulas_strensr(&pp->line,
-                             strnlen(pp->line.buf, pp->line.maxlen) + 128 + 1);
-                tocat = numbuf;
-                tocatlen = 128;
-              }
-
-              if (!tocat) {
-                ulas_strensr(&pp->line, valread + 1);
-                strncat(pp->line.buf, val - valread, valread);
-              } 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) +
-                             tocatlen + wsi + 1);
-                strncat(pp->line.buf, tocat, tocatlen);
-              }
+          }
+
+          if (linelen &&
+              strncmp("$0", pp->macrobuf.buf, pp->macrobuf.maxlen) == 0) {
+            ulas_strensr(&pp->line,
+                         strnlen(pp->line.buf, pp->line.maxlen) + linelen + 1);
+
+            if (linelen > 1) {
+              // this skips the separating token which is usually a space
+              // all further spaces are included though!
+              tocat = line + 1;
+              tocatlen = linelen - 1;
+            } else {
+              // do not do this if the line is literally empty!
+              tocat = line;
+              tocatlen = linelen;
             }
-            goto end;
+          } else if (linelen && strncmp("$$", pp->macrobuf.buf,
+                                        pp->macrobuf.maxlen) == 0) {
+            sprintf(numbuf, "%x", ulas_icntr());
+            ulas_strensr(&pp->line,
+                         strnlen(pp->line.buf, pp->line.maxlen) + 128 + 1);
+            tocat = numbuf;
+            tocatlen = 128;
           }
+
+          if (!tocat) {
+            ulas_strensr(&pp->line, valread + 1);
+            strncat(pp->line.buf, val - valread, valread);
+          } 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) +
+                         tocatlen + wsi + 1);
+            strncat(pp->line.buf, tocat, tocatlen);
+          }
+        }
+        goto end;
+      }
       }
 
     } else {
@@ -648,135 +646,133 @@ found:
   if (found_dir != ULAS_PPDIR_NONE) {
     ulas_trimend('\n', line, strlen(line));
     switch (found_dir) {
-      case ULAS_PPDIR_DEF:{
-          // next token is a name
-          // and then the entire remainder of the line is a value
-          if (ulas_tok(&pp->tok, &pline, n) == 0) {
-            ULASERR("Expected name for #define\n");
-            return -1;
-          }
-
-          if (!ulas_isname(pp->tok.buf, strlen(pp->tok.buf))) {
-            ULASERR("'%s' is not a valid #define name!\n", pp->tok.buf);
-            return -1;
-          }
-
-          struct ulas_ppdef def =
-            { ULAS_PPDEF, strdup(pp->tok.buf), strdup(pline),
-            0
-          };
-          ulas_preprocdef(pp, def);
-          // define short-circuits the rest of the logic
-          // because it just takes the entire rest of the line as a value!
-          goto dirdone;
-        }
-      case ULAS_PPDIR_MACRO:{
-          // get a name, ensure no more tokens come after
-          // and then consume lines until ENDMACRO is seen
-          if (ulas_tok(&pp->tok, &pline, n) == 0) {
-            ULASERR("Expected name for #macro\n");
-            return -1;
-          }
-
-          if (!ulas_isname(pp->tok.buf, strlen(pp->tok.buf))) {
-            ULASERR("'%s' is not a valid #macro name!\n", pp->tok.buf);
-            return -1;
-          }
-          char *name = strdup(pp->tok.buf);
-
-          struct ulas_str val = ulas_str(32);
-          memset(val.buf, 0, 32);
-
-          char buf[ULAS_LINEMAX];
-          memset(buf, 0, ULAS_LINEMAX);
-
-          // consume lines until #endmacro is read
-          // if reaching end of input without #endmacro we have an unterminated
-          // macro. pass NULL as dst to consume lines that are being read instead of
-          // echoing them back
-          int rc = 0;
-          while ((rc = ulas_preprocnext(pp, NULL, src, buf, ULAS_LINEMAX)) > 0) {
-            if (rc == ULAS_PPDIR_ENDMACRO) {
-              // we need to clear the line buffer to now echo back
-              // the #endmacro directive
-              pp->line.buf[0] = '\0';
-              break;
-            }
+    case ULAS_PPDIR_DEF:{
+      // next token is a name
+      // and then the entire remainder of the line is a value
+      if (ulas_tok(&pp->tok, &pline, n) == 0) {
+        ULASERR("Expected name for #define\n");
+        return -1;
+      }
 
-            unsigned long len = strnlen(pp->line.buf, pp->line.maxlen);
-            ulas_strensr(&val, strnlen(val.buf, val.maxlen) + len + 1);
-            strncat(val.buf, pp->line.buf, val.maxlen);
-          }
+      if (!ulas_isname(pp->tok.buf, strlen(pp->tok.buf))) {
+        ULASERR("'%s' is not a valid #define name!\n", pp->tok.buf);
+        return -1;
+      }
 
-          if (rc != ULAS_PPDIR_ENDMACRO) {
-            ULASERR("Unterminated macro directive\n");
-            ulas_strfree(&val);
-            free(name);
-            return -1;
-          }
-          // we leak the str's buffer into the def now
-          // this is ok because we call free for it later anyway
-          struct ulas_ppdef def = { ULAS_PPMACRO, name, val.buf, 0 };
-          ulas_preprocdef(pp, def);
+      struct ulas_ppdef def = { ULAS_PPDEF, strdup(pp->tok.buf), strdup(pline),
+        0
+      };
+      ulas_preprocdef(pp, def);
+      // define short-circuits the rest of the logic
+      // because it just takes the entire rest of the line as a value!
+      goto dirdone;
+    }
+    case ULAS_PPDIR_MACRO:{
+      // get a name, ensure no more tokens come after
+      // and then consume lines until ENDMACRO is seen
+      if (ulas_tok(&pp->tok, &pline, n) == 0) {
+        ULASERR("Expected name for #macro\n");
+        return -1;
+      }
 
-          goto dirdone;
+      if (!ulas_isname(pp->tok.buf, strlen(pp->tok.buf))) {
+        ULASERR("'%s' is not a valid #macro name!\n", pp->tok.buf);
+        return -1;
+      }
+      char *name = strdup(pp->tok.buf);
+
+      struct ulas_str val = ulas_str(32);
+      memset(val.buf, 0, 32);
+
+      char buf[ULAS_LINEMAX];
+      memset(buf, 0, ULAS_LINEMAX);
+
+      // consume lines until #endmacro is read
+      // if reaching end of input without #endmacro we have an unterminated
+      // macro. pass NULL as dst to consume lines that are being read instead of
+      // echoing them back
+      int rc = 0;
+      while ((rc = ulas_preprocnext(pp, NULL, src, buf, ULAS_LINEMAX)) > 0) {
+        if (rc == ULAS_PPDIR_ENDMACRO) {
+          // we need to clear the line buffer to now echo back
+          // the #endmacro directive
+          pp->line.buf[0] = '\0';
+          break;
         }
-      case ULAS_PPDIR_ENDIF:
-      case ULAS_PPDIR_ENDMACRO:
-        break;
-      case ULAS_PPDIR_IFDEF:
-      case ULAS_PPDIR_IFNDEF:{
-          // get the name
-          // get a name, ensure no more tokens come after
-          // and then consume lines until ENDMACRO is seen
-          if (ulas_tok(&pp->tok, &pline, n) == 0) {
-            ULASERR("Expected name for #if(n)def\n");
-            return -1;
-          }
-          struct ulas_ppdef *def =
-            ulas_preprocgetdef(pp, pp->tok.buf, pp->tok.maxlen);
 
-          char buf[ULAS_LINEMAX];
-          memset(buf, 0, ULAS_LINEMAX);
+        unsigned long len = strnlen(pp->line.buf, pp->line.maxlen);
+        ulas_strensr(&val, strnlen(val.buf, val.maxlen) + len + 1);
+        strncat(val.buf, pp->line.buf, val.maxlen);
+      }
 
-          FILE *defdst = NULL;
-          if ((def && found_dir == ULAS_PPDIR_IFDEF) ||
-              (!def && found_dir == ULAS_PPDIR_IFNDEF)) {
-            defdst = dst;
-          }
-          // loop until end of line or endif
-          int rc = 0;
-          while ((rc =
-                  ulas_preprocnext(pp, defdst, src, buf, ULAS_LINEMAX)) > 0) {
-            if (rc == ULAS_PPDIR_ENDIF) {
-              // we need to clear the line buffer to now echo back
-              // the #endif directive
-              pp->line.buf[0] = '\0';
-              break;
-            }
-          }
+      if (rc != ULAS_PPDIR_ENDMACRO) {
+        ULASERR("Unterminated macro directive\n");
+        ulas_strfree(&val);
+        free(name);
+        return -1;
+      }
+      // we leak the str's buffer into the def now
+      // this is ok because we call free for it later anyway
+      struct ulas_ppdef def = { ULAS_PPMACRO, name, val.buf, 0 };
+      ulas_preprocdef(pp, def);
 
-          if (rc != ULAS_PPDIR_ENDIF) {
-            ULASERR("Unterminated if(n)def directive\n");
-            return -1;
-          }
-          goto dirdone;
-        }
-      case ULAS_PPDIR_UNDEF:{
-          if (ulas_tok(&pp->tok, &pline, n) == 0) {
-            ULASERR("Expected name for #undef\n");
-            return -1;
-          }
-          struct ulas_ppdef *def = NULL;
-          while ((def = ulas_preprocgetdef(pp, pp->tok.buf, pp->tok.maxlen))) {
-            def->undef = 1;
-          }
+      goto dirdone;
+    }
+    case ULAS_PPDIR_ENDIF:
+    case ULAS_PPDIR_ENDMACRO:
+      break;
+    case ULAS_PPDIR_IFDEF:
+    case ULAS_PPDIR_IFNDEF:{
+      // get the name
+      // get a name, ensure no more tokens come after
+      // and then consume lines until ENDMACRO is seen
+      if (ulas_tok(&pp->tok, &pline, n) == 0) {
+        ULASERR("Expected name for #if(n)def\n");
+        return -1;
+      }
+      struct ulas_ppdef *def =
+        ulas_preprocgetdef(pp, pp->tok.buf, pp->tok.maxlen);
 
+      char buf[ULAS_LINEMAX];
+      memset(buf, 0, ULAS_LINEMAX);
+
+      FILE *defdst = NULL;
+      if ((def && found_dir == ULAS_PPDIR_IFDEF) ||
+          (!def && found_dir == ULAS_PPDIR_IFNDEF)) {
+        defdst = dst;
+      }
+      // loop until end of line or endif
+      int rc = 0;
+      while ((rc = ulas_preprocnext(pp, defdst, src, buf, ULAS_LINEMAX)) > 0) {
+        if (rc == ULAS_PPDIR_ENDIF) {
+          // we need to clear the line buffer to now echo back
+          // the #endif directive
+          pp->line.buf[0] = '\0';
           break;
         }
-      default:
-        // this should not happen!
-        break;
+      }
+
+      if (rc != ULAS_PPDIR_ENDIF) {
+        ULASERR("Unterminated if(n)def directive\n");
+        return -1;
+      }
+      goto dirdone;
+    }
+    case ULAS_PPDIR_UNDEF:{
+      if (ulas_tok(&pp->tok, &pline, n) == 0) {
+        ULASERR("Expected name for #undef\n");
+        return -1;
+      }
+      struct ulas_ppdef *def = NULL;
+      while ((def = ulas_preprocgetdef(pp, pp->tok.buf, pp->tok.maxlen))) {
+        def->undef = 1;
+      }
+
+      break;
+    }
+    default:
+      // this should not happen!
+      break;
     }
 
   dirdone:
@@ -979,18 +975,18 @@ int ulas_asmline(FILE *dst, FILE *src, const char *line, unsigned long n) {
     }
 
     switch (dir) {
-      case ULAS_ASMDIR_NONE:
-      case ULAS_ASMDIR_ORG:
-        ulas.address = ulas_intexpr(&line, strnlen(start, n), &rc);
-        break;
-      case ULAS_ASMDIR_SET:
-      case ULAS_ASMDIR_BYTE:
-      case ULAS_ASMDIR_STR:
-      case ULAS_ASMDIR_FILL:
-      case ULAS_ASMDIR_PAD:
-      case ULAS_ASMDIR_INCBIN:
-        ULASPANIC("asmdir not implemented\n");
-        break;
+    case ULAS_ASMDIR_NONE:
+    case ULAS_ASMDIR_ORG:
+      ulas.address = ulas_intexpr(&line, strnlen(start, n), &rc);
+      break;
+    case ULAS_ASMDIR_SET:
+    case ULAS_ASMDIR_BYTE:
+    case ULAS_ASMDIR_STR:
+    case ULAS_ASMDIR_FILL:
+    case ULAS_ASMDIR_PAD:
+    case ULAS_ASMDIR_INCBIN:
+      ULASPANIC("asmdir not implemented\n");
+      break;
     }
 
   } else {