Back to index

glibc  2.9
makedb.c
Go to the documentation of this file.
00001 /* Create simple DB database from textual input.
00002    Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <argp.h>
00022 #include <ctype.h>
00023 #include <dlfcn.h>
00024 #include <errno.h>
00025 #include <error.h>
00026 #include <fcntl.h>
00027 #include <libintl.h>
00028 #include <locale.h>
00029 #include <stdio.h>
00030 #include <stdint.h>
00031 #include <stdlib.h>
00032 #include <string.h>
00033 #include <sys/stat.h>
00034 #include "nss_db/dummy-db.h"
00035 
00036 /* Get libc version number.  */
00037 #include "../version.h"
00038 
00039 #define PACKAGE _libc_intl_domainname
00040 
00041 /* If non-zero convert key to lower case.  */
00042 static int to_lowercase;
00043 
00044 /* If non-zero print content of input file, one entry per line.  */
00045 static int do_undo;
00046 
00047 /* If non-zero do not print informational messages.  */
00048 static int be_quiet;
00049 
00050 /* Name of output file.  */
00051 static const char *output_name;
00052 
00053 /* Name and version of program.  */
00054 static void print_version (FILE *stream, struct argp_state *state);
00055 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
00056 
00057 /* Definitions of arguments for argp functions.  */
00058 static const struct argp_option options[] =
00059 {
00060   { "fold-case", 'f', NULL, 0, N_("Convert key to lower case") },
00061   { "output", 'o', N_("NAME"), 0, N_("Write output to file NAME") },
00062   { "quiet", 'q', NULL, 0,
00063     N_("Do not print messages while building database") },
00064   { "undo", 'u', NULL, 0,
00065     N_("Print content of database file, one entry a line") },
00066   { NULL, 0, NULL, 0, NULL }
00067 };
00068 
00069 /* Short description of program.  */
00070 static const char doc[] = N_("Create simple DB database from textual input.");
00071 
00072 /* Strings for arguments in help texts.  */
00073 static const char args_doc[] = N_("\
00074 INPUT-FILE OUTPUT-FILE\n-o OUTPUT-FILE INPUT-FILE\n-u INPUT-FILE");
00075 
00076 /* Prototype for option handler.  */
00077 static error_t parse_opt (int key, char *arg, struct argp_state *state);
00078 
00079 /* Function to print some extra text in the help message.  */
00080 static char *more_help (int key, const char *text, void *input);
00081 
00082 /* Data structure to communicate with argp functions.  */
00083 static struct argp argp =
00084 {
00085   options, parse_opt, args_doc, doc, NULL, more_help
00086 };
00087 
00088 
00089 /* Prototypes for local functions.  */
00090 static int process_input (FILE *input, const char *inname, NSS_DB *output,
00091                        int to_lowercase, int be_quiet);
00092 static int print_database (NSS_DB *db);
00093 
00094 
00095 int
00096 main (int argc, char *argv[])
00097 {
00098   const char *input_name;
00099   FILE *input_file;
00100   NSS_DB *db_file;
00101   int status;
00102   int remaining;
00103   int mode = 0666;
00104 
00105   /* Set locale via LC_ALL.  */
00106   setlocale (LC_ALL, "");
00107 
00108   /* Set the text message domain.  */
00109   textdomain (_libc_intl_domainname);
00110 
00111   /* Initialize local variables.  */
00112   input_name = NULL;
00113 
00114   /* Parse and process arguments.  */
00115   argp_parse (&argp, argc, argv, 0, &remaining, NULL);
00116 
00117   /* Determine file names.  */
00118   if (do_undo || output_name != NULL)
00119     {
00120       if (remaining + 1 != argc)
00121        {
00122        wrong_arguments:
00123          error (0, 0, gettext ("wrong number of arguments"));
00124          argp_help (&argp, stdout, ARGP_HELP_SEE,
00125                    program_invocation_short_name);
00126          exit (1);
00127        }
00128       input_name = argv[remaining];
00129     }
00130   else
00131     {
00132       if (remaining + 2 != argc)
00133        goto wrong_arguments;
00134 
00135       input_name = argv[remaining++];
00136       output_name = argv[remaining];
00137     }
00138 
00139   /* First load the shared object to initialize version dependend
00140      variables.  */
00141   if (load_db () != NSS_STATUS_SUCCESS)
00142     error (EXIT_FAILURE, 0, gettext ("No usable database library found."));
00143 
00144   /* Special handling if we are asked to print the database.  */
00145   if (do_undo)
00146     {
00147       dbopen (input_name, db_rdonly, 0666, &db_file);
00148       if (db_file == NULL)
00149        error (EXIT_FAILURE, 0, gettext ("cannot open database file `%s': %s"),
00150               input_name,
00151               (errno == EINVAL ? gettext ("incorrectly formatted file")
00152               : strerror (errno)));
00153 
00154       status = print_database (db_file);
00155 
00156       db_file->close (db_file->db, 0);
00157 
00158       return status;
00159     }
00160 
00161   /* Open input file.  */
00162   if (strcmp (input_name, "-") == 0 || strcmp (input_name, "/dev/stdin") == 0)
00163     input_file = stdin;
00164   else
00165     {
00166       struct stat st;
00167 
00168       input_file = fopen (input_name, "r");
00169       if (input_file == NULL)
00170        error (EXIT_FAILURE, errno, gettext ("cannot open input file `%s'"),
00171               input_name);
00172 
00173       /* Get the access rights from the source file.  The output file should
00174         have the same.  */
00175       if (fstat (fileno (input_file), &st) >= 0)
00176        mode = st.st_mode & ACCESSPERMS;
00177     }
00178 
00179   /* Open output file.  This must not be standard output so we don't
00180      handle "-" and "/dev/stdout" special.  */
00181   dbopen (output_name, DB_CREATE | db_truncate, mode, &db_file);
00182   if (db_file == NULL)
00183     error (EXIT_FAILURE, errno, gettext ("cannot open output file `%s'"),
00184           output_name);
00185 
00186   /* Start the real work.  */
00187   status = process_input (input_file, input_name, db_file, to_lowercase,
00188                        be_quiet);
00189 
00190   /* Close files.  */
00191   if (input_file != stdin)
00192     fclose (input_file);
00193   db_file->close (db_file->db, 0);
00194 
00195   return status;
00196 }
00197 
00198 
00199 /* Handle program arguments.  */
00200 static error_t
00201 parse_opt (int key, char *arg, struct argp_state *state)
00202 {
00203   switch (key)
00204     {
00205     case 'f':
00206       to_lowercase = 1;
00207       break;
00208     case 'o':
00209       output_name = arg;
00210       break;
00211     case 'q':
00212       be_quiet = 1;
00213       break;
00214     case 'u':
00215       do_undo = 1;
00216       break;
00217     default:
00218       return ARGP_ERR_UNKNOWN;
00219     }
00220   return 0;
00221 }
00222 
00223 
00224 static char *
00225 more_help (int key, const char *text, void *input)
00226 {
00227   switch (key)
00228     {
00229     case ARGP_KEY_HELP_EXTRA:
00230       /* We print some extra information.  */
00231       return strdup (gettext ("\
00232 For bug reporting instructions, please see:\n\
00233 <http://www.gnu.org/software/libc/bugs.html>.\n"));
00234     default:
00235       break;
00236     }
00237   return (char *) text;
00238 }
00239 
00240 /* Print the version information.  */
00241 static void
00242 print_version (FILE *stream, struct argp_state *state)
00243 {
00244   fprintf (stream, "makedb (GNU %s) %s\n", PACKAGE, VERSION);
00245   fprintf (stream, gettext ("\
00246 Copyright (C) %s Free Software Foundation, Inc.\n\
00247 This is free software; see the source for copying conditions.  There is NO\n\
00248 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
00249 "), "2000");
00250   fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
00251 }
00252 
00253 
00254 static int
00255 process_input (input, inname, output, to_lowercase, be_quiet)
00256      FILE *input;
00257      const char *inname;
00258      NSS_DB *output;
00259      int to_lowercase;
00260      int be_quiet;
00261 {
00262   char *line;
00263   size_t linelen;
00264   int status;
00265   size_t linenr;
00266 
00267   line = NULL;
00268   linelen = 0;
00269   status = EXIT_SUCCESS;
00270   linenr = 0;
00271 
00272   while (!feof (input))
00273     {
00274       DBT key;
00275       DBT val;
00276       char *cp;
00277       int n;
00278 
00279       n = getline (&line, &linelen, input);
00280       if (n < 0)
00281        /* This means end of file or some bug.  */
00282        break;
00283       if (n == 0)
00284        /* Short read.  Probably interrupted system call. */
00285        continue;
00286 
00287       ++linenr;
00288 
00289       if (line[n - 1] == '\n')
00290        /* Remove trailing newline.  */
00291        line[--n] = '\0';
00292 
00293       cp = line;
00294       while (isspace (*cp))
00295        ++cp;
00296 
00297       if (*cp == '#')
00298        /* First non-space character in line '#': it's a comment.  */
00299        continue;
00300 
00301       key.data = cp;
00302       while (*cp != '\0' && !isspace (*cp))
00303        {
00304          if (to_lowercase)
00305            *cp = tolower (*cp);
00306          ++cp;
00307        }
00308 
00309       if (key.data == cp)
00310        /* It's an empty line.  */
00311        continue;
00312 
00313       key.size = cp - (char *) key.data;
00314       key.flags = 0;
00315 
00316       while (isspace (*cp))
00317        ++cp;
00318 
00319       val.data = cp;
00320       val.size = (&line[n] - cp) + 1;
00321       val.flags = 0;
00322 
00323       /* Store the value.  */
00324       status = output->put (output->db, NULL, &key, &val, db_nooverwrite);
00325       if (status != 0)
00326        {
00327          if (status == db_keyexist)
00328            {
00329              if (!be_quiet)
00330               error_at_line (0, 0, inname, linenr,
00331                             gettext ("duplicate key"));
00332              /* This is no real error.  Just give a warning.  */
00333              status = 0;
00334              continue;
00335            }
00336          else
00337            error (0, status, gettext ("while writing database file"));
00338 
00339          status = EXIT_FAILURE;
00340 
00341          clearerr (input);
00342          break;
00343        }
00344     }
00345 
00346   if (ferror (input))
00347     {
00348       error (0, 0, gettext ("problems while reading `%s'"), inname);
00349       status = EXIT_FAILURE;
00350     }
00351 
00352   return status;
00353 }
00354 
00355 
00356 static int
00357 print_database (db)
00358      NSS_DB *db;
00359 {
00360   DBT key;
00361   DBT val;
00362   NSS_DBC *cursor;
00363   int status;
00364 
00365   status = db->cursor (db->db, NULL, &cursor);
00366   if (status != 0)
00367     {
00368       error (0, status, gettext ("while reading database"));
00369       return EXIT_FAILURE;
00370     }
00371 
00372   key.flags = 0;
00373   val.flags = 0;
00374   status = cursor->c_get (cursor->cursor, &key, &val, db_first);
00375   while (status == 0)
00376     {
00377       printf ("%.*s %s\n", (int) key.size, (char *) key.data,
00378              (char *) val.data);
00379 
00380       status = cursor->c_get (cursor->cursor, &key, &val, db_next);
00381     }
00382 
00383   if (status != db_notfound)
00384     {
00385       error (0, status, gettext ("while reading database"));
00386       return EXIT_FAILURE;
00387     }
00388 
00389   return EXIT_SUCCESS;
00390 }