1 /* this program shows all possible names for given numbers */
2 
3 #include "ex_utils.h"
4 #include <limits.h>
5 
6 
7 static char phone_state[CHAR_MAX] = {
8  ['2'] = 'a',
9  ['a'] = 'b',
10  ['b'] = 'c',
11  ['c'] = '2',
12 
13  ['3'] = 'd',
14  ['d'] = 'e',
15  ['e'] = 'f',
16  ['f'] = '3',
17 
18  ['4'] = 'g',
19  ['g'] = 'h',
20  ['h'] = 'i',
21  ['i'] = '4',
22 
23  ['5'] = 'j',
24  ['j'] = 'k',
25  ['k'] = 'l',
26  ['l'] = '5',
27 
28  ['6'] = 'm',
29  ['m'] = 'n',
30  ['n'] = 'o',
31  ['o'] = '6',
32 
33  ['7'] = 'p',
34  ['p'] = 'r',
35  ['r'] = 's',
36  ['s'] = '7',
37 
38  ['8'] = 't',
39  ['t'] = 'u',
40  ['u'] = 'v',
41  ['v'] = '8',
42 
43  ['9'] = 'w',
44  ['w'] = 'x',
45  ['x'] = 'y',
46  ['y'] = 'z',
47  ['z'] = '9',
48 };
49 
50 
51 #define xisdigit(x) (((x) >= '2') && ((x) <= '9'))
52 
prnt_phone_name(Vstr_base * s1,Vstr_base * s2,size_t pos,size_t len,Vstr_sects * sects,unsigned int off)53 static int prnt_phone_name(Vstr_base *s1,
54                            Vstr_base *s2, size_t pos, size_t len,
55                            Vstr_sects *sects, unsigned int off)
56 {
57   size_t cpos = 0;
58   char chr = 0;
59   char nxt_chr = 0;
60 
61   if (off > sects->num)
62     return (FALSE);
63 
64   cpos = VSTR_SECTS_NUM(sects, off)->pos;
65   chr = vstr_export_chr(s2, cpos);
66   nxt_chr = phone_state[(unsigned char) chr];
67 
68   vstr_sub_rep_chr(s2, cpos, 1, nxt_chr, 1);
69   if (xisdigit(nxt_chr))
70   {
71     if (!prnt_phone_name(s1, s2, pos, len, sects, off + 1))
72       return (FALSE);
73   }
74 
75   return (TRUE);
76 }
77 
split_num(Vstr_sects * sects,Vstr_base * s2,size_t pos,size_t len)78 static void split_num(Vstr_sects *sects, Vstr_base *s2, size_t pos, size_t len)
79 {
80   Vstr_iter iter[1];
81 
82   if (!vstr_iter_fwd_beg(s2, pos, len, iter))
83     err(EXIT_FAILURE, "INTERNAL ERROR");
84 
85   while (len--)
86   {
87     char chr = vstr_iter_fwd_chr(iter, NULL);
88 
89     if (xisdigit(chr))
90       vstr_sects_add(sects, pos, 1);
91 
92     ++pos;
93   }
94 }
95 
96 #define PRNT_LOOP_NAMES() do {                                          \
97                                                                         \
98       while (prnt_phone_name(s1, s2, 1, llen, sects, 1))                \
99       {                                                                 \
100         ret = TRUE;                                                     \
101                                                                         \
102         vstr_add_vstr(s1, s1->len, s2, 1, llen, VSTR_TYPE_ADD_DEF);     \
103         if (s1->len > EX_MAX_W_DATA_INCORE)                             \
104         {                                                               \
105           if (sects->malloc_bad || s1->conf->malloc_bad)                \
106             errno = ENOMEM, err(EXIT_FAILURE, "adding data");           \
107                                                                         \
108           return (ret);                                                 \
109         }                                                               \
110       }                                                                 \
111                                                                         \
112       if (sects->malloc_bad || s1->conf->malloc_bad)                    \
113         errno = ENOMEM, err(EXIT_FAILURE, "adding data");               \
114                                                                         \
115       vstr_del(s2, 1, llen);                                            \
116       llen = 0;                                                         \
117       if (!s2->len)                                                     \
118       {                                                                 \
119         vstr_sects_free(sects);                                         \
120         sects = NULL;                                                   \
121       }                                                                 \
122 } while (FALSE)
123 
ex_phones_name_process(Vstr_base * s1,Vstr_base * s2,int last)124 static int ex_phones_name_process(Vstr_base *s1, Vstr_base *s2, int last)
125 {
126   static Vstr_sects *sects = NULL;
127   static size_t llen = 0;
128   int ret = FALSE;
129 
130   /* we don't want to create more data, if we are over our limit */
131   if (s1->len > EX_MAX_W_DATA_INCORE)
132     return (FALSE);
133 
134   if (llen)
135   {
136     assert(sects);
137 
138     PRNT_LOOP_NAMES();
139   }
140 
141   if (!s2->len)
142     return (ret);
143 
144   while ((llen = vstr_srch_chr_fwd(s2, 1, s2->len, '\n')))
145   {
146     if (!sects && !(sects = vstr_sects_make(llen - 1)))
147       errno = ENOMEM, err(EXIT_FAILURE, "adding data");
148 
149     split_num(sects, s2, 1, llen);
150     PRNT_LOOP_NAMES();
151   }
152 
153   if (s2->len && last)
154   {
155     llen = s2->len + 1;
156     if (!vstr_add_cstr_buf(s2, s2->len, "\n") &&
157         !sects && !(sects = vstr_sects_make(s2->len - 1)))
158       errno = ENOMEM, err(EXIT_FAILURE, "adding data");
159 
160     ret = TRUE;
161 
162     split_num(sects, s2, 1, llen);
163     PRNT_LOOP_NAMES();
164   }
165 
166   vstr_sects_free(sects);
167   sects = NULL;
168 
169   return (ret);
170 }
171 
172 /* files are merged */
ex_phones_name_read_fd_write_stdout(Vstr_base * s1,Vstr_base * s2,int fd)173 static void ex_phones_name_read_fd_write_stdout(Vstr_base *s1, Vstr_base *s2,
174                                                 int fd)
175 {
176   while (TRUE)
177   {
178     int io_w_state = IO_OK;
179     int io_r_state = io_get(s2, fd);
180 
181     if (io_r_state == IO_EOF)
182       break;
183 
184     ex_phones_name_process(s1, s2, FALSE);
185 
186     io_w_state = io_put(s1, 1);
187 
188     io_limit(io_r_state, fd, io_w_state, 1, s1);
189   }
190 }
191 
ex_phones_name_process_limit(Vstr_base * s1,Vstr_base * s2,unsigned int lim)192 static void ex_phones_name_process_limit(Vstr_base *s1, Vstr_base *s2,
193                                          unsigned int lim)
194 {
195   while (s2->len > lim)
196   {
197     int proc_data = ex_phones_name_process(s1, s2, !lim);
198     if (!proc_data && (io_put(s1, STDOUT_FILENO) == IO_BLOCK))
199       io_block(-1, STDOUT_FILENO);
200   }
201 }
202 
203 
main(int argc,char * argv[])204 int main(int argc, char *argv[])
205 {
206   Vstr_base *s2 = NULL;
207   Vstr_base *s1 = ex_init(&s2);
208   int count = 1;
209 
210   /* if no arguments are given just do stdin to stdout */
211   if (count >= argc)
212   {
213     io_fd_set_o_nonblock(STDIN_FILENO);
214     ex_phones_name_read_fd_write_stdout(s1, s2, STDIN_FILENO);
215   }
216 
217   /* loop through all arguments, open the file specified
218    * and do the read/write loop */
219   while (count < argc)
220   {
221     unsigned int ern = 0;
222 
223     if (s2->len <= EX_MAX_R_DATA_INCORE)
224       vstr_sc_mmap_file(s2, s2->len, argv[count], 0, 0, &ern);
225 
226     if ((ern == VSTR_TYPE_SC_MMAP_FILE_ERR_FSTAT_ERRNO) ||
227         (ern == VSTR_TYPE_SC_MMAP_FILE_ERR_MMAP_ERRNO) ||
228         (ern == VSTR_TYPE_SC_MMAP_FILE_ERR_TOO_LARGE))
229     {
230       int fd = io_open(argv[count]);
231 
232       ex_phones_name_read_fd_write_stdout(s1, s2, fd);
233 
234       if (close(fd) == -1)
235         warn("close(%s)", argv[count]);
236     }
237     else if (ern && (ern != VSTR_TYPE_SC_MMAP_FILE_ERR_CLOSE_ERRNO))
238       err(EXIT_FAILURE, "add");
239     else
240       ex_phones_name_process_limit(s1, s2, EX_MAX_R_DATA_INCORE);
241 
242     ++count;
243   }
244 
245   ex_phones_name_process_limit(s1, s2, 0);
246 
247   io_put_all(s1, STDOUT_FILENO);
248 
249   exit (ex_exit(s1, s2));
250 }
251