libextractor

GNU libextractor
Log | Files | Refs | Submodules | README | LICENSE

extract.c (27868B)


      1 /*
      2      This file is part of libextractor.
      3      Copyright (C) 2002, 2003, 2004, 2005, 2006, 2009, 2012 Vidyut Samanta and Christian Grothoff
      4 
      5      libextractor is free software; you can redistribute it and/or modify
      6      it under the terms of the GNU General Public License as published
      7      by the Free Software Foundation; either version 3, or (at your
      8      option) any later version.
      9 
     10      libextractor is distributed in the hope that it will be useful, but
     11      WITHOUT ANY WARRANTY; without even the implied warranty of
     12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13      General Public License for more details.
     14 
     15      You should have received a copy of the GNU General Public License
     16      along with libextractor; see the file COPYING.  If not, write to the
     17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     18      Boston, MA 02110-1301, USA.
     19 */
     20 /**
     21  * @file main/extract.c
     22  * @brief command-line tool to run GNU libextractor
     23  * @author Christian Grothoff
     24  */
     25 #include "platform.h"
     26 #include "extractor.h"
     27 #include "getopt.h"
     28 #include <signal.h>
     29 
     30 #define YES 1
     31 #define NO 0
     32 
     33 
     34 /**
     35  * Which keyword types should we print?
     36  */
     37 static int *print;
     38 
     39 /**
     40  * How verbose are we supposed to be?
     41  */
     42 static int verbose;
     43 
     44 /**
     45  * Run plugins in-process.
     46  */
     47 static int in_process;
     48 
     49 /**
     50  * Read file contents into memory, then feed them to extractor.
     51  */
     52 static int from_memory;
     53 
     54 #ifndef WINDOWS
     55 /**
     56  * Install a signal handler to ignore SIGPIPE.
     57  */
     58 static void
     59 ignore_sigpipe ()
     60 {
     61   struct sigaction oldsig;
     62   struct sigaction sig;
     63 
     64   memset (&sig, 0, sizeof (struct sigaction));
     65   sig.sa_handler = SIG_IGN;
     66   sigemptyset (&sig.sa_mask);
     67 #ifdef SA_INTERRUPT
     68   sig.sa_flags = SA_INTERRUPT;  /* SunOS */
     69 #else
     70   sig.sa_flags = SA_RESTART;
     71 #endif
     72   if (0 != sigaction (SIGPIPE, &sig, &oldsig))
     73     fprintf (stderr,
     74              "Failed to install SIGPIPE handler: %s\n", strerror (errno));
     75 }
     76 
     77 
     78 #endif
     79 
     80 
     81 /**
     82  * Information about command-line options.
     83  */
     84 struct Help
     85 {
     86   /**
     87    * Single-character option name, '\0' for none.
     88    */
     89   char shortArg;
     90 
     91   /**
     92    * Long name of the option.
     93    */
     94   const char *longArg;
     95 
     96   /**
     97    * Name of the mandatory argument, NULL for no argument.
     98    */
     99   const char *mandatoryArg;
    100 
    101   /**
    102    * Help text for the option.
    103    */
    104   const char *description;
    105 };
    106 
    107 
    108 /**
    109  * Indentation for descriptions.
    110  */
    111 #define BORDER 29
    112 
    113 
    114 /**
    115  * Display help text (--help).
    116  *
    117  * @param general binary name
    118  * @param description program description
    119  * @param opt program options (NULL-terminated array)
    120  */
    121 static void
    122 format_help (const char *general,
    123              const char *description,
    124              const struct Help *opt)
    125 {
    126   size_t slen;
    127   unsigned int i;
    128   ssize_t j;
    129   size_t ml;
    130   size_t p;
    131   char scp[80];
    132   const char *trans;
    133 
    134   printf (_ ("Usage: %s\n%s\n\n"),
    135           gettext (general),
    136           gettext (description));
    137   printf (_ (
    138             "Arguments mandatory for long options are also mandatory for short options.\n"));
    139   slen = 0;
    140   i = 0;
    141   while (NULL != opt[i].description)
    142   {
    143     if (0 == opt[i].shortArg)
    144       printf ("      ");
    145     else
    146       printf ("  -%c, ",
    147               opt[i].shortArg);
    148     printf ("--%s",
    149             opt[i].longArg);
    150     slen = 8 + strlen (opt[i].longArg);
    151     if (NULL != opt[i].mandatoryArg)
    152     {
    153       printf ("=%s",
    154               opt[i].mandatoryArg);
    155       slen += 1 + strlen (opt[i].mandatoryArg);
    156     }
    157     if (slen > BORDER)
    158     {
    159       printf ("\n%*s", BORDER, "");
    160       slen = BORDER;
    161     }
    162     if (slen < BORDER)
    163     {
    164       printf ("%*s", (int) (BORDER - slen), "");
    165       slen = BORDER;
    166     }
    167     trans = gettext (opt[i].description);
    168     ml = strlen (trans);
    169     p = 0;
    170 OUTER:
    171     while (ml - p > 78 - slen)
    172     {
    173       for (j = p + 78 - slen; j>p; j--)
    174       {
    175         if (isspace ( (unsigned char) trans[j]))
    176         {
    177           memcpy (scp,
    178                   &trans[p],
    179                   j - p);
    180           scp[j - p] = '\0';
    181           printf ("%s\n%*s",
    182                   scp,
    183                   BORDER + 2,
    184                   "");
    185           p = j + 1;
    186           slen = BORDER + 2;
    187           goto OUTER;
    188         }
    189       }
    190       /* could not find space to break line */
    191       memcpy (scp,
    192               &trans[p],
    193               78 - slen);
    194       scp[78 - slen] = '\0';
    195       printf ("%s\n%*s",
    196               scp,
    197               BORDER + 2,
    198               "");
    199       slen = BORDER + 2;
    200       p = p + 78 - slen;
    201     }
    202     /* print rest */
    203     if (p < ml)
    204       printf ("%s\n",
    205               &trans[p]);
    206     i++;
    207   }
    208 }
    209 
    210 
    211 /**
    212  * Run --help.
    213  */
    214 static void
    215 print_help ()
    216 {
    217   static struct Help help[] = {
    218     { 'b', "bibtex", NULL,
    219       gettext_noop ("print output in bibtex format") },
    220     { 'g', "grep-friendly", NULL,
    221       gettext_noop (
    222         "produce grep-friendly output (all results on one line per file)") },
    223     { 'h', "help", NULL,
    224       gettext_noop ("print this help") },
    225     { 'i', "in-process", NULL,
    226       gettext_noop ("run plugins in-process (simplifies debugging)") },
    227     { 'm', "from-memory", NULL,
    228       gettext_noop (
    229         "read data from file into memory and extract from memory") },
    230     { 'l', "library", "LIBRARY",
    231       gettext_noop ("load an extractor plugin named LIBRARY") },
    232     { 'L', "list", NULL,
    233       gettext_noop ("list all keyword types") },
    234     { 'n', "nodefault", NULL,
    235       gettext_noop ("do not use the default set of extractor plugins") },
    236     { 'p', "print", "TYPE",
    237       gettext_noop (
    238         "print only keywords of the given TYPE (use -L to get a list)") },
    239     { 'v', "version", NULL,
    240       gettext_noop ("print the version number") },
    241     { 'V', "verbose", NULL,
    242       gettext_noop ("be verbose") },
    243     { 'x', "exclude", "TYPE",
    244       gettext_noop ("do not print keywords of the given TYPE") },
    245     { 0, NULL, NULL, NULL },
    246   };
    247   format_help (_ ("extract [OPTIONS] [FILENAME]*"),
    248                _ ("Extract metadata from files."),
    249                help);
    250 
    251 }
    252 
    253 
    254 #if HAVE_ICONV
    255 #include "iconv.c"
    256 #endif
    257 
    258 /**
    259  * Print a keyword list to a file.
    260  *
    261  * @param cls closure, not used
    262  * @param plugin_name name of the plugin that produced this value;
    263  *        special values can be used (i.e. '<zlib>' for zlib being
    264  *        used in the main libextractor library and yielding
    265  *        meta data).
    266  * @param type libextractor-type describing the meta data
    267  * @param format basic format information about data
    268  * @param data_mime_type mime-type of data (not of the original file);
    269  *        can be NULL (if mime-type is not known)
    270  * @param data actual meta-data found
    271  * @param data_len number of bytes in data
    272  * @return 0 to continue extracting, 1 to abort
    273  */
    274 static int
    275 print_selected_keywords (void *cls,
    276                          const char *plugin_name,
    277                          enum EXTRACTOR_MetaType type,
    278                          enum EXTRACTOR_MetaFormat format,
    279                          const char *data_mime_type,
    280                          const char *data,
    281                          size_t data_len)
    282 {
    283   char *keyword;
    284 #if HAVE_ICONV
    285   iconv_t cd;
    286 #endif
    287   const char *stype;
    288   const char *mt;
    289 
    290   if ( (type >= EXTRACTOR_metatype_get_max ()) ||
    291        (type < 0) )
    292     return 0; /* invalid type */
    293   if (YES != print[type])
    294     return 0;
    295   if (verbose > 3)
    296     fprintf (stdout,
    297              _ ("Found by `%s' plugin:\n"),
    298              plugin_name);
    299   mt = EXTRACTOR_metatype_to_string (type);
    300   stype = (NULL == mt) ? _ ("unknown") : gettext (mt);
    301   switch (format)
    302   {
    303   case EXTRACTOR_METAFORMAT_UNKNOWN:
    304     fprintf (stdout,
    305              _ ("%s - (unknown, %u bytes)\n"),
    306              stype,
    307              (unsigned int) data_len);
    308     break;
    309   case EXTRACTOR_METAFORMAT_UTF8:
    310     if (0 == data_len)
    311       break;
    312 #if HAVE_ICONV
    313     cd = iconv_open (nl_langinfo (CODESET), "UTF-8");
    314     if (((iconv_t) -1) != cd)
    315       keyword = iconv_helper (cd,
    316                               data,
    317                               data_len);
    318     else
    319 #endif
    320     keyword = strdup (data);
    321     if (NULL != keyword)
    322     {
    323       fprintf (stdout,
    324                "%s - %s\n",
    325                stype,
    326                keyword);
    327       free (keyword);
    328     }
    329 #if HAVE_ICONV
    330     if (((iconv_t) -1) != cd)
    331       iconv_close (cd);
    332 #endif
    333     break;
    334   case EXTRACTOR_METAFORMAT_BINARY:
    335     fprintf (stdout,
    336              _ ("%s - (binary, %u bytes)\n"),
    337              stype,
    338              (unsigned int) data_len);
    339     break;
    340   case EXTRACTOR_METAFORMAT_C_STRING:
    341     fprintf (stdout,
    342              "%s - %.*s\n",
    343              stype,
    344              (int) data_len,
    345              data);
    346     break;
    347   default:
    348     break;
    349   }
    350   return 0;
    351 }
    352 
    353 
    354 /**
    355  * Print a keyword list to a file without new lines.
    356  *
    357  * @param cls closure, not used
    358  * @param plugin_name name of the plugin that produced this value;
    359  *        special values can be used (i.e. '<zlib>' for zlib being
    360  *        used in the main libextractor library and yielding
    361  *        meta data).
    362  * @param type libextractor-type describing the meta data
    363  * @param format basic format information about data
    364  * @param data_mime_type mime-type of data (not of the original file);
    365  *        can be NULL (if mime-type is not known)
    366  * @param data actual meta-data found
    367  * @param data_len number of bytes in data
    368  * @return 0 to continue extracting, 1 to abort
    369  */
    370 static int
    371 print_selected_keywords_grep_friendly (void *cls,
    372                                        const char *plugin_name,
    373                                        enum EXTRACTOR_MetaType type,
    374                                        enum EXTRACTOR_MetaFormat format,
    375                                        const char *data_mime_type,
    376                                        const char *data,
    377                                        size_t data_len)
    378 {
    379   char *keyword;
    380 #if HAVE_ICONV
    381   iconv_t cd;
    382 #endif
    383   const char *mt;
    384 
    385   if (YES != print[type])
    386     return 0;
    387   mt = EXTRACTOR_metatype_to_string (type);
    388   if (NULL == mt)
    389     mt = gettext_noop ("unknown");
    390   switch (format)
    391   {
    392   case EXTRACTOR_METAFORMAT_UNKNOWN:
    393     break;
    394   case EXTRACTOR_METAFORMAT_UTF8:
    395     if (0 == data_len)
    396       return 0;
    397     if (verbose > 1)
    398       fprintf (stdout,
    399                "%s: ",
    400                gettext (mt));
    401 #if HAVE_ICONV
    402     cd = iconv_open (nl_langinfo (CODESET), "UTF-8");
    403     if (((iconv_t) -1) != cd)
    404       keyword = iconv_helper (cd,
    405                               data,
    406                               data_len);
    407     else
    408 #endif
    409     keyword = strdup (data);
    410     if (NULL != keyword)
    411     {
    412       fprintf (stdout,
    413                "`%s' ",
    414                keyword);
    415       free (keyword);
    416     }
    417 #if HAVE_ICONV
    418     if (((iconv_t) -1) != cd)
    419       iconv_close (cd);
    420 #endif
    421     break;
    422   case EXTRACTOR_METAFORMAT_BINARY:
    423     break;
    424   case EXTRACTOR_METAFORMAT_C_STRING:
    425     if (verbose > 1)
    426       fprintf (stdout,
    427                "%s ",
    428                gettext (mt));
    429     fprintf (stdout,
    430              "`%.*s'",
    431              (int) data_len,
    432              data);
    433     break;
    434   default:
    435     break;
    436   }
    437   return 0;
    438 }
    439 
    440 
    441 /**
    442  * Entry in the map we construct for each file.
    443  */
    444 struct BibTexMap
    445 {
    446   /**
    447    * Name in bibTeX
    448    */
    449   const char *bibTexName;
    450 
    451   /**
    452    * Meta type for the value.
    453    */
    454   enum EXTRACTOR_MetaType le_type;
    455 
    456   /**
    457    * The value itself.
    458    */
    459   char *value;
    460 };
    461 
    462 
    463 /**
    464  * Type of the entry for bibtex.
    465  */
    466 static char *entry_type;
    467 
    468 /**
    469  * Mapping between bibTeX strings, libextractor
    470  * meta data types and values for the current document.
    471  */
    472 static struct BibTexMap btm[] = {
    473   { "title", EXTRACTOR_METATYPE_TITLE, NULL},
    474   { "year", EXTRACTOR_METATYPE_PUBLICATION_YEAR, NULL },
    475   { "author", EXTRACTOR_METATYPE_AUTHOR_NAME, NULL },
    476   { "book", EXTRACTOR_METATYPE_BOOK_TITLE, NULL},
    477   { "edition", EXTRACTOR_METATYPE_BOOK_EDITION, NULL},
    478   { "chapter", EXTRACTOR_METATYPE_BOOK_CHAPTER_NUMBER, NULL},
    479   { "journal", EXTRACTOR_METATYPE_JOURNAL_NAME, NULL},
    480   { "volume", EXTRACTOR_METATYPE_JOURNAL_VOLUME, NULL},
    481   { "number", EXTRACTOR_METATYPE_JOURNAL_NUMBER, NULL},
    482   { "pages", EXTRACTOR_METATYPE_PAGE_COUNT, NULL },
    483   { "pages", EXTRACTOR_METATYPE_PAGE_RANGE, NULL },
    484   { "school", EXTRACTOR_METATYPE_AUTHOR_INSTITUTION, NULL},
    485   { "publisher", EXTRACTOR_METATYPE_PUBLISHER, NULL },
    486   { "address", EXTRACTOR_METATYPE_PUBLISHER_ADDRESS, NULL },
    487   { "institution", EXTRACTOR_METATYPE_PUBLISHER_INSTITUTION, NULL },
    488   { "series", EXTRACTOR_METATYPE_PUBLISHER_SERIES, NULL},
    489   { "month", EXTRACTOR_METATYPE_PUBLICATION_MONTH, NULL },
    490   { "url", EXTRACTOR_METATYPE_URL, NULL},
    491   { "note", EXTRACTOR_METATYPE_COMMENT, NULL},
    492   { "eprint", EXTRACTOR_METATYPE_BIBTEX_EPRINT, NULL },
    493   { "type", EXTRACTOR_METATYPE_PUBLICATION_TYPE, NULL },
    494   { NULL, 0, NULL }
    495 };
    496 
    497 
    498 /**
    499  * Clean up the bibtex processor in preparation for the next round.
    500  */
    501 static void
    502 cleanup_bibtex ()
    503 {
    504   unsigned int i;
    505 
    506   for (i = 0; NULL != btm[i].bibTexName; i++)
    507   {
    508     free (btm[i].value);
    509     btm[i].value = NULL;
    510   }
    511   free (entry_type);
    512   entry_type = NULL;
    513 }
    514 
    515 
    516 /**
    517  * Callback function for printing meta data in bibtex format.
    518  *
    519  * @param cls closure, not used
    520  * @param plugin_name name of the plugin that produced this value;
    521  *        special values can be used (i.e. '<zlib>' for zlib being
    522  *        used in the main libextractor library and yielding
    523  *        meta data).
    524  * @param type libextractor-type describing the meta data
    525  * @param format basic format information about data
    526  * @param data_mime_type mime-type of data (not of the original file);
    527  *        can be NULL (if mime-type is not known)
    528  * @param data actual meta-data found
    529  * @param data_len number of bytes in data
    530  * @return 0 to continue extracting (always)
    531  */
    532 static int
    533 print_bibtex (void *cls,
    534               const char *plugin_name,
    535               enum EXTRACTOR_MetaType type,
    536               enum EXTRACTOR_MetaFormat format,
    537               const char *data_mime_type,
    538               const char *data,
    539               size_t data_len)
    540 {
    541   if (0 == data_len)
    542     return 0;
    543   if (YES != print[type])
    544     return 0;
    545   if (EXTRACTOR_METAFORMAT_UTF8 != format)
    546     return 0;
    547   if (EXTRACTOR_METATYPE_BIBTEX_ENTRY_TYPE == type)
    548   {
    549     entry_type = strndup (data,
    550                           data_len);
    551     return 0;
    552   }
    553   for (unsigned int i = 0;
    554        NULL != btm[i].bibTexName;
    555        i++)
    556     if ( (NULL == btm[i].value) &&
    557          (btm[i].le_type == type) )
    558       btm[i].value = strndup (data,
    559                               data_len);
    560   return 0;
    561 }
    562 
    563 
    564 /**
    565  * Print the computed bibTeX entry.
    566  *
    567  * @param fn file for which the entry was created.
    568  */
    569 static void
    570 finish_bibtex (const char *fn)
    571 {
    572   ssize_t n;
    573   const char *et;
    574   char temp[20];
    575 
    576   if (NULL != entry_type)
    577     et = entry_type;
    578   else
    579     et = "misc";
    580   if ( (NULL == btm[0].value) ||
    581        (NULL == btm[1].value) ||
    582        (NULL == btm[2].value) )
    583     fprintf (stdout,
    584              "@%s %s { ",
    585              et,
    586              fn);
    587   else
    588   {
    589     snprintf (temp,
    590               sizeof (temp),
    591               "%.5s%.5s%.5s",
    592               btm[2].value,
    593               btm[1].value,
    594               btm[0].value);
    595     for (n = strlen (temp) - 1; n>=0; n--)
    596       if (! isalnum ( (unsigned char) temp[n]) )
    597         temp[n] = '_';
    598       else
    599         temp[n] = tolower ( (unsigned char) temp[n]);
    600     fprintf (stdout,
    601              "@%s %s { ",
    602              et,
    603              temp);
    604   }
    605   for (unsigned int i = 0; NULL != btm[i].bibTexName; i++)
    606     if (NULL != btm[i].value)
    607       fprintf (stdout,
    608                "\t%s = {%s},\n",
    609                btm[i].bibTexName,
    610                btm[i].value);
    611   fprintf (stdout,
    612            "%s",
    613            "}\n\n");
    614 }
    615 
    616 
    617 #ifdef WINDOWS
    618 static int
    619 _wchar_to_str (const wchar_t *wstr,
    620                char **retstr,
    621                UINT cp)
    622 {
    623   char *str;
    624   int len, lenc;
    625   BOOL lossy = FALSE;
    626   DWORD error;
    627 
    628   SetLastError (0);
    629   len = WideCharToMultiByte (cp,
    630                              0,
    631                              wstr,
    632                              -1,
    633                              NULL,
    634                              0,
    635                              NULL,
    636                              (cp == CP_UTF8 ||
    637                               cp == CP_UTF7)
    638                              ? NULL
    639                              : &lossy);
    640   error = GetLastError ();
    641   if (len <= 0)
    642     return -1;
    643 
    644   str = malloc (sizeof (char) * len);
    645 
    646   SetLastError (0);
    647   lenc = WideCharToMultiByte (cp,
    648                               0,
    649                               wstr,
    650                               -1,
    651                               str,
    652                               len,
    653                               NULL,
    654                               (cp == CP_UTF8 ||
    655                                cp == CP_UTF7)
    656                               ? NULL
    657                               : &lossy);
    658   error = GetLastError ();
    659   if (lenc != len)
    660   {
    661     free (str);
    662     return -3;
    663   }
    664   *retstr = str;
    665   if (lossy)
    666     return 1;
    667   return 0;
    668 }
    669 
    670 
    671 #endif
    672 
    673 
    674 /**
    675  * Makes a copy of argv that consists of a single memory chunk that can be
    676  * freed with a single call to free ();
    677  */
    678 static char **
    679 _make_continuous_arg_copy (int argc,
    680                            char *const *argv)
    681 {
    682   size_t argvsize = 0;
    683   int i;
    684   char **new_argv;
    685   char *p;
    686 
    687   for (i = 0; i < argc; i++)
    688     argvsize += strlen (argv[i]) + 1 + sizeof (char *);
    689   new_argv = malloc (argvsize + sizeof (char *));
    690   if (NULL == new_argv)
    691     return NULL;
    692   p = (char *) &new_argv[argc + 1];
    693   for (i = 0; i < argc; i++)
    694   {
    695     new_argv[i] = p;
    696     strcpy (p, argv[i]);
    697     p += strlen (argv[i]) + 1;
    698   }
    699   new_argv[argc] = NULL;
    700   return (char **) new_argv;
    701 }
    702 
    703 
    704 /**
    705  * Returns utf-8 encoded arguments.
    706  * Returned argv has u8argv[u8argc] == NULL.
    707  * Returned argv is a single memory block, and can be freed with a single
    708  *   free () call.
    709  *
    710  * @param argc argc (as given by main())
    711  * @param argv argv (as given by main())
    712  * @param u8argc a location to store new argc in (though it's th same as argc)
    713  * @param u8argv a location to store new argv in
    714  * @return 0 on success, -1 on failure
    715  */
    716 static int
    717 _get_utf8_args (int argc,
    718                 char *const *argv,
    719                 int *u8argc,
    720                 char ***u8argv)
    721 {
    722 #ifdef WINDOWS
    723   wchar_t *wcmd;
    724   wchar_t **wargv;
    725   int wargc;
    726   char **split_u8argv;
    727 
    728   wcmd = GetCommandLineW ();
    729   if (NULL == wcmd)
    730     return -1;
    731   wargv = CommandLineToArgvW (wcmd,
    732                               &wargc);
    733   if (NULL == wargv)
    734     return -1;
    735 
    736   split_u8argv = malloc (wargc * sizeof (char *));
    737   if (NULL == split_u8argv)
    738     return -1;
    739   for (unsigned int i = 0; i < wargc; i++)
    740   {
    741     if (0 !=
    742         _wchar_to_str (wargv[i],
    743                        &split_u8argv[i],
    744                        CP_UTF8))
    745     {
    746       int e = errno;
    747 
    748       for (unsigned int j = 0; j < i; j++)
    749         free (split_u8argv[j]);
    750       free (split_u8argv);
    751       LocalFree (wargv);
    752       errno = e;
    753       return -1;
    754     }
    755   }
    756 
    757   *u8argv = _make_continuous_arg_copy (wargc,
    758                                        split_u8argv);
    759   if (NULL == *u8argv)
    760   {
    761     free (split_u8argv);
    762     return -1;
    763   }
    764   *u8argc = wargc;
    765 
    766   for (unsigned int i = 0; i < wargc; i++)
    767     free (split_u8argv[i]);
    768   free (split_u8argv);
    769 #else
    770   *u8argv = _make_continuous_arg_copy (argc,
    771                                        argv);
    772   if (NULL == *u8argv)
    773     return -1;
    774   *u8argc = argc;
    775 #endif
    776   return 0;
    777 }
    778 
    779 
    780 /**
    781  * Main function for the 'extract' tool.  Invoke with a list of
    782  * filenames to extract keywords from.
    783  *
    784  * @param argc number of arguments in argv
    785  * @param argv command line options and filename to run on
    786  * @return 0 on success
    787  */
    788 int
    789 main (int argc,
    790       char *argv[])
    791 {
    792   unsigned int i;
    793   struct EXTRACTOR_PluginList *plugins;
    794   int option_index;
    795   int c;
    796   char *libraries = NULL;
    797   int nodefault = NO;
    798   int defaultAll = YES;
    799   int bibtex = NO;
    800   int grepfriendly = NO;
    801   int ret = 0;
    802   EXTRACTOR_MetaDataProcessor processor = NULL;
    803   char **utf8_argv;
    804   int utf8_argc;
    805 
    806 #if ENABLE_NLS
    807   setlocale (LC_ALL, "");
    808   textdomain (PACKAGE);
    809 #endif
    810 #ifndef WINDOWS
    811   ignore_sigpipe ();
    812 #endif
    813   if (NULL == (print = malloc (sizeof (int) * EXTRACTOR_metatype_get_max ())))
    814   {
    815     fprintf (stderr,
    816              "malloc failed: %s\n",
    817              strerror (errno));
    818     return 1;
    819   }
    820   for (i = 0; i < EXTRACTOR_metatype_get_max (); i++)
    821     print[i] = YES;   /* default: print everything */
    822 
    823   if (0 != _get_utf8_args (argc, argv,
    824                            &utf8_argc, &utf8_argv))
    825   {
    826     fprintf (stderr,
    827              "Failed to get arguments: %s\n",
    828              strerror (errno));
    829     return 1;
    830   }
    831 
    832   while (1)
    833   {
    834     static struct option long_options[] = {
    835       {"bibtex", 0, 0, 'b'},
    836       {"grep-friendly", 0, 0, 'g'},
    837       {"help", 0, 0, 'h'},
    838       {"in-process", 0, 0, 'i'},
    839       {"from-memory", 0, 0, 'm'},
    840       {"list", 0, 0, 'L'},
    841       {"library", 1, 0, 'l'},
    842       {"nodefault", 0, 0, 'n'},
    843       {"print", 1, 0, 'p'},
    844       {"verbose", 0, 0, 'V'},
    845       {"version", 0, 0, 'v'},
    846       {"exclude", 1, 0, 'x'},
    847       {0, 0, 0, 0}
    848     };
    849     option_index = 0;
    850     c = getopt_long (utf8_argc,
    851                      utf8_argv,
    852                      "abghiml:Lnp:vVx:",
    853                      long_options,
    854                      &option_index);
    855 
    856     if (c == -1)
    857       break;  /* No more flags to process */
    858     switch (c)
    859     {
    860     case 'b':
    861       bibtex = YES;
    862       if (NULL != processor)
    863       {
    864         fprintf (stderr,
    865                  "%s",
    866                  _ (
    867                    "Illegal combination of options, cannot combine multiple styles of printing.\n"))
    868         ;
    869         free (utf8_argv);
    870         return 0;
    871       }
    872       processor = &print_bibtex;
    873       break;
    874     case 'g':
    875       grepfriendly = YES;
    876       if (NULL != processor)
    877       {
    878         fprintf (stderr,
    879                  "%s",
    880                  _ (
    881                    "Illegal combination of options, cannot combine multiple styles of printing.\n"))
    882         ;
    883         free (utf8_argv);
    884         return 0;
    885       }
    886       processor = &print_selected_keywords_grep_friendly;
    887       break;
    888     case 'h':
    889       print_help ();
    890       free (utf8_argv);
    891       return 0;
    892     case 'i':
    893       in_process = YES;
    894       break;
    895     case 'm':
    896       from_memory = YES;
    897       break;
    898     case 'l':
    899       libraries = optarg;
    900       break;
    901     case 'L':
    902       i = 0;
    903       while (NULL != EXTRACTOR_metatype_to_string (i))
    904         printf ("%s\n",
    905                 gettext (EXTRACTOR_metatype_to_string (i++)));
    906       free (utf8_argv);
    907       return 0;
    908     case 'n':
    909       nodefault = YES;
    910       break;
    911     case 'p':
    912       if (NULL == optarg)
    913       {
    914         fprintf (stderr,
    915                  _ (
    916                    "You must specify an argument for the `%s' option (option ignored).\n"),
    917                  "-p");
    918         break;
    919       }
    920       if (YES == defaultAll)
    921       {
    922         defaultAll = NO;
    923         i = 0;
    924         while (NULL != EXTRACTOR_metatype_to_string (i))
    925           print[i++] = NO;
    926       }
    927       i = 0;
    928       while (NULL != EXTRACTOR_metatype_to_string (i))
    929       {
    930         if ( (0 == strcmp (optarg,
    931                            EXTRACTOR_metatype_to_string (i))) ||
    932              (0 == strcmp (optarg,
    933                            gettext (EXTRACTOR_metatype_to_string (i)))) )
    934 
    935         {
    936           print[i] = YES;
    937           break;
    938         }
    939         i++;
    940       }
    941       if (NULL == EXTRACTOR_metatype_to_string (i))
    942       {
    943         fprintf (stderr,
    944                  "Unknown keyword type `%s', use option `%s' to get a list.\n",
    945                  optarg,
    946                  "-L");
    947         free (utf8_argv);
    948         return -1;
    949       }
    950       break;
    951     case 'v':
    952       printf ("extract v%s\n", PACKAGE_VERSION);
    953       free (utf8_argv);
    954       return 0;
    955     case 'V':
    956       verbose++;
    957       break;
    958     case 'x':
    959       i = 0;
    960       while (NULL != EXTRACTOR_metatype_to_string (i))
    961       {
    962         if ( (0 == strcmp (optarg,
    963                            EXTRACTOR_metatype_to_string (i))) ||
    964              (0 == strcmp (optarg,
    965                            gettext (EXTRACTOR_metatype_to_string (i)))) )
    966         {
    967           print[i] = NO;
    968           break;
    969         }
    970         i++;
    971       }
    972       if (NULL == EXTRACTOR_metatype_to_string (i))
    973       {
    974         fprintf (stderr,
    975                  "Unknown keyword type `%s', use option `%s' to get a list.\n",
    976                  optarg,
    977                  "-L");
    978         free (utf8_argv);
    979         return -1;
    980       }
    981       break;
    982     default:
    983       fprintf (stderr,
    984                "%s",
    985                _ ("Use --help to get a list of options.\n"));
    986       free (utf8_argv);
    987       return -1;
    988     }   /* end of parsing commandline */
    989   }         /* while (1) */
    990   if (optind < 0)
    991   {
    992     fprintf (stderr,
    993              "%s", "Unknown error parsing options\n");
    994     free (print);
    995     free (utf8_argv);
    996     return -1;
    997   }
    998   if (utf8_argc - optind < 1)
    999   {
   1000     fprintf (stderr,
   1001              "%s", "Invoke with list of filenames to extract keywords form!\n");
   1002     free (print);
   1003     free (utf8_argv);
   1004     return -1;
   1005   }
   1006 
   1007   /* build list of libraries */
   1008   if (NO == nodefault)
   1009     plugins = EXTRACTOR_plugin_add_defaults (in_process
   1010                                              ? EXTRACTOR_OPTION_IN_PROCESS
   1011                                              : EXTRACTOR_OPTION_DEFAULT_POLICY);
   1012   else
   1013     plugins = NULL;
   1014   if (NULL != libraries)
   1015     plugins = EXTRACTOR_plugin_add_config (plugins,
   1016                                            libraries,
   1017                                            in_process
   1018                                            ? EXTRACTOR_OPTION_IN_PROCESS
   1019                                            : EXTRACTOR_OPTION_DEFAULT_POLICY);
   1020   if (NULL == processor)
   1021     processor = &print_selected_keywords;
   1022   if (NULL == utf8_argv[optind])
   1023     goto cleanup;
   1024   /* extract keywords */
   1025   if (YES == bibtex)
   1026     fprintf (stdout,
   1027              "%s",
   1028              _ ("% BiBTeX file\n"));
   1029   for (i = optind; NULL != utf8_argv[i]; i++)
   1030   {
   1031     errno = 0;
   1032     if (YES == grepfriendly)
   1033       fprintf (stdout,
   1034                "%s ",
   1035                utf8_argv[i]);
   1036     else if (NO == bibtex)
   1037       fprintf (stdout,
   1038                _ ("Keywords for file %s:\n"),
   1039                utf8_argv[i]);
   1040     else
   1041       cleanup_bibtex ();
   1042     if (NO == from_memory)
   1043       EXTRACTOR_extract (plugins,
   1044                          utf8_argv[i],
   1045                          NULL, 0,
   1046                          processor,
   1047                          NULL);
   1048     else
   1049     {
   1050       struct stat sb;
   1051       unsigned char *data = NULL;
   1052       int f = open (utf8_argv[i],
   1053                     O_RDONLY
   1054 #if WINDOWS
   1055                     | O_BINARY
   1056 #endif
   1057                     );
   1058 
   1059       if ( (-1 != f) &&
   1060            (0 == fstat (f,
   1061                         &sb)) &&
   1062            (MAP_FAILED !=
   1063             (data = mmap (NULL,
   1064                           (size_t) sb.st_size,
   1065                           PROT_READ,
   1066                           MAP_SHARED,
   1067                           f,
   1068                           0))) )
   1069       {
   1070         EXTRACTOR_extract (plugins,
   1071                            NULL,
   1072                            data, sb.st_size,
   1073                            processor,
   1074                            NULL);
   1075       }
   1076       else
   1077       {
   1078         if (verbose > 0)
   1079           fprintf (stderr,
   1080                    "%s: %s: %s\n",
   1081                    utf8_argv[0],
   1082                    utf8_argv[i],
   1083                    strerror (errno));
   1084         ret = 1;
   1085       }
   1086       if (MAP_FAILED != data)
   1087         munmap (data,
   1088                 (size_t) sb.st_size);
   1089       if (-1 != f)
   1090         (void) close (f);
   1091     }
   1092     if (YES == grepfriendly)
   1093       fprintf (stdout,
   1094                "%s", "\n");
   1095     continue;
   1096   }
   1097   if (YES == grepfriendly)
   1098     fprintf (stdout,
   1099              "%s",
   1100              "\n");
   1101   if (bibtex)
   1102     finish_bibtex (utf8_argv[optind]);
   1103   if (verbose > 0)
   1104     fprintf (stdout,
   1105              "%s",
   1106              "\n");
   1107 cleanup:
   1108   free (print);
   1109   free (utf8_argv);
   1110   EXTRACTOR_plugin_remove_all (plugins);
   1111   plugins = NULL;
   1112   cleanup_bibtex (); /* actually free's stuff */
   1113   return ret;
   1114 }
   1115 
   1116 
   1117 /* end of extract.c */