/* * shuffle.c - source code for shuffle binary. * * Copyright 2009 by Paul Jungwirth */ #include #include #include #include struct line { char *text; struct line* next; }; /* void print_lines(struct line *first) { while (first != NULL) { printf("%s", first->text); first = first->next; } } */ void help(int err) { fprintf(stderr, "USAGE: shuffle [inputs]\n"); exit(err); } struct line* add_line(struct line *last) { struct line* ret; ret = malloc(sizeof(struct line)); if (last != NULL) last->next = ret; return ret; } char *read_line(FILE *f) { // fills a buffer using gets, then returns the whole line. size_t buflen; char *tmp, *ret; ssize_t len; tmp = NULL; len = getline(&tmp, &buflen, f); if (len == -1) { if (feof(f)) { clearerr(f); return NULL; } else { perror("shuffle"); exit(1); } } // puts(tmp); // tmp already contains both \n (if present) and \0 after getline ret = malloc(sizeof(char) * (len+1)); if (ret == NULL) help(1); strncpy(ret, tmp, len); ret[len] = '\0'; // free(tmp); return ret; /* MacOS X: size_t len; char *tmp, *ret; tmp = fgetln(f, &len); if (tmp == NULL) { if (feof(f)) { clearerr(f); return NULL; } else { perror("shuffle"); exit(1); } } // now copy tmp into a real string so we can reuse it (and append \0). ret = malloc(sizeof(char) * (len+1)); if (ret == NULL) help(1); strncpy(ret, tmp, len); ret[len] = '\0'; // printf("r: %x\n", ret); return ret; */ } void shuffle(char **lines, int len) { int i; char *tmp; // Fisher-Yates shuffle while (--len) { i = random() % (len+1); tmp = lines[len]; lines[len] = lines[i]; lines[i] = tmp; } } void print_lines(char **lines, int len) { int i; for (i = 0; i < len; i++) { printf("%s", lines[i]); } } char **to_array(struct line* first, int lines) { char **ret, **cur; cur = ret = malloc(sizeof(char *) * lines); // printf("A: %x\n", ret); if (ret == NULL) return NULL; while (first != NULL) { *cur = first->text; // printf("a: %x\n", *cur); cur++; first = first->next; } return ret; } int main(int argc, char **argv) { // If there are arguments, open each one as a file; otherwise read from stdin. // Once everything is read into an array, shuffle it. // Print it to stdout. struct line* first; struct line* last; char **line_array; int lines = 0; char* text; int i; FILE *f; // TODO: permit -h or -? options to display help srandom(time(NULL)); // srandomdev(); // for mac last = first = add_line(NULL); // Don't store any text in first; it's just to simplify the loop. if (first == NULL) help(1); if (argc > 1) { for (i = 1; i < argc; i++) { f = fopen(argv[i], "r"); if (f == NULL) { perror("shuffle"); help(1); } while ((text = read_line(f)) != NULL) { if(!add_line(last)) help(1); last = last->next; last->text = text; lines++; } fclose(f); } } else { while ((text = read_line(stdin)) != NULL) { if(!add_line(last)) help(1); last = last->next; last->text = text; lines++; } } // puts("FINISHED READING"); if (lines > 0) { // convert the linked list into an array of char*s to make shuffling easier. line_array = to_array(first->next, lines); if (line_array == NULL) help(1); // now shuffle shuffle(line_array, lines); // print_lines(first->next); print_lines(line_array, lines); } return 0; }