1 /* do a rot13 of ASCII text */
2 
3 #include "ex_utils.h"
4 
5 #define CONF_USE_MMAP_DEF FALSE
6 
7 /* configuration:
8    how to do it ... */
9 #define EX_ROT13_USE_ITER        1
10 #define EX_ROT13_USE_EXPORT_CHR  0
11 #define EX_ROT13_USE_SUB_CHR     0
12 #define EX_ROT13_USE_CSTR_MALLOC 0
13 
14 #define ROT13_LETTER(x) ( \
15  (((x) >= 'A' && (x) <= 'M') || \
16   ((x) >= 'a' && (x) <= 'm')) ? ((x) + 13) : ((x) - 13) \
17  )
18 
19 #if 0
20 #define ROT13_MAP(x) ( \
21  ((((x) >= 'A') && ((x) <= 'Z')) || \
22   (((x) >= 'a') && ((x) <= 'z'))) ? ROT13_LETTER(x) : (x) \
23  )
24 #else
25 static char rot13_map[] = {
26  1*   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
27  1*  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
28  1*  32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
29  1*  48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
30  1*  64, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 65, 66,
31  1*  67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 91, 92, 93, 94, 95,
32  1*  96,110,111,112,113,114,115,116,117,118,119,120,121,122, 97, 98,
33  1*  99,100,101,102,103,104,105,106,107,108,109,123,124,125,126,127,
34  1* 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
35  1* 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
36  1* 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
37  1* 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
38  1* 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
39  1* 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
40  1* 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
41  1* 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255};
42 #define ROT13_MAP(x) rot13_map[(unsigned char)(x)]
43 #endif
44 
ex_rot13_process(Vstr_base * s1,Vstr_base * s2)45 static int ex_rot13_process(Vstr_base *s1, Vstr_base *s2)
46 {
47   size_t count = 0;
48   static const char chrs[] = ("abcdefghijklmnopqrstuvwxyz"
49                               "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
50 
51   /* we don't want to create more data, if we are over our limit */
52   if (s1->len > EX_MAX_W_DATA_INCORE)
53     return (FALSE);
54 
55   if (!s2->len)
56     return (FALSE);
57 
58   if (EX_ROT13_USE_ITER)
59   {
60     Vstr_iter iter[1];
61 
62     if (!vstr_iter_fwd_beg(s2, 1, s2->len, iter))
63       abort();
64 
65     do
66     {
67       unsigned int scan = 0;
68       while (scan < iter->len)
69       {
70         char tmp = ROT13_MAP(iter->ptr[scan]);
71         vstr_add_rep_chr(s1, s1->len, tmp, 1);
72         ++scan;
73       }
74     } while (vstr_iter_fwd_nxt(iter));
75 
76     vstr_del(s2, 1, s2->len);
77   }
78 
79   if (EX_ROT13_USE_EXPORT_CHR)
80   {
81     unsigned int scan = 0;
82     while (scan++ < s2->len)
83     {
84       char tmp = vstr_export_chr(s2, scan);
85       tmp = ROT13_MAP(tmp);
86       vstr_add_rep_chr(s1, s1->len, tmp, 1);
87     }
88     vstr_del(s2, 1, s2->len);
89   }
90 
91   if (EX_ROT13_USE_SUB_CHR)
92   {
93     unsigned int scan = 0;
94 
95     while (scan++ < s2->len)
96     {
97       char tmp = vstr_export_chr(s2, scan);
98       tmp = ROT13_MAP(tmp);
99       vstr_sub_rep_chr(s2, scan, 1, tmp, 1);
100     }
101     vstr_add_vstr(s1, s1->len, s2, 1, s2->len,
102                   VSTR_TYPE_ADD_BUF_REF);
103     vstr_del(s2, 1, s2->len);
104   }
105 
106   if (EX_ROT13_USE_CSTR_MALLOC)
107   while (s2->len)
108   {
109     if ((count = VSTR_CSPN_CSTR_CHRS_FWD(s2, 1, s2->len, chrs)))
110     {
111       vstr_add_vstr(s1, s1->len, s2, 1, count,
112                     VSTR_TYPE_ADD_BUF_REF);
113       vstr_del(s2, 1, count);
114 
115       if (s1->len > EX_MAX_W_DATA_INCORE)
116         return (TRUE);
117     }
118 
119     if ((count = VSTR_SPN_CSTR_CHRS_FWD(s2, 1, s2->len, chrs)))
120     {
121       char *ptr = vstr_export_cstr_malloc(s2, 1, count);
122       Vstr_ref *ref = vstr_ref_make_ptr(ptr, vstr_ref_cb_free_ptr_ref);
123 
124       if (!ref || !ref->ptr)
125         errno = ENOMEM, err(EXIT_FAILURE, "vstr_make_conf");
126 
127       while (*ptr)
128       {
129         *ptr = ROT13_LETTER(*ptr);
130         ++ptr;
131       }
132 
133       vstr_add_ref(s1, s1->len, ref, 0, count);
134       vstr_del(s2, 1, count);
135     }
136   }
137 
138   return (TRUE);
139 }
140 
ex_rot13_read_fd_write_stdout(Vstr_base * s1,Vstr_base * s2,int fd)141 static void ex_rot13_read_fd_write_stdout(Vstr_base *s1, Vstr_base *s2, int fd)
142 {
143   while (TRUE)
144   {
145     int io_w_state = IO_OK;
146     int io_r_state = io_get(s2, fd);
147 
148     if (io_r_state == IO_EOF)
149       break;
150 
151     ex_rot13_process(s1, s2);
152 
153     io_w_state = io_put(s1, 1);
154 
155     io_limit(io_r_state, fd, io_w_state, 1, s1);
156   }
157 }
158 
ex_rot13_process_limit(Vstr_base * s1,Vstr_base * s2,unsigned int lim)159 static void ex_rot13_process_limit(Vstr_base *s1, Vstr_base *s2,
160                                    unsigned int lim)
161 {
162   while (s2->len > lim)
163   {
164     int proc_data = ex_rot13_process(s1, s2);
165     if (!proc_data && (io_put(s1, STDOUT_FILENO) == IO_BLOCK))
166       io_block(-1, STDOUT_FILENO);
167   }
168 }
169 
main(int argc,char * argv[])170 int main(int argc, char *argv[])
171 {
172   Vstr_base *s1 = NULL;
173   Vstr_base *s2 = ex_init(&s1);
174   int count = 1;
175   int use_mmap = CONF_USE_MMAP_DEF;
176 
177   /* parse command line arguments... */
178   while (count < argc)
179   { /* quick hack getopt_long */
180     if (!strcmp("--", argv[count]))
181     {
182       ++count;
183       break;
184     }
185     else if (!strcmp("--mmap", argv[count])) /* toggle use of mmap */
186       use_mmap = !use_mmap;
187     else if (!strcmp("--version", argv[count]))
188     { /* print version and exit */
189       vstr_add_fmt(s1, 0, "%s", "\
190 jrot13 1.0.0\n\
191 Written by James Antill\n\
192 \n\
193 Uses Vstr string library.\n\
194 ");
195       goto out;
196     }
197     else if (!strcmp("--help", argv[count]))
198     { /* print version and exit */
199       vstr_add_fmt(s1, 0, "%s", "\
200 Usage: jrot13 [FILENAME]...\n\
201    or: jrot13 OPTION\n\
202 Output filenames.\n\
203 \n\
204       --help     Display this help and exit\n\
205       --version  Output version information and exit\n\
206       --mmap     Toggle use of mmap() to load input files\n\
207       --         Treat rest of cmd line as input filenames\n\
208 \n\
209 Report bugs to James Antill <james@and.org>.\n\
210 ");
211       goto out;
212     }
213     else
214       break;
215     ++count;
216   }
217 
218   if (count >= argc)  /* use stdin */
219   {
220     io_fd_set_o_nonblock(STDIN_FILENO);
221     ex_rot13_read_fd_write_stdout(s1, s2, STDIN_FILENO);
222   }
223 
224   /* loop through all arguments, open the file specified
225    * and do the read/write loop */
226   while (count < argc)
227   {
228     unsigned int ern = 0;
229 
230     if (use_mmap)
231       vstr_sc_mmap_file(s2, s2->len, argv[count], 0, 0, &ern);
232 
233     if (!use_mmap ||
234         (ern == VSTR_TYPE_SC_MMAP_FILE_ERR_FSTAT_ERRNO) ||
235         (ern == VSTR_TYPE_SC_MMAP_FILE_ERR_MMAP_ERRNO) ||
236         (ern == VSTR_TYPE_SC_MMAP_FILE_ERR_TOO_LARGE))
237     {
238       int fd = io_open(argv[count]);
239 
240       ex_rot13_read_fd_write_stdout(s1, s2, fd);
241 
242       if (close(fd) == -1)
243         warn("close(%s)", argv[count]);
244     }
245     else if (ern && (ern != VSTR_TYPE_SC_MMAP_FILE_ERR_CLOSE_ERRNO))
246       err(EXIT_FAILURE, "add");
247     else
248       ex_rot13_process_limit(s1, s2, EX_MAX_R_DATA_INCORE);
249 
250     ++count;
251   }
252 
253   ex_rot13_process_limit(s1, s2, 0);
254 
255  out:
256   io_put_all(s1, STDOUT_FILENO);
257 
258   exit (ex_exit(s1, s2));
259 }
260