"Fossies" - the Fresh Open Source Software Archive

Member "mlr-5.6.2/c/lib/mlrutil.c" (5 Sep 2019, 16196 Bytes) of package /linux/misc/mlr-5.6.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "mlrutil.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 5.5.0_vs_5.6.0.

    1 #include <stdio.h>
    2 #include <string.h>
    3 #include <unistd.h>
    4 #include <ctype.h>
    5 #include <sys/stat.h>
    6 #include "lib/mlrutil.h"
    7 #include "lib/mlr_globals.h"
    8 #include "lib/free_flags.h"
    9 
   10 // ----------------------------------------------------------------
   11 void mlr_internal_coding_error(char* file, int line) {
   12     fprintf(stderr, "%s: internal coding error detected in file %s at line %d.\n",
   13         MLR_GLOBALS.bargv0, file, line);
   14     exit(1);
   15 }
   16 
   17 void mlr_internal_coding_error_if(int v, char* file, int line) {
   18     if (v) {
   19         mlr_internal_coding_error(file, line);
   20     }
   21 }
   22 
   23 void mlr_internal_coding_error_unless(int v, char* file, int line) {
   24     if (!v) {
   25         mlr_internal_coding_error(file, line);
   26     }
   27 }
   28 
   29 // ----------------------------------------------------------------
   30 char* mlr_strmsep(char **pstring, const char *sep, int seplen) {
   31     char* string = *pstring;
   32     if (string == NULL) {
   33         return NULL;
   34     }
   35     char* pnext = strstr(string, sep);
   36     if (pnext == NULL) {
   37         *pstring = NULL;
   38         return string;
   39     } else {
   40         *pnext = 0;
   41         *pstring = pnext + seplen;
   42         return string;
   43     }
   44 }
   45 
   46 // ----------------------------------------------------------------
   47 int mlr_bsearch_double_for_insert(double* array, int size, double value) {
   48     int lo = 0;
   49     int hi = size-1;
   50     int mid = (hi+lo)/2;
   51     int newmid;
   52 
   53     if (size == 0)
   54         return 0;
   55     if (value > array[0])
   56         return 0;
   57     if (value < array[hi])
   58         return size;
   59 
   60     while (lo < hi) {
   61         double a = array[mid];
   62         if (value == a) {
   63             return mid;
   64         }
   65         else if (value > a) {
   66             hi = mid;
   67             newmid = (hi+lo)/2;
   68         }
   69         else {
   70             lo = mid;
   71             newmid = (hi+lo)/2;
   72         }
   73         if (mid == newmid) {
   74             if (value >= array[lo])
   75                 return lo;
   76             else if (value >= array[hi])
   77                 return hi;
   78             else
   79                 return hi+1;
   80         }
   81         mid = newmid;
   82     }
   83 
   84     return lo;
   85 }
   86 
   87 // ----------------------------------------------------------------
   88 void* mlr_malloc_or_die(size_t size) {
   89     void* p = malloc(size);
   90     if (p == NULL) {
   91         fprintf(stderr, "malloc(%llu) failed.\n", (unsigned long long)size);
   92         exit(1);
   93     }
   94 #ifdef MLR_MALLOC_TRACE
   95     fprintf(stderr, "MALLOC size=%llu,p=%p\n", (unsigned long long)size, p);
   96 #endif
   97     return p;
   98 }
   99 
  100 // ----------------------------------------------------------------
  101 void* mlr_realloc_or_die(void *optr, size_t size) {
  102     void* nptr = realloc(optr, size);
  103     if (nptr == NULL) {
  104         fprintf(stderr, "realloc(%llu) failed.\n", (unsigned long long)size);
  105         exit(1);
  106     }
  107 #ifdef MLR_MALLOC_TRACE
  108     fprintf(stderr, "REALLOC size=%llu,p=%p\n", (unsigned long long)size, nptr);
  109 #endif
  110     return nptr;
  111 }
  112 
  113 // ----------------------------------------------------------------
  114 char * mlr_strdup_quoted_or_die(const char *s1) {
  115     int len = strlen(s1);
  116     char* s2 = mlr_malloc_or_die(len+3);
  117     s2[0] = '"';
  118     strcpy(&s2[1], s1);
  119     s2[len+1] = '"';
  120     s2[len+2] = 0;
  121     return s2;
  122 }
  123 
  124 // ----------------------------------------------------------------
  125 // The caller should free the return value from each of these.
  126 
  127 char* mlr_alloc_string_from_double(double value, char* fmt) {
  128     int n = snprintf(NULL, 0, fmt, value);
  129     char* string = mlr_malloc_or_die(n+1);
  130     sprintf(string, fmt, value);
  131     return string;
  132 }
  133 
  134 char* mlr_alloc_string_from_ull(unsigned long long value) {
  135     int n = snprintf(NULL, 0, "%llu", value);
  136     char* string = mlr_malloc_or_die(n+1);
  137     sprintf(string, "%llu", value);
  138     return string;
  139 }
  140 
  141 char* mlr_alloc_string_from_ll(long long value) {
  142     int n = snprintf(NULL, 0, "%lld", value);
  143     char* string = mlr_malloc_or_die(n+1);
  144     sprintf(string, "%lld", value);
  145     return string;
  146 }
  147 
  148 char* mlr_alloc_string_from_ll_and_format(long long value, char* fmt) {
  149     int n = snprintf(NULL, 0, fmt, value);
  150     char* string = mlr_malloc_or_die(n+1);
  151     sprintf(string, fmt, value);
  152     return string;
  153 }
  154 
  155 char* mlr_alloc_string_from_int(int value) {
  156     int n = snprintf(NULL, 0, "%d", value);
  157     char* string = mlr_malloc_or_die(n+1);
  158     sprintf(string, "%d", value);
  159     return string;
  160 }
  161 
  162 char* mlr_alloc_string_from_char_range(char* start, int num_bytes) {
  163     char* string = mlr_malloc_or_die(num_bytes+1);
  164     memcpy(string, start, num_bytes);
  165     string[num_bytes] = 0;
  166     return string;
  167 }
  168 
  169 char* mlr_alloc_hexfmt_from_ll(long long value) {
  170     int n = snprintf(NULL, 0, "0x%llx", (unsigned long long)value);
  171     char* string = mlr_malloc_or_die(n+1);
  172     sprintf(string, "0x%llx", value);
  173     return string;
  174 }
  175 
  176 char* mlr_alloc_string_from_string_and_format(char* old_value, char* fmt) {
  177     int n = snprintf(NULL, 0, fmt, old_value);
  178     char* new_value = mlr_malloc_or_die(n+1);
  179     sprintf(new_value, fmt, old_value);
  180     return new_value;
  181 }
  182 
  183 double mlr_double_from_string_or_die(char* string) {
  184     double d;
  185     if (!mlr_try_float_from_string(string, &d)) {
  186         fprintf(stderr, "%s: couldn't parse \"%s\" as number.\n",
  187             MLR_GLOBALS.bargv0, string);
  188         exit(1);
  189     }
  190     return d;
  191 }
  192 
  193 // E.g. "300" is a number; "300ms" is not.
  194 int mlr_try_float_from_string(char* string, double* pval) {
  195     int num_bytes_scanned;
  196     int rc = sscanf(string, "%lf%n", pval, &num_bytes_scanned);
  197     if (rc != 1)
  198         return 0;
  199     if (string[num_bytes_scanned] != 0) // scanned to end of string?
  200         return 0;
  201     return 1;
  202 }
  203 
  204 long long mlr_int_from_string_or_die(char* string) {
  205     long long i;
  206     if (!mlr_try_int_from_string(string, &i)) {
  207         fprintf(stderr, "Couldn't parse \"%s\" as number.\n", string);
  208         exit(1);
  209     }
  210     return i;
  211 }
  212 
  213 // E.g. "300" is a number; "300ms" is not.
  214 int mlr_try_int_from_string(char* string, long long* pval) {
  215     int num_bytes_scanned, rc;
  216     // sscanf with %li / %lli doesn't scan correctly when the high bit is set
  217     // on hex input; it just returns max signed. So we need to special-case hex
  218     // input.
  219     if (string[0] == '0' && (string[1] == 'x' || string[1] == 'X')) {
  220         rc = sscanf(string, "%llx%n", pval, &num_bytes_scanned);
  221     } else {
  222         rc = sscanf(string, "%lli%n", pval, &num_bytes_scanned);
  223     }
  224     if (rc != 1)
  225         return 0;
  226     if (string[num_bytes_scanned] != 0) // scanned to end of string?
  227         return 0;
  228     return 1;
  229 }
  230 
  231 // ----------------------------------------------------------------
  232 static char* low_int_to_string_data[] = {
  233     "0",   "1",  "2",  "3",  "4",  "5",  "6",  "7",  "8",  "9",
  234     "10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
  235     "20", "21", "22", "23", "24", "25", "26", "27", "28", "29",
  236     "30", "31", "32", "33", "34", "35", "36", "37", "38", "39",
  237     "40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
  238     "50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
  239     "60", "61", "62", "63", "64", "65", "66", "67", "68", "69",
  240     "70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
  241     "80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
  242     "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "100"
  243 };
  244 
  245 char* low_int_to_string(int idx, char* pfree_flags) {
  246     if ((0 <= idx) && (idx <= 100)) {
  247         *pfree_flags = 0;
  248         return low_int_to_string_data[idx];
  249     } else {
  250         char buf[32];
  251         sprintf(buf, "%d", idx);
  252         *pfree_flags = FREE_ENTRY_KEY;
  253         return mlr_strdup_or_die(buf);
  254     }
  255 }
  256 
  257 // ----------------------------------------------------------------
  258 char* mlr_paste_2_strings(char* s1, char* s2) {
  259     int n1 = strlen(s1);
  260     int n2 = strlen(s2);
  261     char* s = mlr_malloc_or_die(n1+n2+1);
  262     strcpy(s, s1);
  263     strcat(s, s2);
  264     return s;
  265 }
  266 
  267 char* mlr_paste_3_strings(char* s1, char* s2, char* s3) {
  268     int n1 = strlen(s1);
  269     int n2 = strlen(s2);
  270     int n3 = strlen(s3);
  271     char* s = mlr_malloc_or_die(n1+n2+n3+1);
  272     strcpy(s, s1);
  273     strcat(s, s2);
  274     strcat(s, s3);
  275     return s;
  276 }
  277 
  278 char* mlr_paste_4_strings(char* s1, char* s2, char* s3, char* s4) {
  279     int n1 = strlen(s1);
  280     int n2 = strlen(s2);
  281     int n3 = strlen(s3);
  282     int n4 = strlen(s4);
  283     char* s = mlr_malloc_or_die(n1+n2+n3+n4+1);
  284     strcpy(s, s1);
  285     strcat(s, s2);
  286     strcat(s, s3);
  287     strcat(s, s4);
  288     return s;
  289 }
  290 
  291 char* mlr_paste_5_strings(char* s1, char* s2, char* s3, char* s4, char* s5) {
  292     int n1 = strlen(s1);
  293     int n2 = strlen(s2);
  294     int n3 = strlen(s3);
  295     int n4 = strlen(s4);
  296     int n5 = strlen(s5);
  297     char* s = mlr_malloc_or_die(n1+n2+n3+n4+n5+1);
  298     strcpy(s, s1);
  299     strcat(s, s2);
  300     strcat(s, s3);
  301     strcat(s, s4);
  302     strcat(s, s5);
  303     return s;
  304 }
  305 
  306 // ----------------------------------------------------------------
  307 // This is djb2.
  308 int mlr_string_hash_func(char *str) {
  309     unsigned long hash = 5381;
  310     int c;
  311 
  312     while ((c = *str++) != 0)
  313         hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
  314 
  315     return (int)hash;
  316 }
  317 
  318 int mlr_string_pair_hash_func(char* str1, char* str2) {
  319     unsigned long hash = 5381;
  320     int c;
  321 
  322     while ((c = *str1++) != 0)
  323         hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
  324     while ((c = *str2++) != 0)
  325         hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
  326 
  327     return (int)hash;
  328 }
  329 
  330 // ----------------------------------------------------------------
  331 // 0x00-0x7f (MSB is 0) are ASCII and printable.
  332 // 0x80-0xbf (MSBs are 10) are continuation characters and don't add to printable length.
  333 // 0xc0-0xfe (MSBs are 11) are leading characters and do add to printable length.
  334 // (0xff, incidentally, is never a valid UTF-8 byte).
  335 int strlen_for_utf8_display(char* str) {
  336     int len = 0;
  337     for (char* p = str; *p; p++) {
  338         if ((*p & 0xc0) != 0x80)
  339             len++;
  340     }
  341     return len;
  342 }
  343 
  344 // ----------------------------------------------------------------
  345 // These are for low-volume, call-at-startup applications. If they get used
  346 // record-by-record they should be replaced with pointer-walking logic which
  347 // avoids the unnecessary expense of calling strlen.
  348 
  349 int string_starts_with(char* string, char* prefix) {
  350     int prefixlen = strlen(prefix);
  351     return !strncmp(string, prefix, prefixlen);
  352 }
  353 
  354 int string_ends_with(char* string, char* suffix, int* pstringlen) {
  355     int stringlen = strlen(string);
  356     int suffixlen = strlen(suffix);
  357     if (pstringlen != NULL)
  358         *pstringlen = stringlen;
  359     if (stringlen < suffixlen)
  360         return FALSE;
  361     return !strcmp(&string[stringlen-suffixlen], suffix);
  362 }
  363 
  364 // ----------------------------------------------------------------
  365 int mlr_imax2(int a, int b) {
  366     if (a >= b)
  367         return a;
  368     else
  369         return b;
  370 }
  371 
  372 // ----------------------------------------------------------------
  373 int mlr_imax3(int a, int b, int c) {
  374     return mlr_imax2(a, mlr_imax2(b, c));
  375 }
  376 
  377 // ----------------------------------------------------------------
  378 int power_of_two_above(int n) {
  379     n |= (n >> 1);
  380     n |= (n >> 2);
  381     n |= (n >> 4);
  382     n |= (n >> 8);
  383     n |= (n >> 16);
  384     return(n+1);
  385 }
  386 
  387 // ----------------------------------------------------------------
  388 static int is_backslash_octal(char* input, int* pcode) {
  389     if (strlen(input) < 4)
  390         return FALSE;
  391     if (input[0] != '\\')
  392         return FALSE;
  393     if (input[1] < '0' || input[1] > '7')
  394         return FALSE;
  395     if (input[2] < '0' || input[2] > '7')
  396         return FALSE;
  397     if (input[3] < '0' || input[3] > '7')
  398         return FALSE;
  399     *pcode = (input[1] - '0') * 64
  400         + (input[2] - '0') * 8
  401         + (input[3] - '0');
  402     return TRUE;
  403 }
  404 
  405 static int is_backslash_hex(char* input, int* pcode) {
  406     if (strlen(input) < 4)
  407         return FALSE;
  408     if (input[0] != '\\')
  409         return FALSE;
  410     if (input[1] != 'x')
  411         return FALSE;
  412     if (!isxdigit(input[2]))
  413         return FALSE;
  414     if (!isxdigit(input[3]))
  415         return FALSE;
  416 
  417     char buf[3];
  418     buf[0] = input[2];
  419     buf[1] = input[3];
  420     buf[2] = 0;
  421     if (sscanf(buf, "%x", pcode) != 1) {
  422         fprintf(stderr, "Miller: internal coding error detected in file %s at line %d.\n",
  423             __FILE__, __LINE__);
  424         exit(1);
  425     }
  426     return TRUE;
  427 }
  428 
  429 char* mlr_alloc_unbackslash(char* input) {
  430     // Do the strdup even if there's nothing to expand, so the caller can unconditionally
  431     // free what we return.
  432     char* output = mlr_strdup_or_die(input);
  433     char* pi = input;
  434     char* po = output;
  435     int code = 0;
  436     while (*pi) {
  437         // https://en.wikipedia.org/wiki/Escape_sequences_in_C
  438         if (streqn(pi, "\\a", 2)) {
  439             pi += 2;
  440             *(po++) = '\a';
  441         } else if (streqn(pi, "\\b", 2)) {
  442             pi += 2;
  443             *(po++) = '\b';
  444         } else if (streqn(pi, "\\f", 2)) {
  445             pi += 2;
  446             *(po++) = '\f';
  447         } else if (streqn(pi, "\\n", 2)) {
  448             pi += 2;
  449             *(po++) = '\n';
  450         } else if (streqn(pi, "\\r", 2)) {
  451             pi += 2;
  452             *(po++) = '\r';
  453         } else if (streqn(pi, "\\t", 2)) {
  454             pi += 2;
  455             *(po++) = '\t';
  456         } else if (streqn(pi, "\\v", 2)) {
  457             pi += 2;
  458             *(po++) = '\v';
  459         } else if (streqn(pi, "\\\\", 2)) {
  460             pi += 2;
  461             *(po++) = '\\';
  462         } else if (streqn(pi, "\\'", 2)) {
  463             pi += 2;
  464             *(po++) = '\'';
  465         } else if (streqn(pi, "\\\"", 2)) {
  466             pi += 2;
  467             *(po++) = '"';
  468         } else if (streqn(pi, "\\?", 2)) {
  469             pi += 2;
  470             *(po++) = '?';
  471         } else if (is_backslash_octal(pi, &code)) {
  472             pi += 4;
  473             *(po++) = code;
  474         } else if (is_backslash_hex(pi, &code)) {
  475             pi += 4;
  476             *(po++) = code;
  477         } else {
  478             *po = *pi;
  479             pi++;
  480             po++;
  481         }
  482     }
  483     *po = 0;
  484 
  485     return output;
  486 }
  487 
  488 // Does a strdup even if there's nothing to expand, so the caller can unconditionally
  489 // free what we return.
  490 char* mlr_alloc_double_backslash(char* input) {
  491     char *p, *q;
  492     int input_length = 0;
  493     int num_backslashes = 0;
  494     for (p = input; *p; p++) {
  495         input_length++;
  496         if (*p == '\\') {
  497             if (p[1] != '.') {
  498                 num_backslashes++;
  499             }
  500         }
  501     }
  502     char* output = mlr_malloc_or_die(input_length + num_backslashes + 1);
  503     for (p = input, q = output; *p; p++) {
  504         if (*p == '\\') {
  505             if (p[1] != '.') {
  506                 *(q++) = *p;
  507             }
  508             *(q++) = *p;
  509         } else {
  510             *(q++) = *p;
  511         }
  512     }
  513     *q = 0;
  514 
  515     return output;
  516 }
  517 
  518 // ----------------------------------------------------------------
  519 // Returns -1 on error
  520 ssize_t get_file_size(char* filename) {
  521     struct stat statbuf;
  522     if (stat(filename, &statbuf) < 0) {
  523         return (ssize_t)(-1);
  524     } else {
  525         return statbuf.st_size;
  526     }
  527 }
  528 
  529 // ----------------------------------------------------------------
  530 char* read_file_into_memory(char* filename, size_t* psize) {
  531     struct stat statbuf;
  532     if (stat(filename, &statbuf) < 0) {
  533         perror("stat");
  534         fprintf(stderr, "%s: could not stat \"%s\"\n", MLR_GLOBALS.bargv0, filename);
  535         exit(1);
  536     }
  537     char* buffer = mlr_malloc_or_die(statbuf.st_size + 1);
  538 
  539     FILE* fp = fopen(filename, "r");
  540     if (fp == NULL) {
  541         perror("fopen");
  542         fprintf(stderr, "%s: could not fopen \"%s\"\n", MLR_GLOBALS.bargv0, filename);
  543         free(buffer);
  544         return NULL;
  545     }
  546 
  547     size_t rc = fread(buffer, 1, statbuf.st_size, fp);
  548     if (rc != statbuf.st_size) {
  549         fprintf(stderr, "Unable to read content of %s\n", filename);
  550         perror("fread");
  551         fprintf(stderr, "%s: could not fread \"%s\"\n", MLR_GLOBALS.bargv0, filename);
  552         fclose(fp);
  553         free(buffer);
  554         return NULL;
  555     }
  556     fclose(fp);
  557     buffer[statbuf.st_size] = 0;
  558     if (psize)
  559         *psize = statbuf.st_size;
  560     return buffer;
  561 }
  562 
  563 // ----------------------------------------------------------------
  564 #define INITIAL_ALLOC_SIZE 16384
  565 #define BLOCK_SIZE 16384
  566 char* read_fp_into_memory(FILE* fp, size_t* psize) {
  567     size_t file_size = 0;
  568     size_t alloc_size = INITIAL_ALLOC_SIZE;
  569     char* buffer = mlr_malloc_or_die(alloc_size);
  570 
  571     while (TRUE) {
  572         if (file_size + BLOCK_SIZE > alloc_size) {
  573             alloc_size *= 2;
  574             buffer = mlr_realloc_or_die(buffer, alloc_size);
  575         }
  576         size_t block_num_bytes_read = fread(&buffer[file_size], 1, BLOCK_SIZE, fp);
  577         if (block_num_bytes_read == 0) {
  578             if (feof(fp))
  579                 break;
  580             perror("fread");
  581             fprintf(stderr, "%s: stdio/popen fread failed\n", MLR_GLOBALS.bargv0);
  582             free(buffer);
  583             *psize = 0;
  584             return NULL;
  585         }
  586         file_size += block_num_bytes_read;
  587     }
  588 
  589     *psize = file_size;
  590     return buffer;
  591 }
  592 
  593 // ----------------------------------------------------------------
  594 char* alloc_suffixed_temp_file_name(char* filename) {
  595     const int suffix_length = 6;
  596     static char bag[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789";
  597     const static int bag_length = sizeof(bag) - 1;
  598 
  599     char* output = mlr_malloc_or_die(strlen(filename) + 2 + suffix_length);
  600 
  601     int rand_start_index = sprintf(output, "%s.", filename);
  602     char* rand_start_ptr = &output[rand_start_index];
  603 
  604     int i = 0;
  605     for ( ; i < suffix_length; i++) {
  606         rand_start_ptr[i] = bag[get_mtrand_int32() % bag_length];
  607     }
  608     rand_start_ptr[i] = 0;
  609 
  610     return output;
  611 }
  612 
  613 // ----------------------------------------------------------------
  614 // The convention for argv-style arrays is that they're null-terminated.
  615 // So we loop through once to find the length.
  616 char** copy_argv(char** argv) {
  617     int length = 0;
  618     int argi;
  619     for (argi = 0; argv[argi]; argi++) {
  620         length++;
  621     }
  622 
  623     char** copy = mlr_malloc_or_die((length + 1) * sizeof(char*));
  624     for (argi = 0; argv[argi]; argi++) {
  625         copy[argi] = mlr_strdup_or_die(argv[argi]);
  626     }
  627 
  628     copy[length] = 0;
  629 
  630     return copy;
  631 }
  632 
  633 void free_argv_copy(char** copy) {
  634     for (int argi = 0; copy[argi]; argi++) {
  635         free(copy[argi]);
  636     }
  637     free(copy);
  638 }