ref: 1e4ace8974d75367138de5e0c10769e0ee791dad
dir: /src/asm/macro.c/
#include <assert.h> #include <errno.h> #include <inttypes.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "asm/macro.h" #include "asm/warning.h" #define MAXMACROARGS 99999 /* * Your average macro invocation does not go past the tens, but some go further * This ensures that sane and slightly insane invocations suffer no penalties, * and the rest is insane and thus will assume responsibility. * Additionally, ~300 bytes (on x64) of memory per level of nesting has been * deemed reasonable. (Halve that on x86.) */ #define INITIAL_ARG_SIZE 32 struct MacroArgs { unsigned int nbArgs; unsigned int shift; unsigned int capacity; char *args[]; }; #define SIZEOF_ARGS(nbArgs) (sizeof(struct MacroArgs) + \ sizeof(((struct MacroArgs){0}).args[0]) * (nbArgs)) static struct MacroArgs *macroArgs = NULL; static uint32_t uniqueID = 0; static uint32_t maxUniqueID = 0; /* * The initialization is somewhat harmful, since it is never used, but it * guarantees the size of the buffer will be correct. I was unable to find a * better solution, but if you have one, please feel free! */ static char uniqueIDBuf[] = "_u4294967295"; // UINT32_MAX static char *uniqueIDPtr = NULL; struct MacroArgs *macro_GetCurrentArgs(void) { return macroArgs; } struct MacroArgs *macro_NewArgs(void) { struct MacroArgs *args = malloc(SIZEOF_ARGS(INITIAL_ARG_SIZE)); if (!args) fatalerror("Unable to register macro arguments: %s\n", strerror(errno)); args->nbArgs = 0; args->shift = 0; args->capacity = INITIAL_ARG_SIZE; return args; } void macro_AppendArg(struct MacroArgs **argPtr, char *s) { #define macArgs (*argPtr) if (s[0] == '\0') warning(WARNING_EMPTY_MACRO_ARG, "Empty macro argument\n"); if (macArgs->nbArgs == MAXMACROARGS) error("A maximum of " EXPAND_AND_STR(MAXMACROARGS) " arguments is allowed\n"); if (macArgs->nbArgs >= macArgs->capacity) { macArgs->capacity *= 2; /* Check that overflow didn't roll us back */ if (macArgs->capacity <= macArgs->nbArgs) fatalerror("Failed to add new macro argument: capacity overflow\n"); macArgs = realloc(macArgs, SIZEOF_ARGS(macArgs->capacity)); if (!macArgs) fatalerror("Error adding new macro argument: %s\n", strerror(errno)); } macArgs->args[macArgs->nbArgs++] = s; #undef macArgs } void macro_UseNewArgs(struct MacroArgs *args) { macroArgs = args; } void macro_FreeArgs(struct MacroArgs *args) { for (uint32_t i = 0; i < macroArgs->nbArgs; i++) free(args->args[i]); } char const *macro_GetArg(uint32_t i) { if (!macroArgs) return NULL; uint32_t realIndex = i + macroArgs->shift - 1; return realIndex >= macroArgs->nbArgs ? NULL : macroArgs->args[realIndex]; } char *macro_GetAllArgs(void) { if (!macroArgs) return NULL; if (macroArgs->shift >= macroArgs->nbArgs) return ""; size_t len = 0; for (uint32_t i = macroArgs->shift; i < macroArgs->nbArgs; i++) len += strlen(macroArgs->args[i]) + 1; /* 1 for comma */ char *str = malloc(len + 1); /* 1 for '\0' */ char *ptr = str; if (!str) fatalerror("Failed to allocate memory for expanding '\\#': %s\n", strerror(errno)); for (uint32_t i = macroArgs->shift; i < macroArgs->nbArgs; i++) { size_t n = strlen(macroArgs->args[i]); memcpy(ptr, macroArgs->args[i], n); ptr += n; /* Commas go between args and after a last empty arg */ if (i < macroArgs->nbArgs - 1 || n == 0) *ptr++ = ','; /* no space after comma */ } *ptr = '\0'; return str; } uint32_t macro_GetUniqueID(void) { return uniqueID; } char const *macro_GetUniqueIDStr(void) { return uniqueIDPtr; } void macro_SetUniqueID(uint32_t id) { uniqueID = id; if (id == 0) { uniqueIDPtr = NULL; } else { if (uniqueID > maxUniqueID) maxUniqueID = uniqueID; /* The buffer is guaranteed to be the correct size */ /* This is a valid label fragment, but not a valid numeric */ sprintf(uniqueIDBuf, "_u%" PRIu32, id); uniqueIDPtr = uniqueIDBuf; } } uint32_t macro_UseNewUniqueID(void) { macro_SetUniqueID(++maxUniqueID); return maxUniqueID; } void macro_ShiftCurrentArgs(int32_t count) { if (!macroArgs) { error("Cannot shift macro arguments outside of a macro\n"); } else if (count > 0 && ((uint32_t)count > macroArgs->nbArgs || macroArgs->shift > macroArgs->nbArgs - count)) { warning(WARNING_MACRO_SHIFT, "Cannot shift macro arguments past their end\n"); macroArgs->shift = macroArgs->nbArgs; } else if (count < 0 && macroArgs->shift < (uint32_t)-count) { warning(WARNING_MACRO_SHIFT, "Cannot shift macro arguments past their beginning\n"); macroArgs->shift = 0; } else { macroArgs->shift += count; } } uint32_t macro_NbArgs(void) { return macroArgs->nbArgs - macroArgs->shift; }