kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

utils.c (4992B)


      1 /*
      2  * Utility functions: arena-backed allocation, diagnostics that longjmp instead
      3  * of exit(), and output routed through the KitWriter sinks. Ported from
      4  * pdpmake utils.c. Part of the src/api/make.c amalgamation.
      5  */
      6 #include "make.h"
      7 
      8 /* ---- allocation (arena; OOM longjmps via mk_error) ----------------------- */
      9 
     10 static void* mk_alloc(MakeCtx* mc, size_t n) {
     11   void* p = arena_alloc(&mc->arena, n ? n : 1, 16);
     12   if (!p) mk_error(mc, "out of memory");
     13   return p;
     14 }
     15 
     16 static void* mk_realloc(MakeCtx* mc, void* p, size_t oldn, size_t newn) {
     17   void* q = mk_alloc(mc, newn);
     18   if (p && oldn) memcpy(q, p, oldn < newn ? oldn : newn);
     19   return q;
     20 }
     21 
     22 static char* mk_strdup(MakeCtx* mc, const char* s) {
     23   size_t len;
     24   char* t;
     25   if (s == NULL) return NULL;
     26   len = strlen(s);
     27   t = mk_alloc(mc, len + 1);
     28   memcpy(t, s, len + 1);
     29   return t;
     30 }
     31 
     32 static char* mk_strndup(MakeCtx* mc, const char* s, size_t n) {
     33   size_t len = 0;
     34   char* t;
     35   while (len < n && s[len] != '\0') ++len;
     36   t = mk_alloc(mc, len + 1);
     37   memcpy(t, s, len);
     38   t[len] = '\0';
     39   return t;
     40 }
     41 
     42 static char* mk_concat3(MakeCtx* mc, const char* s1, const char* s2,
     43                         const char* s3) {
     44   const size_t len1 = strlen(s1);
     45   const size_t len2 = strlen(s2);
     46   const size_t len3 = strlen(s3);
     47   char* t = mk_alloc(mc, len1 + len2 + len3 + 1);
     48   char* s = t;
     49   s = (char*)memcpy(s, s1, len1) + len1;
     50   s = (char*)memcpy(s, s2, len2) + len2;
     51   s = (char*)memcpy(s, s3, len3) + len3;
     52   *s = '\0';
     53   return t;
     54 }
     55 
     56 /*
     57  * Append a word to a space-separated string of words. The first call should
     58  * pass NULL for str. Unlike pdpmake there is no free() -- the arena owns the
     59  * old string, which is left to be reclaimed wholesale.
     60  */
     61 static char* mk_appendword(MakeCtx* mc, const char* str, const char* word) {
     62   return str ? mk_concat3(mc, str, " ", word) : mk_strdup(mc, word);
     63 }
     64 
     65 /* ---- error handling: longjmp back to kit_make_run ------------------------ */
     66 
     67 static void mk_exit(MakeCtx* mc, int code) {
     68   mc->exit_code = code;
     69   longjmp(mc->jmpbuf, 1);
     70 }
     71 
     72 /*
     73  * Format "myname: (makefile:line): message\n" to a writer. Mirrors pdpmake's
     74  * vwarning but targets a KitWriter instead of a stdio stream.
     75  */
     76 static void mk_vwarn(MakeCtx* mc, KitWriter* w, const char* fmt, va_list ap) {
     77   char buf[2048];
     78   size_t cap = sizeof buf;
     79   size_t n = 0;
     80   int r;
     81   const char* m = NULL;
     82   int d = 0;
     83 
     84   if (mc->curr_cmd) {
     85     m = mc->curr_cmd->c_makefile;
     86     d = mc->curr_cmd->c_dispno;
     87   } else if (mc->makefile) {
     88     m = mc->makefile;
     89     d = mc->dispno;
     90   }
     91 
     92   r = snprintf(buf + n, cap - n, "%s: ", mc->myname ? mc->myname : "make");
     93   if (r > 0) n += (size_t)r < cap - n ? (size_t)r : cap - n - 1;
     94   if (m) {
     95     r = snprintf(buf + n, cap - n, "(%s:%d): ", m, d);
     96     if (r > 0) n += (size_t)r < cap - n ? (size_t)r : cap - n - 1;
     97   }
     98   r = vsnprintf(buf + n, cap - n, fmt, ap);
     99   if (r > 0) n += (size_t)r < cap - n ? (size_t)r : cap - n - 1;
    100   if (n >= cap) n = cap - 1;
    101   buf[n] = '\n';
    102   n++;
    103   if (w) kit_writer_write(w, buf, n);
    104 }
    105 
    106 static void mk_error(MakeCtx* mc, const char* fmt, ...) {
    107   va_list ap;
    108   va_start(ap, fmt);
    109   mk_vwarn(mc, mc->err, fmt, ap);
    110   va_end(ap);
    111   mk_exit(mc, 2);
    112 }
    113 
    114 static void mk_warning(MakeCtx* mc, const char* fmt, ...) {
    115   va_list ap;
    116   va_start(ap, fmt);
    117   mk_vwarn(mc, mc->out, fmt, ap); /* pdpmake sends warnings to stdout */
    118   va_end(ap);
    119 }
    120 
    121 static void mk_diagnostic(MakeCtx* mc, const char* fmt, ...) {
    122   va_list ap;
    123   va_start(ap, fmt);
    124   mk_vwarn(mc, mc->err, fmt, ap);
    125   va_end(ap);
    126 }
    127 
    128 static void mk_error_unexpected(MakeCtx* mc, const char* s) {
    129   mk_error(mc, "unexpected %s", s);
    130 }
    131 
    132 static void mk_error_in_inference_rule(MakeCtx* mc, const char* s) {
    133   mk_error(mc, "%s in inference rule", s);
    134 }
    135 
    136 static void mk_error_not_allowed(MakeCtx* mc, const char* s, const char* t) {
    137   mk_error(mc, "%s not allowed for %s", s, t);
    138 }
    139 
    140 /* ---- output through the KitWriter sinks ---------------------------------- */
    141 
    142 static void mk_out_bytes(MakeCtx* mc, const char* p, size_t n) {
    143   if (mc->out && n) kit_writer_write(mc->out, p, n);
    144 }
    145 
    146 static void mk_out(MakeCtx* mc, const char* s) {
    147   if (s) mk_out_bytes(mc, s, strlen(s));
    148 }
    149 
    150 static void mk_outc(MakeCtx* mc, char c) { mk_out_bytes(mc, &c, 1); }
    151 
    152 static void mk_outf(MakeCtx* mc, const char* fmt, ...) {
    153   char buf[2048];
    154   va_list ap;
    155   int r;
    156   va_start(ap, fmt);
    157   r = vsnprintf(buf, sizeof buf, fmt, ap);
    158   va_end(ap);
    159   if (r < 0) return;
    160   mk_out_bytes(mc, buf, (size_t)r < sizeof buf ? (size_t)r : sizeof buf - 1);
    161 }
    162 
    163 /* ---- misc ---------------------------------------------------------------- */
    164 
    165 static unsigned mk_getbucket(const char* name) {
    166   unsigned hashval = 0;
    167   const unsigned char* p = (const unsigned char*)name;
    168   while (*p) hashval ^= (unsigned)(hashval << 5) + (hashval >> 2) + *p++;
    169   return hashval % HTABSIZE;
    170 }
    171 
    172 static const char* mk_path(MakeCtx* mc, const char* name) {
    173   if (!mc->root || !name || name[0] == '/') return name;
    174   return mk_concat3(mc, mc->root, "/", name);
    175 }