BibTeXq
query a bibtex file
|
00001 /* 00002 * This work is licensed under a Creative Commons 00003 * Attribution-Noncommercial-Share Alike 3.0 United States License. 00004 * 00005 * http://creativecommons.org/licenses/by-nc-sa/3.0/us/ 00006 * 00007 * You are free: 00008 * 00009 * to Share - to copy, distribute, display, and perform the work 00010 * to Remix - to make derivative works 00011 * 00012 * Under the following conditions: 00013 * 00014 * Attribution. You must attribute the work in the manner specified by the 00015 * author or licensor (but not in any way that suggests that they endorse you 00016 * or your use of the work). 00017 * 00018 * Noncommercial. You may not use this work for commercial purposes. 00019 * 00020 * Share Alike. If you alter, transform, or build upon this work, you may 00021 * distribute the resulting work only under the same or similar license to 00022 * this one. 00023 * 00024 * For any reuse or distribution, you must make clear to others the license 00025 * terms of this work. The best way to do this is by including this header. 00026 * 00027 * Any of the above conditions can be waived if you get permission from the 00028 * copyright holder. 00029 * 00030 * Apart from the remix rights granted under this license, nothing in this 00031 * license impairs or restricts the author's moral rights. 00032 */ 00033 00034 00072 #include <config.h> 00073 00074 #include <stdlib.h> 00075 #include <stdio.h> 00076 #include <assert.h> 00077 #include <errno.h> 00078 #include <string.h> 00079 #include <strings.h> 00080 #include <regex.h> 00081 00082 #ifdef BIBTEXQ_HAVE_DMALLOC 00083 #include <dmalloc.h> 00084 #endif 00085 00086 #include <jwsc/base/option.h> 00087 #include <jwsc/base/error.h> 00088 00089 #include "bibtex_entry.h" 00090 00091 00092 #define NUM_OPTS_NO_ARG 2 00093 #define NUM_OPTS_WITH_ARG 8 00094 00095 00096 extern FILE* yyin; 00097 extern int yyparse(); 00098 00099 00101 Bibtex_entry* entry = NULL; 00102 00103 00105 static Option_no_arg opts_no_arg[NUM_OPTS_NO_ARG]; 00106 00108 static Option_with_arg opts_with_arg[NUM_OPTS_WITH_ARG]; 00109 00111 static const char* output_fname; 00112 00114 static FILE* output_fp; 00115 00117 static uint8_t query_type; 00118 00120 static uint8_t query_key; 00121 00123 static uint8_t query_author; 00124 00126 static uint8_t query_title; 00127 00129 static uint8_t query_project; 00130 00132 static uint8_t query_venue; 00133 00135 static uint8_t query_keyword; 00136 00138 static regex_t type_preg; 00139 00141 static regex_t key_preg; 00142 00144 static regex_t author_preg; 00145 00147 static regex_t title_preg; 00148 00150 static regex_t project_preg; 00151 00153 static regex_t venue_preg; 00154 00156 static regex_t keyword_preg; 00157 00158 00159 static Error* init_regex(const char* value, regex_t* preg) 00160 { 00161 int errcode; 00162 char errbuf[256] = {0}; 00163 00164 if ((errcode = regcomp(preg, value, REG_EXTENDED | REG_ICASE | REG_NOSUB))) 00165 { 00166 regerror(errcode, preg, errbuf, 255); 00167 return JWSC_EARG(errbuf); 00168 } 00169 return NULL; 00170 } 00171 00173 static void print_usage(void) 00174 { 00175 fprintf(stderr, "usage: bibtexq OPTIONS <file.bib>\n"); 00176 print_options(stderr, 25, NUM_OPTS_NO_ARG, opts_no_arg, NUM_OPTS_WITH_ARG, 00177 opts_with_arg); 00178 } 00179 00181 static Error* process_help_opt(void) 00182 { 00183 print_usage(); 00184 exit(EXIT_SUCCESS); 00185 return NULL; 00186 } 00187 00189 static Error* process_version_opt(void) 00190 { 00191 fprintf(stderr, "%s\n", BIBTEXQ_PACKAGE_STRING); 00192 exit(EXIT_SUCCESS); 00193 return NULL; 00194 } 00195 00197 static Error* process_output_opt(Option_arg arg) 00198 { 00199 if (arg == NULL) 00200 { 00201 return JWSC_EARG("Option 'output' requires an argument"); 00202 } 00203 output_fname = arg; 00204 return NULL; 00205 } 00206 00208 static Error* process_type_opt(Option_arg arg) 00209 { 00210 Error* e; 00211 00212 if (arg == NULL) 00213 { 00214 return JWSC_EARG("Option 'type' requires an argument"); 00215 } 00216 if ((e = init_regex(arg, &type_preg))) 00217 { 00218 return e; 00219 } 00220 query_type = 1; 00221 return NULL; 00222 } 00223 00225 static Error* process_key_opt(Option_arg arg) 00226 { 00227 Error* e; 00228 00229 if (arg == NULL) 00230 { 00231 return JWSC_EARG("Option 'key' requires an argument"); 00232 } 00233 if ((e = init_regex(arg, &key_preg))) 00234 { 00235 return e; 00236 } 00237 query_key = 1; 00238 return NULL; 00239 } 00240 00242 static Error* process_author_opt(Option_arg arg) 00243 { 00244 Error* e; 00245 00246 if (arg == NULL) 00247 { 00248 return JWSC_EARG("Option 'author' requires an argument"); 00249 } 00250 if ((e = init_regex(arg, &author_preg))) 00251 { 00252 return e; 00253 } 00254 query_author = 1; 00255 return NULL; 00256 } 00257 00259 static Error* process_title_opt(Option_arg arg) 00260 { 00261 Error* e; 00262 00263 if (arg == NULL) 00264 { 00265 return JWSC_EARG("Option 'title' requires an argument"); 00266 } 00267 if ((e = init_regex(arg, &title_preg))) 00268 { 00269 return e; 00270 } 00271 query_title = 1; 00272 return NULL; 00273 } 00274 00276 static Error* process_project_opt(Option_arg arg) 00277 { 00278 Error* e; 00279 00280 if (arg == NULL) 00281 { 00282 return JWSC_EARG("Option 'project' requires an argument"); 00283 } 00284 if ((e = init_regex(arg, &project_preg))) 00285 { 00286 return e; 00287 } 00288 query_project = 1; 00289 return NULL; 00290 } 00291 00293 static Error* process_venue_opt(Option_arg arg) 00294 { 00295 Error* e; 00296 00297 if (arg == NULL) 00298 { 00299 return JWSC_EARG("Option 'venue' requires an argument"); 00300 } 00301 if ((e = init_regex(arg, &venue_preg))) 00302 { 00303 return e; 00304 } 00305 query_venue = 1; 00306 return NULL; 00307 } 00308 00310 static Error* process_keyword_opt(Option_arg arg) 00311 { 00312 Error* e; 00313 00314 if (arg == NULL) 00315 { 00316 return JWSC_EARG("Option 'keyword' requires an argument"); 00317 } 00318 if ((e = init_regex(arg, &keyword_preg))) 00319 { 00320 return e; 00321 } 00322 query_keyword = 1; 00323 return NULL; 00324 } 00325 00327 static void init_options(void) 00328 { 00329 uint32_t i; 00330 00331 i = 0; 00332 init_option_no_arg(&(opts_no_arg[i++]), "help", 'h', 00333 "Prints program usage.", process_help_opt); 00334 init_option_no_arg(&(opts_no_arg[i++]), "version", 'v', 00335 "Prints program version.", process_version_opt); 00336 00337 i = 0; 00338 init_option_with_arg(&(opts_with_arg[i++]), "output", 'o', 00339 "File to write the queried entries to. Default is to use stdout.", 00340 process_output_opt); 00341 init_option_with_arg(&(opts_with_arg[i++]), "type", '\0', 00342 "Entry type regular expression.", process_type_opt); 00343 init_option_with_arg(&(opts_with_arg[i++]), "key", '\0', 00344 "Unique entry key regular expression.", process_key_opt); 00345 init_option_with_arg(&(opts_with_arg[i++]), "author", '\0', 00346 "Author field regular expression.", process_author_opt); 00347 init_option_with_arg(&(opts_with_arg[i++]), "title", '\0', 00348 "Title field regular expression.", process_title_opt); 00349 init_option_with_arg(&(opts_with_arg[i++]), "project", '\0', 00350 "Project field regular expression.", process_project_opt); 00351 init_option_with_arg(&(opts_with_arg[i++]), "venue", '\0', 00352 "Venue field regular expression.", process_venue_opt); 00353 init_option_with_arg(&(opts_with_arg[i++]), "keyword", '\0', 00354 "Keyword field regular expression.", process_keyword_opt); 00355 } 00356 00357 00358 00367 void query_bibtex_entry(Bibtex_entry* entry) 00368 { 00369 uint32_t i; 00370 uint8_t match; 00371 uint8_t queried_author; 00372 uint8_t queried_title; 00373 uint8_t queried_project; 00374 uint8_t queried_venue; 00375 uint8_t queried_keyword; 00376 Bibtex_field* field; 00377 00378 match = 1; 00379 queried_author = 0; 00380 queried_title = 0; 00381 queried_project = 0; 00382 queried_venue = 0; 00383 queried_keyword = 0; 00384 00385 if (match && query_type) 00386 { 00387 if (regexec(&type_preg, entry->type, 0, 0, 0) 00388 == REG_NOMATCH) 00389 { 00390 match = 0; 00391 } 00392 } 00393 00394 if (match && query_key) 00395 { 00396 if (regexec(&key_preg, entry->key, 0, 0, 0) 00397 == REG_NOMATCH) 00398 { 00399 match = 0; 00400 } 00401 } 00402 00403 for (i = 0; match && i < entry->num_fields; i++) 00404 { 00405 field = entry->fields[ i ]; 00406 00407 if (match && query_author && strcasecmp(field->name, "author") == 0) 00408 { 00409 queried_author = 1; 00410 if (regexec(&author_preg, (const char*)field->value, 00411 0, 0, 0) == REG_NOMATCH) 00412 { 00413 match = 0; 00414 } 00415 } 00416 00417 if (match && query_title && strcasecmp(field->name, "title") == 0) 00418 { 00419 queried_title = 1; 00420 if (regexec(&title_preg, (const char*)field->value, 00421 0, 0, 0) == REG_NOMATCH) 00422 { 00423 match = 0; 00424 } 00425 } 00426 00427 if (match && query_project && strcasecmp(field->name, "projects") == 0) 00428 { 00429 queried_project = 1; 00430 if (regexec(&project_preg, (const char*)field->value, 00431 0, 0, 0) == REG_NOMATCH) 00432 { 00433 match = 0; 00434 } 00435 } 00436 00437 if (match && query_venue && strcasecmp(field->name, "venue") == 0) 00438 { 00439 queried_venue = 1; 00440 if (regexec(&venue_preg, (const char*)field->value, 00441 0, 0, 0) == REG_NOMATCH) 00442 { 00443 match = 0; 00444 } 00445 } 00446 00447 if (match && query_keyword && strcasecmp(field->name, "keywords") == 0) 00448 { 00449 queried_keyword = 1; 00450 if (regexec(&keyword_preg, (const char*)field->value, 00451 0, 0, 0) == REG_NOMATCH) 00452 { 00453 match = 0; 00454 } 00455 } 00456 } 00457 00458 if ((query_author && !queried_author ) || 00459 (query_title && !queried_title ) || 00460 (query_project && !queried_project) || 00461 (query_venue && !queried_venue ) || 00462 (query_keyword && !queried_keyword)) 00463 { 00464 match = 0; 00465 } 00466 00467 if (match) 00468 { 00469 write_bibtex_entry(entry, output_fp); 00470 } 00471 } 00472 00473 00474 00476 int main(int argc, const char** argv) 00477 { 00478 int argi; 00479 const char* bibtex_fname; 00480 Error* e; 00481 00482 init_options(); 00483 00484 output_fp = stdout; 00485 query_type = 0; 00486 query_key = 0; 00487 query_author = 0; 00488 query_title = 0; 00489 query_project = 0; 00490 query_venue = 0; 00491 query_keyword = 0; 00492 00493 if ((e = process_options(argc, argv, &argi, NUM_OPTS_NO_ARG, opts_no_arg, 00494 NUM_OPTS_WITH_ARG, opts_with_arg)) != NULL) 00495 { 00496 print_error_msg_exit("bibtexq", e->msg); 00497 } 00498 00499 if (output_fname && (output_fp = fopen(output_fname, "w")) == NULL) 00500 { 00501 print_error_msg("bibtexq", NULL); 00502 print_error_msg_exit(output_fname, strerror(errno)); 00503 } 00504 00505 if ((argc - argi) < 1) 00506 { 00507 print_error_msg_exit("bibtexq", "No BIBTEX file to query"); 00508 } 00509 bibtex_fname = argv[ argi ]; 00510 00511 if ((yyin = fopen(bibtex_fname, "r")) == NULL) 00512 { 00513 print_error_msg("bibtexq", NULL); 00514 print_errno_exit(bibtex_fname); 00515 } 00516 00517 yyparse(); 00518 00519 if (output_fp != stdout) 00520 { 00521 if (fclose(output_fp) != 0) 00522 { 00523 print_error_msg("bibtexq", NULL); 00524 print_errno_exit("output file"); 00525 } 00526 } 00527 00528 fclose(yyin); 00529 00530 free_bibtex_entry(entry); 00531 00532 return EXIT_SUCCESS; 00533 }