]>
Commit | Line | Data |
---|---|---|
001ffaa6 JH |
1 | /* Scramble the "inner" letters of each word in the input into a random order, and output the result. Non-word (that is, non-alphabetical) characters, and the first and last letters of each word, are left alone. |
2 | * Output to something other than stdout will append to the file instead of overwriting it - this may be undesirable, and can be changed if so. | |
3 | */ | |
4 | ||
5 | /* Copyright 2009-07-11 Andrew J. Buehler. | |
6 | */ | |
7 | ||
8 | /* This program is free software: you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License as published by | |
10 | * the Free Software Foundation, either version 3 of the License, or | |
11 | * (at your option) any later version. | |
12 | * This program is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
18 | */ | |
19 | ||
20 | #include <stdio.h> | |
21 | #include <ctype.h> // for isalpha() | |
22 | #include <stdlib.h> // for malloc()/calloc()/realloc()/free() and rand()/srand() | |
23 | #include <string.h> // for strlen() | |
24 | #include <time.h> // for time() | |
25 | ||
a49d78a9 | 26 | #define ALLOW_FILE_IO 0 |
001ffaa6 JH |
27 | |
28 | ||
29 | /* strips 'reduction' characters from the end of the input string and returns the result | |
30 | * works only if strlen(string> >= reduction, which is the case in the only place it is presently called | |
31 | */ | |
32 | char *shorten_string(char *string, int reduction) { | |
33 | int i; | |
34 | ||
35 | i = strlen(string); | |
36 | ||
37 | for (; reduction > 0; reduction--, i--) { | |
38 | string[i-1] = '\0'; // would it work to use an 'i-reduction' approach instead, similar to what was later done in narrow_string()? | |
39 | } | |
40 | ||
41 | return string; | |
42 | } | |
43 | ||
44 | /* strips 'reduction' characters from the beginning and the end of the input string and returns the result | |
45 | * works only if(strlen(string) >= 2*reduction), which is the case in the only place it is presently called | |
46 | */ | |
47 | char *narrow_string(char *string, int reduction) { | |
48 | int i = reduction; | |
49 | ||
50 | while(string[i]) { | |
51 | string[i-reduction] = string[i]; | |
52 | i++; | |
53 | } | |
54 | string[i-reduction] = '\0'; | |
55 | ||
56 | return shorten_string(string, reduction); | |
57 | } | |
58 | ||
59 | int all_one_letter(char *string) { | |
60 | char c; | |
61 | int i; | |
62 | ||
63 | c = string[0]; | |
64 | for(i = 1; string[i] != '\0'; i++) { | |
65 | if(c != string[i]) { | |
66 | return 0; // a nonduplicate letter has been found | |
67 | } | |
68 | c = string[i]; | |
69 | } | |
70 | ||
71 | return 1; // reached the end of the string having found only duplicate letters, so it's all one letter | |
72 | } | |
73 | ||
74 | /* randomly reorders the contents of the string | |
75 | * WARNING: frees the input string and returns a replacement | |
76 | */ | |
77 | char *scramble_string(char *string) { | |
78 | char *ret, *tmpstr; | |
79 | int len, i, j; | |
80 | ||
81 | len = strlen(string); | |
82 | if(len < 2) return string; // can't scramble a 1-character string or an empty string! | |
83 | if(all_one_letter(string)) return(string); // can't scramble a string which consists entirely of one letter! | |
84 | ||
85 | ret = strdup(string); | |
86 | ||
87 | while(strcmp(string, ret) == 0) { | |
88 | j = 0; | |
89 | tmpstr = strdup(string); | |
90 | while(len > 0) { | |
91 | i = rand() % len; | |
92 | ret[j] = tmpstr[i]; | |
93 | j++; | |
94 | while(tmpstr[i] != '\0') { | |
95 | tmpstr[i] = tmpstr[i+1]; | |
96 | i++; | |
97 | } | |
98 | len--; | |
99 | } | |
100 | free(tmpstr); | |
101 | len = strlen(string); | |
102 | } | |
103 | ||
104 | ||
105 | free(string); | |
106 | return ret; | |
107 | } | |
108 | ||
109 | char *clear_string(char *string) { | |
110 | int i; | |
111 | ||
112 | i = strlen(string); | |
113 | ||
114 | for(; i >= 0 ; i--) { | |
115 | string[i] = '\0'; | |
116 | } | |
117 | ||
118 | return string; | |
119 | } | |
120 | ||
121 | int main(int argc, char **argv) { | |
122 | int word_length; | |
dd1b852e | 123 | char c, tempchar, *word, *rword; |
001ffaa6 JH |
124 | FILE *infile, *outfile; |
125 | ||
126 | #if ALLOW_FILE_IO | |
127 | /* open files, if any other than stdin and stdout */ | |
128 | if(argc > 1) { | |
129 | if(!strcmp(argv[1], "--help") || | |
130 | !strcmp(argv[1], "-h")) { | |
131 | printf("Usage: %s [INPUT_FILENAME] [OUTPUT_FILENAME]\n", argv[0]); | |
132 | printf("If INPUT_FILENAME is omitted or is '-', read from standard input\nIf OUTPUT_FILENAME is omitted or is '-', print to standard output\n"); | |
133 | return 0; | |
134 | } | |
135 | ||
136 | if(strcmp(argv[1], "-")) { | |
137 | infile = fopen(argv[1], "r"); | |
138 | if(infile == NULL) { | |
139 | fprintf(stderr, "Unable to open input file %s for reading\n", argv[1]); | |
140 | return 1; | |
141 | } | |
142 | } else { | |
143 | infile = stdin; | |
144 | } | |
145 | ||
146 | if(argc > 2) { | |
147 | if(strcmp(argv[2], "-")) { | |
148 | outfile = fopen(argv[2], "a"); | |
149 | if(outfile == NULL) { | |
150 | fprintf(stderr, "Unable to open output file %s for writing\n", argv[2]); | |
151 | return 2; | |
152 | } | |
153 | } else { | |
154 | outfile = stdout; | |
155 | } | |
156 | } | |
157 | } else { // no arguments specified | |
158 | infile = stdin; | |
159 | outfile = stdout; | |
160 | } | |
161 | #else | |
162 | infile = stdin; | |
163 | outfile = stdout; | |
164 | #endif | |
165 | ||
166 | srand(time(NULL)); // needed for scramble_string() to actually be random | |
167 | ||
168 | word_length = 0; | |
169 | word = malloc(sizeof(char)); | |
170 | word[0] = '\0'; | |
171 | c = fgetc(infile); | |
172 | ||
173 | if(feof(infile)) { | |
f51e83a2 | 174 | fprintf(stderr, "Reached EOF while reading the first character of the input file!\n"); |
dd1b852e | 175 | free(word); |
001ffaa6 JH |
176 | return 4; |
177 | } | |
178 | ||
179 | while(!feof(infile)) { | |
180 | if(isalpha(c)) { | |
dd1b852e MG |
181 | rword = realloc(word, word_length+2); // one for the new character, one for the null |
182 | if(rword == NULL){ | |
183 | free(word); | |
184 | fprintf(stderr, "Unable to allocate memory\n"); | |
185 | return 5; | |
186 | } | |
187 | word = rword; | |
001ffaa6 JH |
188 | word[word_length] = c; |
189 | word[word_length + 1] = '\0'; // duplicate addition with the next line, but possibly more readable | |
190 | word_length++; | |
191 | } else { | |
192 | if(word_length) { | |
193 | word_length--; | |
194 | fputc(word[0], outfile); | |
195 | if(word_length) { | |
196 | tempchar = word[word_length]; | |
197 | word = scramble_string(narrow_string(word, 1)); | |
198 | fprintf(outfile, "%s", word); | |
199 | fputc(tempchar, outfile); | |
200 | } | |
201 | word = clear_string(word); | |
202 | word_length = 0; | |
203 | } | |
204 | fputc(c, outfile); | |
205 | } | |
206 | fflush(outfile); | |
207 | c = fgetc(infile); | |
208 | } | |
209 | ||
210 | free(word); | |
211 | return 0; | |
212 | } |