#include #include #include #include #include #include #define SIZE 4096 #define out_of_memory(n) do { printf("Out of memory: " n "\n"); exxx(1); } while(0) typedef enum { DIGIT, NON_DIGIT } match; union strnum { char **ptr; char *string; int *integer; void *generic; mpz_t *bignum; }; typedef struct _linkedlist { union strnum data; struct _linkedlist *next; } LinkedList; void *pointers[1024 * 1024]; int pointer_size[1024 * 1024]; int pointer_count = 0; void exxx(int i) { exit(i); } void fprint_raw(char *p, int n) { int i; for (i = 0; i < n; i++) fprintf(stderr, "%c", p[i]); } /* A far from great huge list of pointers, * used to verify that we aren't allocating * over an existing pointer as well as to * have a list to verify against when we try * to free a pointer. */ int add_pointer(void *p, int n) { int i, match = 0, uhoh = 0; /* Verify it doesn't cross an existing pointer */ for (i = 0; i < pointer_count; i++) { if (p > pointers[i] && p < pointers[i] + pointer_size[i]) { fprintf(stderr, "Uh oh. %p crosses %p (size %d) [%p-%p]! : [", p, pointers[i], pointer_size[i], pointers[i], pointers[i] + pointer_size[i]); fprint_raw(pointers[i], 32); fprintf(stderr, "] or from start position ["); fprint_raw(p, 32); fprintf(stderr, "]\n"); uhoh = 1; //exxx(2); } } fprintf(stderr, "Adding pointer %p of size %d.\n", p, n); /* Then add it */ for (i = 0; i < pointer_count; i++) { if (pointers[i] == NULL) { match = 1; pointers[i] = p; pointer_size[i] = n; break; } } if (!match) { pointers[pointer_count] = p; pointer_size[pointer_count++] = n; } return uhoh; } static int string_number_cmp(const void *a, const void *b) { char *temp_data; LinkedList *left = ((LinkedList *) a)->next, *right = ((LinkedList *) b)->next; int i; match str = NON_DIGIT; while (1) { if (left == NULL && right == NULL) { return 0; } else { if (left == NULL && right != NULL) return -1; else if (left != NULL && right == NULL) { return 1; } else { if (str == NON_DIGIT) { i = strcmp(left->data.string, right->data.string); str = DIGIT; } else { i = mpz_cmp(*(left->data.bignum), *(right->data.bignum)); str = NON_DIGIT; } if (i) { return i; } else { left = left->next; right = right->next; } } } } } LinkedList *alloc_linkedlist(LinkedList ** list, void *data) { LinkedList *temp; int i, match = 0; assert(data != NULL); temp = malloc(sizeof(LinkedList)); if (temp == NULL) return NULL; temp->data.generic = data; temp->next = NULL; if (add_pointer(temp, sizeof(LinkedList))) { fprintf(stderr, "Linkedlist data: "); fprint_raw(data, 8); fprintf(stderr, "\n"); } //fprintf(stderr, " ]%p[ ", temp); *list = temp; return temp; } /* Simple step through linkedlist to clear */ void free_linkedlist(LinkedList * list, int free_data) { LinkedList *temp; int i, match; while (list != NULL) { if (free_data) { free(list->data.generic); fprintf(stderr, "Freeing data %p\n", list->data.generic); } temp = list; list = list->next; match = 0; for (i = 0; i < pointer_count; i++) { if (temp == pointers[i]) { match = 1; break; } } if (!match) { fprintf(stderr, "Trying to deallocated %p, which was never allocated.\n", temp); exxx(2); } fprintf(stderr, "Freeing linkedlist %p\n", temp); free(temp); pointers[i] = NULL; //fprintf(stderr, " >%p< ", temp); } //fprintf(stderr, "\n"); } /* Read in from stdin into an a linked list of the form * lines = [ count of lines | chain ] * chain = [ line of text | chain ] * * or NULL on failure */ LinkedList *read_in_lines(void) { LinkedList *lines, **current_line; char buffer[SIZE], *current_pos, *rest, *line; int size, count, line_length; int *temp; current_line = &lines; temp = malloc(sizeof(int)); if ((lines = alloc_linkedlist(current_line, temp)) == NULL) { return NULL; } current_line = &((*current_line)->next); if (temp == NULL) { fprintf(stderr, "Inappropriate free called.\n"); //free(lines); return NULL; } if (add_pointer(temp, sizeof(int))) fprintf(stderr, "Allocating int for return.\n"); line = NULL; line_length = count = 0; while ((size = read(STDIN_FILENO, buffer, SIZE)) > 0) { current_pos = buffer; while ((rest = memchr(current_pos, '\n', size)) != NULL) { /* Append line. */ if ((line = realloc(line, line_length + (rest - current_pos + 1))) == NULL) out_of_memory("line"); memcpy(&line[line_length], current_pos, (rest - current_pos)); line_length += (rest - current_pos); line[line_length] = '\0'; /* Add to chain */ count++; if (add_pointer(line, line_length)) fprintf(stderr, "Adding in read in line: %s\n", line); if (alloc_linkedlist(current_line, line) == NULL) { free_linkedlist(lines, 1); return NULL; } current_line = &((*current_line)->next); line_length = 0; line = NULL; /* Adjust buffer */ size -= (rest - current_pos + 1); current_pos = rest + 1; } /* Append part of line */ if (size > 0) { if ((line = realloc(line, line_length + size)) == NULL) out_of_memory("line"); memcpy(&line[line_length], current_pos, size); line_length += size; } } if (line_length > 0) { /* Add to chain */ count++; if ((line = realloc(line, line_length + 1)) == NULL) out_of_memory("line"); line[line_length] = '\0'; add_pointer(line, line_length); fprintf(stderr, "Adding in read in line: %s\n", line); if (alloc_linkedlist(current_line, line) == NULL) { free_linkedlist(lines, 1); return NULL; } //current_line = &((*current_line)->next); } *(lines->data.integer) = count; //fprintf(stderr, "\n"); return lines; } /* Simple linked list to array move */ char **linkedlist_to_array(LinkedList * chain, int count) { char **lines = malloc(sizeof(LinkedList) * count); int i = 0; if (lines == NULL) return NULL; if (add_pointer(lines, sizeof(LinkedList) * count)) fprintf(stderr, "Adding in block for linkedlist to array conversion.\n"); for (; chain != NULL; chain = chain->next) lines[i++] = chain->data.string; return lines; } /* Two part divide of text into numbers and non-numbers */ LinkedList *string_and_numbers(char *text) { LinkedList *san, **san_temp; char *temp, *mt_c; mpz_t *mt_m; match str = NON_DIGIT; san = NULL; san_temp = &san; fprintf(stderr, "%s\n", text); while (*text != '\0') { /* String */ temp = text; if (str == DIGIT) { for (; *temp != '\0' && strchr("0123456789", *temp) != NULL; temp++); if ((mt_m = malloc(temp - text + 1)) == NULL) out_of_memory("san"); if (add_pointer(mt_m, sizeof(mpz_t))) fprintf(stderr, "Adding in big int.\n"); mpz_init(*mt_m); gmp_sscanf(text, "%Zd", *mt_m); if (alloc_linkedlist(san_temp, mt_m) == NULL) out_of_memory("san, n"); str = NON_DIGIT; } else { for (; *temp != '\0' && strchr("0123456789", *temp) == NULL; temp++); if ((mt_c = malloc(sizeof(mpz_t))) == NULL) out_of_memory("san"); memcpy(mt_c, text, temp - text); mt_c[temp - text] = '\0'; fprintf(stderr, "%s\n", mt_c); if (add_pointer(mt_c, temp - text + 1)) fprintf(stderr, "Adding in text fragment: %s.\n", mt_c); if (alloc_linkedlist(san_temp, mt_c) == NULL) out_of_memory("san, n"); str = DIGIT; } san_temp = &((*san_temp)->next); text = temp; } //fprintf(stderr, "\n"); return san; } /* Stuff pointers into array so string_number_cmp * can manually shuffle them around as appropriate. */ void sort_by_string_number(char **chain, int count) { LinkedList array[count], *temp, *temp2; int i; printf("((((\n"); for (i = 0; i < count; i++) { printf("%d : %s\n", i, chain[i]); array[i].data.string = chain[i]; array[i].next = string_and_numbers(chain[i]); } printf("))))\n"); printf("<<<<\n"); for (i = 0; i < count; i++) printf("%d : %s\n", i, chain[i]); printf(">>>>\n"); qsort(array, count, sizeof(LinkedList), string_number_cmp); for (i = 0; i < count; i++) { chain[i] = array[i].data.string; free_linkedlist(array[i].next, 0); /* Special clean-up for bignums. */ /*temp = array[i].next; while (temp != NULL) { free(temp->data.string); temp2 = temp->next; free(temp); if (temp2 == NULL) temp = NULL; else { mpz_clear(*(temp2->data.bignum)); free(temp2->data.bignum); temp = temp2->next; free(temp2); } } */ } } /* Print array */ void print_lines_as_array(char **array, int count) { int i; // Print the sorted list, using the original lines. for (i = 0; i < count; i++) { printf("%s\n", array[i]); } } int main() { LinkedList *lines; char **lines_as_array; int count; fprintf(stderr, "read_in_lines()\n"); lines = read_in_lines(); if (lines == NULL) out_of_memory("ril"); count = *(lines->data.integer); fprintf(stderr, "linkedlist_to_array(...)\n"); lines_as_array = linkedlist_to_array(lines->next, count); if (lines_as_array == NULL) out_of_memory("lta"); fprintf(stderr, "print_lines_as_array(...)\n"); print_lines_as_array(lines_as_array, count); printf("------\n"); /* We never reallocated the text data, so don't clear it */ free_linkedlist(lines, 0); fprintf(stderr, "print_lines_as_array(...)\n"); print_lines_as_array(lines_as_array, count); printf("++++++\n"); fprintf(stderr, "sort_by_string_number(...)\n"); sort_by_string_number(lines_as_array, count); fprintf(stderr, "print_lines_as_array(...)\n"); print_lines_as_array(lines_as_array, count); return 0; }