Advertisement
aaaaaa123456789

Common library code

Dec 16th, 2013
113
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2.   This file is hereby released to the public domain.
  3.   ~aaaaaa123456789, 2015-01-21
  4.  
  5.   last updated 2015-01-23
  6. */
  7.  
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11.  
  12. #include "common.h"
  13.  
  14. static char ** get_lines_data(unsigned, const char *, unsigned char *);
  15. static void flatten_line_pointers(char ***, unsigned);
  16. static int add_line_count(void *, void *);
  17. static int array_all_callback(void *, void *);
  18.  
  19. struct array_all_struct {
  20.   int (* callback) (void *, void *);
  21.   void * data;
  22. };
  23.  
  24. char * get_line (unsigned char * reachedEOF) {
  25.   char * line = NULL;
  26.   unsigned length = 0;
  27.   int newchar;
  28.   for (newchar = getchar(); (newchar != EOF) && (newchar != '\n'); newchar = getchar()) {
  29.     line = realloc(line, ++ length);
  30.     line[length - 1] = newchar;
  31.   }
  32.   line = realloc(line, length + 1);
  33.   line[length] = 0;
  34.   if (reachedEOF) *reachedEOF = newchar == EOF;
  35.   return line;
  36. }
  37.  
  38. char ** get_lines (unsigned lines, const char * stopper, int single_pointer, unsigned char * reachedEOF) {
  39.   if (reachedEOF) *reachedEOF = 0;
  40.   char ** result = get_lines_data(lines, stopper, reachedEOF);
  41.   if (single_pointer) flatten_line_pointers(&result, count_lines(result));
  42.   return result;
  43. }
  44.  
  45. char * read_all (FILE * stream) {
  46.   char * result;
  47.   unsigned length = read_all_binary(stream, &result);
  48.   if (!result) return NULL;
  49.   result = realloc(result, length + 1);
  50.   result[length] = 0;
  51.   return result;
  52. }
  53.  
  54. unsigned read_all_binary (FILE * stream, char ** result) {
  55.   if (!result) return -1;
  56.   *result = NULL;
  57.   if (!stream) return -2;
  58.   char * data = NULL;
  59.   unsigned length = 0;
  60.   char buffer[16384];
  61.   unsigned short read_length;
  62.   rewind(stream);
  63.   while (!(feof(stream) || ferror(stream))) {
  64.     read_length = fread(buffer, 1, 16384, stream);
  65.     data = realloc(data, length + read_length);
  66.     memcpy(data + length, buffer, read_length);
  67.     length += read_length;
  68.   }
  69.   if (ferror(stream)) {
  70.     free(data);
  71.     return -3;
  72.   }
  73.   *result = data;
  74.   return length;
  75. }
  76.  
  77. void free_lines_array (char ** lines, unsigned size) {
  78.   if (!size) size = -1;
  79.   unsigned line;
  80.   for (line = 0; line < size; line ++) {
  81.     if (!lines[line]) break;
  82.     free(lines[line]);
  83.   }
  84.   free(lines);
  85. }
  86.  
  87. int check_line (char ** line, unsigned expected_size, const char * valid_chars, char replacement, FILE * error_stream, unsigned line_number) {
  88.   int errors = LCERR_OK;
  89.   unsigned pos, length;
  90.   char * current;
  91.   char lnbuf[30];
  92.   if (line_number)
  93.     sprintf(lnbuf, "Line %u", line_number);
  94.   else
  95.     strcpy(lnbuf, "Line");
  96.   if ((valid_chars || expected_size) && (!replacement)) return LCERR_INVALID_REPLACEMENT;
  97.   if (!expected_size) goto size_checked;
  98.   length = strlen(*line);
  99.   if (length > expected_size) {
  100.     if (error_stream) fprintf(error_stream, "%s is %u characters long (expected: %u), truncating\n", lnbuf, length, expected_size);
  101.     *line = realloc(*line, expected_size + 1);
  102.     expected_size[*line] = 0;
  103.     errors |= LCERR_LINE_TOO_LONG;
  104.   } else if (length < expected_size) {
  105.     if (error_stream)
  106.       fprintf(error_stream, "%s is %u characters long (expected: %u), padding with '%c'\n", lnbuf, length, expected_size, replacement);
  107.     *line = realloc(*line, expected_size + 1);
  108.     memset(*line + length, replacement, expected_size - length);
  109.     expected_size[*line] = 0;
  110.     errors |= LCERR_LINE_TOO_SHORT;
  111.   }
  112.   size_checked:
  113.   if (!valid_chars) goto chars_checked;
  114.   for (current = *line, pos = 0; current < (*line + expected_size); current += pos + 1) {
  115.     pos = strspn(current, valid_chars);
  116.     if ((current + pos) >= (*line + expected_size)) break;
  117.     length = current - *line;
  118.     if (error_stream)
  119.       fprintf(error_stream, "%s: spurious character 0x%02x at column %u, inserting '%c'\n", lnbuf, current[pos], pos + length + 1, replacement);
  120.     current[pos] = replacement;
  121.     errors |= LCERR_SPURIOUS_CHARS;
  122.   }
  123.   chars_checked:
  124.   return errors;
  125. }
  126.  
  127. unsigned get_number (void) {
  128.   char * line = get_line(NULL);
  129.   if (!*line) {
  130.     free(line);
  131.     return 0;
  132.   }
  133.   char * end;
  134.   unsigned number = strtoul(line, &end, 10);
  135.   if (*end) number = 0;
  136.   free(line);
  137.   return number;
  138. }
  139.  
  140. int array_each (void * array, unsigned item_size, unsigned count, void * stopper, int (* callback) (void *, void *), void * data) {
  141.   char * current;
  142.   int value;
  143.   if (!array) return 0;
  144.   if (!count) count = -1;
  145.   for (current = array; count; count --, current += item_size) {
  146.     if ((stopper) && (!memcmp(current, stopper, item_size))) return 0;
  147.     value = (*callback)(current, data);
  148.     if (value) return value;
  149.   }
  150.   return 0;
  151. }
  152.  
  153. int array_all (void * array, unsigned item_size, unsigned count, void * stopper, int (* callback) (void *, void *), void * data) {
  154.   struct array_all_struct cbdata = {.callback = callback, .data = data};
  155.   return !array_each(array, item_size, count, stopper, &array_all_callback, &cbdata);
  156. }
  157.  
  158. unsigned count_lines (char ** lines) {
  159.   unsigned count = 0;
  160.   array_each(lines, sizeof(char *), 0, NULL, &add_line_count, &count);
  161.   return count;
  162. }
  163.  
  164. char ** tokenize_string (const char * string, const char * delimiters, int single_pointer) {
  165.   if (!string) return NULL;
  166.   if (!delimiters) delimiters = " \f\n\r\t\v";
  167.   char ** result = malloc(sizeof(char *));
  168.   const char * current = string + strspn(string, delimiters);
  169.   unsigned count = 0;
  170.   unsigned length;
  171.   while (*current) {
  172.     length = strcspn(current, delimiters);
  173.     result[count] = malloc(length + 1);
  174.     memcpy(result[count], current, length);
  175.     result[count][length] = 0;
  176.     result = realloc(result, sizeof(char *) * (count + 2));
  177.     count ++;
  178.     current += length;
  179.     length = strspn(current, delimiters);
  180.     current += length;
  181.   }
  182.   result[count] = NULL;
  183.   if (single_pointer) flatten_line_pointers(&result, count_lines(result));
  184.   return result;
  185. }
  186.  
  187. void * xmalloc (size_t size) {
  188.   if (!size) return NULL;
  189.   void * rv = malloc(size);
  190.   if (!rv) {
  191.     fputs("ERROR: Out of memory.\n", stderr);
  192.     abort();
  193.   }
  194.   return rv;
  195. }
  196.  
  197. void * xrealloc (void * buf, size_t size) {
  198.   void * rv = realloc(buf, size);
  199.   if (!rv) {
  200.     fputs("ERROR: Out of memory.\n", stderr);
  201.     abort();
  202.   }
  203.   return rv;
  204. }
  205.  
  206.  
  207. static char ** get_lines_data (unsigned lines, const char * stopper, unsigned char * reachedEOF) {
  208.   char ** result = malloc(sizeof(char *));
  209.   unsigned count = 0;
  210.   char * line;
  211.   unsigned char eofstatus = 0;
  212.   if (!reachedEOF) reachedEOF = &eofstatus;
  213.   while (1) {
  214.     if (lines && (count >= lines)) break;
  215.     line = get_line(reachedEOF);
  216.     if (stopper && !strcmp(stopper, line)) {
  217.       free(line);
  218.       break;
  219.     }
  220.     result[count] = line;
  221.     result = realloc(result, sizeof(char *) * (count + 2));
  222.     count ++;
  223.     if (*reachedEOF) break;
  224.   }
  225.   result[count] = NULL;
  226.   return result;
  227. }
  228.  
  229. static void flatten_line_pointers (char *** pointers, unsigned lines) {
  230.   unsigned offset = sizeof(char *) * (lines + 1);
  231.   unsigned line;
  232.   unsigned total = 0;
  233.   for (line = 0; line < lines; line ++) total += strlen(line[*pointers]);
  234.   char ** result = malloc(offset + total + lines);
  235.   char * lineptr = ((char *) result) + offset;
  236.   result[lines] = NULL;
  237.   for (line = 0; line < lines; line ++) {
  238.     offset = strlen(line[*pointers]) + 1;
  239.     memcpy(lineptr, line[*pointers], offset);
  240.     free(line[*pointers]);
  241.     result[line] = lineptr;
  242.     lineptr += offset;
  243.   }
  244.   free(*pointers);
  245.   *pointers = result;
  246. }
  247.  
  248. static int add_line_count (void * line, void * count) {
  249.   if (!*((char **) line)) return 1;
  250.   unsigned * c = count;
  251.   (*c) ++;
  252.   return 0;
  253. }
  254.  
  255. static int array_all_callback (void * item, void * data) {
  256.   return !(((struct array_all_struct *) data -> callback)(item, (struct array_all_struct *) data -> data));
  257. }
Advertisement
RAW Paste Data Copied
Advertisement