#include #include #include #include #if defined(bsdi) #include "fdrand48.h" #define srand48 fsrand48 #define drand48 fdrand48 #endif #define ALLOCATION_SIZE (1024*1024*8) static unsigned long memsize = 0; char* allocation_buffer = NULL; int allocation_index = 0; #define PADDING 8 int verbose_mode = 0; struct word_list { char* word; struct word_list* next; }; void init_buffer(void) { if((allocation_buffer = malloc(ALLOCATION_SIZE)) == NULL) { perror("malloc"); exit(1); } allocation_index = 0; if(verbose_mode) fprintf(stderr, "Memory allocation +%d\n", ALLOCATION_SIZE); } void* alloc_memory(long sz) { void* ptr; if(allocation_index + sz + PADDING >= ALLOCATION_SIZE) init_buffer(); ptr = (void *)(allocation_buffer + allocation_index); allocation_index += sz; allocation_index += (PADDING-1) - (allocation_index+PADDING-1)%PADDING; memsize += sz; return ptr; } FILE* file_open(const char* fname) { if(!strcmp(fname, "-")) return stdin; return fopen(fname, "r"); } void print_list(struct word_list* list) { puts("("); while(list) { printf(" %s", list->word); list = list->next; } puts(")"); } struct word_list* make_list(FILE* fp, struct word_list* list, long* len) { struct word_list* p; static char buff[BUFSIZ]; long n, linelen; n = 0; if(verbose_mode) fprintf(stderr, "make word list.\n(256 lines per `#')\n"); while(fgets(buff, BUFSIZ, fp) != NULL) { p = (struct word_list *)alloc_memory(sizeof(struct word_list)); linelen = strlen(buff); p->word = (char *)alloc_memory(linelen + 1); memcpy(p->word, buff, linelen + 1); p->next = list; list = p; if(verbose_mode) { if(n % 256 == 0 && n > 0) fprintf(stderr, "#"); } n++; } if(verbose_mode) fprintf(stderr, " done\n"); *len = n; return list; } struct word_list* split_list(struct word_list* list, long list_len, long *len1, long *len2) { long i, n; struct word_list* ret; if(list_len == 1) { *len1 = 1; *len2 = 0; return NULL; } *len1 = list_len / 2; *len2 = list_len - *len1; n = *len1 - 1; for(i = 0; i < n; i++) list = list->next; ret = list->next; list->next = NULL; return ret; } struct word_list* merge(struct word_list* list1, struct word_list* list2) { struct word_list* list; struct word_list* p; if(drand48() < 0.5) { list = list1; list1 = list2; list2 = list; } list = list1; list1 = list1->next; list->next = NULL; while(list1 && list2) { p = list2; list2 = list2->next; p->next = list; list = p; p = list1; list1 = list1->next; p->next = list; list = p; } while(list2) { p = list2; list2 = list2->next; p->next = list; list = p; } while(list1) { p = list1; list1 = list1->next; p->next = list; list = p; } return list; } struct word_list* shake(struct word_list* list, long len) { struct word_list* ret; if(len > 256) { struct word_list* list2; long len1, len2; list2 = split_list(list, len, &len1, &len2); list = shake(list, len1); list2 = shake(list2, len2); return merge(list, list2); } if(verbose_mode) fprintf(stderr, "[%ld]", len); ret = NULL; while(--len >= 0) { long pos; struct word_list* cur; struct word_list* prev; pos = (long)(drand48() * (len + 1)); cur = list; prev = NULL; while(--pos >= 0) { prev = cur; cur = cur->next; } if(prev == NULL) list = list->next; else prev->next = cur->next; cur->next = ret; ret = cur; } return ret; } int main(int argc, char** argv) { struct word_list* list; FILE* fp; long len; extern double drand48(); extern void srand48(); time_t t; time(&t); srand48(t); list = NULL; init_buffer(); if(argc == 1) list = make_list(stdin, list, &len); else { int i = 1; if(!strcmp(argv[1], "-h")) { fprintf(stderr, "%s [-h] [-v]\n", argv[0]); return 0; } else if(!strcmp(argv[1], "-v")) { verbose_mode = 1; if(argc == 2) list = make_list(stdin, list, &len); else { i++; goto each_file; } } else { each_file: len = 0; for(; i < argc; i++) { long n; if((fp = file_open(argv[i])) == NULL) { perror(argv[i]); continue; } if(verbose_mode) fprintf(stderr, "Loading from %s\n", fp == stdin ? "stdin" : argv[i]); list = make_list(fp, list, &n); len += n; if(fp != stdin) fclose(fp); } } } if(verbose_mode) fprintf(stderr, "Total list length: %ld\n", len); list = shake(list, len); while(--len >= 0) { fputs(list->word, stdout); list = list->next; } if(verbose_mode) fprintf(stderr, "\n"); return 0; }