Use STDERR for errors consistently in scramble.c
[filters.git] / scramble.c
CommitLineData
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 */
32char *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 */
47char *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
59int 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 */
77char *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
109char *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
121int 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}
This page took 0.022345 seconds and 4 git commands to generate.