2 * cep-browser: Address search based on CEP.
4 * A CEP is a sequence of numbers which correspond to a specific
5 * address. It's the system of postal codes used by the Correios
6 * (Brazil's Postal Service).
8 * This program supports more than one data structure to store
9 * and search the addresses, it can be used to experiment
10 * different data structures and algorithms.
12 * This program is lincesed under the GPLv2, see COPYING for
15 * Luiz Fernando N. Capitulino
16 * <lcapitulino@gmail.com>
32 /* module being used */
33 static struct module
*cep_module
;
35 /* usage(): print usage info */
36 static void usage(void)
39 "usage: cep-browser [options] < file >\n\n"
42 " -l use list module\n"
43 " -a use AVL tree module\n"
44 " -b use BST tree module\n"
45 " -A use AA tree module\n"
46 " -D dump the database using choosen module\n"
47 " -r raw database dump\n"
48 " -t run test for selected data structure\n"
53 /* cep_compare(): return -1 if key1 < key2, 1 if key1 > key2 and
54 * 0 if key1 == key2. Where key is the struct db_entry and what
55 * gets compared is its cep member */
56 static int cep_compare(const void *key1
, const void *key2
)
58 const struct db_entry
*entry1
, *entry2
;
60 entry1
= (const struct db_entry
*) key1
;
61 entry2
= (const struct db_entry
*) key2
;
63 if (entry1
->cep
< entry2
->cep
)
65 else if (entry1
->cep
> entry2
->cep
)
70 /* cep_destroy(): wrapper to db_free_entry() which can be used by
71 * the module's destroy function */
72 static void cep_destroy(void *data
)
74 struct db_entry
*entry
;
76 entry
= (struct db_entry
*) data
;
77 db_free_entry(&entry
);
80 /* cep_dump(): wrapper for db_dump_entry() which can be used by
81 the module's dump function */
82 static void cep_dump(const void *data
)
84 db_dump_entry((const struct db_entry
*) data
);
89 * cep_is_duplicated(): return a positive integer if 'cep' is
90 * in the duplicated list, otherwise return 0.
92 * This function should only be used in do_test().
94 * The problem here is that the Brazil's full CEP list file has
95 * some entries which have the same CEP number for different
96 * addresses, but the module's insert() function will only insert
97 * the first occurence of the duplicated entry, silently ignoring
100 * This can make the do_test() function fail because there won't
101 * be a match for the sencond entry.
103 * So we just ignore duplicated CEPs in do_test().
107 static inline int cep_is_duplicated(int cep
)
123 /* do_test(): run a simple test to assure that basic functionality
124 * is working. The test resets the database file and does a lookup()
125 * for each CEP in the file. */
126 static void do_test(FILE *db
)
130 struct db_entry
*entry
;
134 printf("%s LOOKUP TEST: ", cep_module
->mod_name
);
138 entry
= db_next_entry(db
);
142 if (cep_is_duplicated(entry
->cep
))
145 ret
= cep_module
->mod_lookup((void *) &entry
->cep
);
148 if (ret
&& !db_entries_match(entry
, (struct db_entry
*) ret
))
151 db_free_entry(&entry
);
160 /* user_command(): executes a command entered by the user in the
161 * interactive shell. Return 1 if the command was executed or
162 * 0 if the command doesn't exist. */
163 static int user_command(const char *cmd
)
165 if (!strcmp(cmd
, "size")) {
166 printf("%d\n", cep_module
->mod_size());
173 static int eof_input(FILE *stream
, char c
)
177 return (c
== '\n' ? 1 : 0);
180 static char *user_shell(const char *prompt
)
182 printf("%s", prompt
);
183 return read_chars(stdin
, eof_input
);
186 int main(int argc
, char *argv
[])
189 struct db_entry
*entry
;
190 int opt
, verbose
, raw_dump
, dump
, run_test
;
193 raw_dump
= dump
= run_test
= verbose
= 0;
195 while ((opt
= getopt(argc
, argv
, "hlAabrDtv")) != -1 ) {
201 cep_module
= &list_module
;
204 cep_module
= &avl_module
;
207 cep_module
= &aa_module
;
210 cep_module
= &bst_module
;
231 fatal("you have to specify a filename");
233 if ((dump
&& !cep_module
) || (!cep_module
&& !raw_dump
))
234 fatal("you have to select a module");
236 if (cep_module
&& raw_dump
)
237 fatal("you can't use a module to do raw database dump");
239 db
= fopen(argv
[optind
], "r");
241 fatal("can't open file '%s': %s", argv
[optind
],
252 * Setup done, here we go
255 cep_module
->mod_init(cep_compare
, cep_destroy
, cep_dump
);
260 /* read all entries */
262 entry
= db_next_entry(db
);
266 cep_module
->mod_insert((void *) entry
);
269 printf("-> reading entries: %d\r",
270 cep_module
->mod_size());
275 if (cep_module
->mod_dump
== NULL
) {
276 fatal("module '%s' doesn't support database dump",
277 cep_module
->mod_name
);
281 fatal("you can't run the test if you want to dump "
285 cep_module
->mod_dump();
300 printf("\n-> using %s module [ with %d entries ]\n\n",
301 cep_module
->mod_name
, cep_module
->mod_size());
308 line
= user_shell(">>> ");
314 if (line
[0] == '\0') {
319 if (user_command(line
)) {
324 cep
= strtol(line
, NULL
, 10);
326 data
= cep_module
->mod_lookup((void *) &cep
);
328 db_print_entry((struct db_entry
*) data
);
330 printf("%s: not found\n", line
);
336 if (cep_module
->mod_destroy
)
337 cep_module
->mod_destroy();