aaaaaa123456789 icon

Common library code

aaaaaa123456789 | PRO | 12/16/13 09:18:43 AM UTC | 0 ⭐ | 410 👁️ | Never ⏰ | []
C |

7.7 KB

|

None

|

0 👍

/

0 👎

/*
  This file is hereby released to the public domain.
  ~aaaaaa123456789, 2015-01-21
  
  last updated 2015-01-23
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#include "common.h"
 
static char ** get_lines_data(unsigned, const char *, unsigned char *);
static void flatten_line_pointers(char ***, unsigned);
static int add_line_count(void *, void *);
static int array_all_callback(void *, void *);
 
struct array_all_struct {
  int (* callback) (void *, void *);
  void * data;
};
 
char * get_line (unsigned char * reachedEOF) {
  char * line = NULL;
  unsigned length = 0;
  int newchar;
  for (newchar = getchar(); (newchar != EOF) && (newchar != '\n'); newchar = getchar()) {
    line = realloc(line, ++ length);
    line[length - 1] = newchar;
  }
  line = realloc(line, length + 1);
  line[length] = 0;
  if (reachedEOF) *reachedEOF = newchar == EOF;
  return line;
}
 
char ** get_lines (unsigned lines, const char * stopper, int single_pointer, unsigned char * reachedEOF) {
  if (reachedEOF) *reachedEOF = 0;
  char ** result = get_lines_data(lines, stopper, reachedEOF);
  if (single_pointer) flatten_line_pointers(&result, count_lines(result));
  return result;
}
 
char * read_all (FILE * stream) {
  char * result;
  unsigned length = read_all_binary(stream, &result);
  if (!result) return NULL;
  result = realloc(result, length + 1);
  result[length] = 0;
  return result;
}
 
unsigned read_all_binary (FILE * stream, char ** result) {
  if (!result) return -1;
  *result = NULL;
  if (!stream) return -2;
  char * data = NULL;
  unsigned length = 0;
  char buffer[16384];
  unsigned short read_length;
  rewind(stream);
  while (!(feof(stream) || ferror(stream))) {
    read_length = fread(buffer, 1, 16384, stream);
    data = realloc(data, length + read_length);
    memcpy(data + length, buffer, read_length);
    length += read_length;
  }
  if (ferror(stream)) {
    free(data);
    return -3;
  }
  *result = data;
  return length;
}
 
void free_lines_array (char ** lines, unsigned size) {
  if (!size) size = -1;
  unsigned line;
  for (line = 0; line < size; line ++) {
    if (!lines[line]) break;
    free(lines[line]);
  }
  free(lines);
}
 
int check_line (char ** line, unsigned expected_size, const char * valid_chars, char replacement, FILE * error_stream, unsigned line_number) {
  int errors = LCERR_OK;
  unsigned pos, length;
  char * current;
  char lnbuf[30];
  if (line_number)
    sprintf(lnbuf, "Line %u", line_number);
  else
    strcpy(lnbuf, "Line");
  if ((valid_chars || expected_size) && (!replacement)) return LCERR_INVALID_REPLACEMENT;
  if (!expected_size) goto size_checked;
  length = strlen(*line);
  if (length > expected_size) {
    if (error_stream) fprintf(error_stream, "%s is %u characters long (expected: %u), truncating\n", lnbuf, length, expected_size);
    *line = realloc(*line, expected_size + 1);
    expected_size[*line] = 0;
    errors |= LCERR_LINE_TOO_LONG;
  } else if (length < expected_size) {
    if (error_stream)
      fprintf(error_stream, "%s is %u characters long (expected: %u), padding with '%c'\n", lnbuf, length, expected_size, replacement);
    *line = realloc(*line, expected_size + 1);
    memset(*line + length, replacement, expected_size - length);
    expected_size[*line] = 0;
    errors |= LCERR_LINE_TOO_SHORT;
  }
  size_checked:
  if (!valid_chars) goto chars_checked;
  for (current = *line, pos = 0; current < (*line + expected_size); current += pos + 1) {
    pos = strspn(current, valid_chars);
    if ((current + pos) >= (*line + expected_size)) break;
    length = current - *line;
    if (error_stream)
      fprintf(error_stream, "%s: spurious character 0x%02x at column %u, inserting '%c'\n", lnbuf, current[pos], pos + length + 1, replacement);
    current[pos] = replacement;
    errors |= LCERR_SPURIOUS_CHARS;
  }
  chars_checked:
  return errors;
}
 
unsigned get_number (void) {
  char * line = get_line(NULL);
  if (!*line) {
    free(line);
    return 0;
  }
  char * end;
  unsigned number = strtoul(line, &end, 10);
  if (*end) number = 0;
  free(line);
  return number;
}
 
int array_each (void * array, unsigned item_size, unsigned count, void * stopper, int (* callback) (void *, void *), void * data) {
  char * current;
  int value;
  if (!array) return 0;
  if (!count) count = -1;
  for (current = array; count; count --, current += item_size) {
    if ((stopper) && (!memcmp(current, stopper, item_size))) return 0;
    value = (*callback)(current, data);
    if (value) return value;
  }
  return 0;
}
 
int array_all (void * array, unsigned item_size, unsigned count, void * stopper, int (* callback) (void *, void *), void * data) {
  struct array_all_struct cbdata = {.callback = callback, .data = data};
  return !array_each(array, item_size, count, stopper, &array_all_callback, &cbdata);
}
 
unsigned count_lines (char ** lines) {
  unsigned count = 0;
  array_each(lines, sizeof(char *), 0, NULL, &add_line_count, &count);
  return count;
}
 
char ** tokenize_string (const char * string, const char * delimiters, int single_pointer) {
  if (!string) return NULL;
  if (!delimiters) delimiters = " \f\n\r\t\v";
  char ** result = malloc(sizeof(char *));
  const char * current = string + strspn(string, delimiters);
  unsigned count = 0;
  unsigned length;
  while (*current) {
    length = strcspn(current, delimiters);
    result[count] = malloc(length + 1);
    memcpy(result[count], current, length);
    result[count][length] = 0;
    result = realloc(result, sizeof(char *) * (count + 2));
    count ++;
    current += length;
    length = strspn(current, delimiters);
    current += length;
  }
  result[count] = NULL;
  if (single_pointer) flatten_line_pointers(&result, count_lines(result));
  return result;
}
 
void * xmalloc (size_t size) {
  if (!size) return NULL;
  void * rv = malloc(size);
  if (!rv) {
    fputs("ERROR: Out of memory.\n", stderr);
    abort();
  }
  return rv;
}
 
void * xrealloc (void * buf, size_t size) {
  void * rv = realloc(buf, size);
  if (!rv) {
    fputs("ERROR: Out of memory.\n", stderr);
    abort();
  }
  return rv;
}
 
 
static char ** get_lines_data (unsigned lines, const char * stopper, unsigned char * reachedEOF) {
  char ** result = malloc(sizeof(char *));
  unsigned count = 0;
  char * line;
  unsigned char eofstatus = 0;
  if (!reachedEOF) reachedEOF = &eofstatus;
  while (1) {
    if (lines && (count >= lines)) break;
    line = get_line(reachedEOF);
    if (stopper && !strcmp(stopper, line)) {
      free(line);
      break;
    }
    result[count] = line;
    result = realloc(result, sizeof(char *) * (count + 2));
    count ++;
    if (*reachedEOF) break;
  }
  result[count] = NULL;
  return result;
}
 
static void flatten_line_pointers (char *** pointers, unsigned lines) {
  unsigned offset = sizeof(char *) * (lines + 1);
  unsigned line;
  unsigned total = 0;
  for (line = 0; line < lines; line ++) total += strlen(line[*pointers]);
  char ** result = malloc(offset + total + lines);
  char * lineptr = ((char *) result) + offset;
  result[lines] = NULL;
  for (line = 0; line < lines; line ++) {
    offset = strlen(line[*pointers]) + 1;
    memcpy(lineptr, line[*pointers], offset);
    free(line[*pointers]);
    result[line] = lineptr;
    lineptr += offset;
  }
  free(*pointers);
  *pointers = result;
}
 
static int add_line_count (void * line, void * count) {
  if (!*((char **) line)) return 1;
  unsigned * c = count;
  (*c) ++;
  return 0;
}
 
static int array_all_callback (void * item, void * data) {
  return !(((struct array_all_struct *) data -> callback)(item, (struct array_all_struct *) data -> data));
}

Comments