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 }