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