]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - misc-utils/look.c
logger: (man) add info about rewrite and authors
[thirdparty/util-linux.git] / misc-utils / look.c
index f3b4ba517f0314f807b8ced4963503bf075a41cd..d2699bfdd695c2dc963c23601f08a94e7a62c226 100644 (file)
  * SUCH DAMAGE.
  */
 
- /* 1999-02-22 Arkadiusz Mikiewicz <misiek@pld.ORG.PL>
+ /* 1999-02-22 Arkadiusz Miśkiewicz <misiek@pld.ORG.PL>
   * - added Native Language Support
   */
 
 /*
  * look -- find lines in a sorted list.
- * 
+ *
  * The man page said that TABs and SPACEs participate in -d comparisons.
  * In fact, they were ignored.  This implements historic practice, not
  * the manual page.
  */
 
-#include <sys/types.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
-
-#include <limits.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <stddef.h>
 #include <string.h>
 #include <ctype.h>
 #include <getopt.h>
-#include <locale.h>
-#include "pathnames.h"
+
 #include "nls.h"
+#include "xalloc.h"
+#include "pathnames.h"
+#include "closestream.h"
 
 #define        EQUAL           0
 #define        GREATER         1
 #define        LESS            (-1)
 
-int dflag, fflag;
+static int dflag, fflag;
 /* uglified the source a bit with globals, so that we only need
    to allocate comparbuf once */
-int stringlen;
-char *string;
-char *comparbuf;
+static int stringlen;
+static char *string;
+static char *comparbuf;
 
 static char *binary_search (char *, char *);
 static int compare (char *, char *);
-static void err (const char *fmt, ...);
 static char *linear_search (char *, char *);
 static int look (char *, char *);
 static void print_from (char *, char *);
-static void usage (void);
+static void __attribute__((__noreturn__)) usage(void);
 
 int
 main(int argc, char *argv[])
@@ -88,21 +87,36 @@ main(int argc, char *argv[])
        int ch, fd, termchar;
        char *back, *file, *front, *p;
 
+       static const struct option longopts[] = {
+               {"alternative", no_argument, NULL, 'a'},
+               {"alphanum", no_argument, NULL, 'd'},
+               {"ignore-case", no_argument, NULL, 'f'},
+               {"terminate", required_argument, NULL, 't'},
+               {"version", no_argument, NULL, 'V'},
+               {"help", no_argument, NULL, 'h'},
+               {NULL, 0, NULL, 0}
+       };
+
        setlocale(LC_ALL, "");
        bindtextdomain(PACKAGE, LOCALEDIR);
        textdomain(PACKAGE);
-       
+       atexit(close_stdout);
+
        setlocale(LC_ALL, "");
 
-       file = _PATH_WORDS;
+       if ((file = getenv("WORDLIST")) && !access(file, R_OK))
+               /* use the WORDLIST */;
+       else
+               file = _PATH_WORDS;
+
        termchar = '\0';
        string = NULL;          /* just for gcc */
 
-       while ((ch = getopt(argc, argv, "adft:")) != EOF)
+       while ((ch = getopt_long(argc, argv, "adft:Vh", longopts, NULL)) != -1)
                switch(ch) {
                case 'a':
-                       file = _PATH_WORDS_ALT;
-                       break;
+                       file = _PATH_WORDS_ALT;
+                       break;
                case 'd':
                        dflag = 1;
                        break;
@@ -112,9 +126,13 @@ main(int argc, char *argv[])
                case 't':
                        termchar = *optarg;
                        break;
-               case '?':
-               default:
+               case 'V':
+                       printf(UTIL_LINUX_VERSION);
+                       return EXIT_SUCCESS;
+               case 'h':
                        usage();
+               default:
+                       errtryhelp(EXIT_FAILURE);
                }
        argc -= optind;
        argv += optind;
@@ -129,47 +147,38 @@ main(int argc, char *argv[])
                string = *argv;
                break;
        default:
-               usage();
+               warnx(_("bad usage"));
+               errtryhelp(EXIT_FAILURE);
        }
 
        if (termchar != '\0' && (p = strchr(string, termchar)) != NULL)
                *++p = '\0';
 
        if ((fd = open(file, O_RDONLY, 0)) < 0 || fstat(fd, &sb))
-               err("%s: %s", file, strerror(errno));
+               err(EXIT_FAILURE, "%s", file);
        front = mmap(NULL, (size_t) sb.st_size, PROT_READ,
-#ifdef MAP_FILE
-                    MAP_FILE |
-#endif
                     MAP_SHARED, fd, (off_t) 0);
        if
 #ifdef MAP_FAILED
-          (front == MAP_FAILED)
+               (front == MAP_FAILED)
 #else
-          ((void *)(front) <= (void *)0)
+               ((void *)(front) <= (void *)0)
 #endif
-               err("%s: %s", file, strerror(errno));
-
-#if 0
-       /* workaround for mmap problem (rmiller@duskglow.com) */
-       if (front == (void *)0)
-               return 1;
-#endif
-
+                       err(EXIT_FAILURE, "%s", file);
        back = front + sb.st_size;
        return look(front, back);
 }
 
-int
+static int
 look(char *front, char *back)
 {
        int ch;
        char *readp, *writep;
 
-       /* Reformat string string to avoid doing it multiple times later. */
+       /* Reformat string to avoid doing it multiple times later. */
        if (dflag) {
                for (readp = writep = string; (ch = *readp++) != 0;) {
-                       if (isalnum(ch))
+                       if (isalnum(ch) || isblank(ch))
                                *(writep++) = ch;
                }
                *writep = '\0';
@@ -177,57 +186,58 @@ look(char *front, char *back)
        } else
                stringlen = strlen(string);
 
-       comparbuf = malloc(stringlen+1);
-       if (comparbuf == NULL)
-               err(_("Out of memory"));
+       comparbuf = xmalloc(stringlen+1);
 
        front = binary_search(front, back);
        front = linear_search(front, back);
 
        if (front)
                print_from(front, back);
+
+       free(comparbuf);
+
        return (front ? 0 : 1);
 }
 
 
 /*
  * Binary search for "string" in memory between "front" and "back".
- * 
+ *
  * This routine is expected to return a pointer to the start of a line at
  * *or before* the first word matching "string".  Relaxing the constraint
  * this way simplifies the algorithm.
- * 
+ *
  * Invariants:
- *     front points to the beginning of a line at or before the first 
+ *     front points to the beginning of a line at or before the first
  *     matching string.
- * 
- *     back points to the beginning of a line at or after the first 
+ *
+ *     back points to the beginning of a line at or after the first
  *     matching line.
- * 
+ *
  * Advancing the Invariants:
- * 
+ *
  *     p = first newline after halfway point from front to back.
- * 
- *     If the string at "p" is not greater than the string to match, 
+ *
+ *     If the string at "p" is not greater than the string to match,
  *     p is the new front.  Otherwise it is the new back.
- * 
+ *
  * Termination:
- * 
- *     The definition of the routine allows it return at any point, 
+ *
+ *     The definition of the routine allows it return at any point,
  *     since front is always at or before the line to print.
- * 
- *     In fact, it returns when the chosen "p" equals "back".  This 
- *     implies that there exists a string is least half as long as 
- *     (back - front), which in turn implies that a linear search will 
+ *
+ *     In fact, it returns when the chosen "p" equals "back".  This
+ *     implies that there exists a string is least half as long as
+ *     (back - front), which in turn implies that a linear search will
  *     be no more expensive than the cost of simply printing a string or two.
- * 
- *     Trying to continue with binary search at this point would be 
+ *
+ *     Trying to continue with binary search at this point would be
  *     more trouble than it's worth.
  */
 #define        SKIP_PAST_NEWLINE(p, back) \
-       while (p < back && *p++ != '\n');
+       while (p < back && *p++ != '\n')
 
-char *
+static char *
 binary_search(char *front, char *back)
 {
        char *p;
@@ -253,25 +263,23 @@ binary_search(char *front, char *back)
 /*
  * Find the first line that starts with string, linearly searching from front
  * to back.
- * 
+ *
  * Return NULL for no such line.
- * 
+ *
  * This routine assumes:
- * 
- *     o front points at the first character in a line. 
+ *
+ *     o front points at the first character in a line.
  *     o front is before or at the first line to be printed.
  */
-char *
+static char *
 linear_search(char *front, char *back)
 {
        while (front < back) {
                switch (compare(front, back)) {
                case EQUAL:             /* Found it. */
                        return (front);
-                       break;
                case LESS:              /* No such string. */
                        return (NULL);
-                       break;
                case GREATER:           /* Keep going. */
                        break;
                }
@@ -283,7 +291,7 @@ linear_search(char *front, char *back)
 /*
  * Print as many lines as match string, starting at front.
  */
-void 
+static void
 print_from(char *front, char *back)
 {
        int eol;
@@ -293,7 +301,7 @@ print_from(char *front, char *back)
                        eol = 0;
                        while (front < back && !eol) {
                                if (putchar(*front) == EOF)
-                                       err("stdout: %s", strerror(errno));
+                                       err(EXIT_FAILURE, "stdout");
                                if (*front++ == '\n')
                                        eol = 1;
                        }
@@ -305,20 +313,20 @@ print_from(char *front, char *back)
 /*
  * Return LESS, GREATER, or EQUAL depending on how  string  compares with
  * string2 (s1 ??? s2).
- * 
- *     o Matches up to len(s1) are EQUAL. 
+ *
+ *     o Matches up to len(s1) are EQUAL.
  *     o Matches up to len(s2) are GREATER.
- * 
+ *
  * Compare understands about the -f and -d flags, and treats comparisons
  * appropriately.
- * 
+ *
  * The string "string" is null terminated.  The string "s2" is '\n' terminated
  * (or "s2end" terminated).
  *
  * We use strcasecmp etc, since it knows how to ignore case also
  * in other locales.
  */
-int
+static int
 compare(char *s2, char *s2end) {
        int i;
        char *p;
@@ -326,9 +334,12 @@ compare(char *s2, char *s2end) {
        /* copy, ignoring things that should be ignored */
        p = comparbuf;
        i = stringlen;
-       while(s2 < s2end && *s2 != '\n' && i--) {
-               if (!dflag || isalnum(*s2))
+       while(s2 < s2end && *s2 != '\n' && i) {
+               if (!dflag || isalnum(*s2) || isblank(*s2))
+               {
                        *p++ = *s2;
+                       i--;
+               }
                s2++;
        }
        *p = 0;
@@ -342,38 +353,24 @@ compare(char *s2, char *s2end) {
        return ((i > 0) ? LESS : (i < 0) ? GREATER : EQUAL);
 }
 
-static void
-usage()
+static void __attribute__((__noreturn__)) usage(void)
 {
-       (void)fprintf(stderr, _("usage: look [-dfa] [-t char] string [file]\n"));
-       exit(2);
-}
+       FILE *out = stdout;
+       fputs(USAGE_HEADER, out);
+       fprintf(out, _(" %s [options] <string> [<file>...]\n"), program_invocation_short_name);
 
-#if __STDC__
-#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
+       fputs(USAGE_SEPARATOR, out);
+       fputs(_("Display lines beginning with a specified string.\n"), out);
 
-void
-#if __STDC__
-err(const char *fmt, ...)
-#else
-err(fmt, va_alist)
-       char *fmt;
-       va_dcl
-#endif
-{
-       va_list ap;
-#if __STDC__
-       va_start(ap, fmt);
-#else
-       va_start(ap);
-#endif
-       (void)fprintf(stderr, "look: ");
-       (void)vfprintf(stderr, fmt, ap);
-       va_end(ap);
-       (void)fprintf(stderr, "\n");
-       exit(2);
-       /* NOTREACHED */
+       fputs(USAGE_OPTIONS, out);
+       fputs(_(" -a, --alternative        use the alternative dictionary\n"), out);
+       fputs(_(" -d, --alphanum           compare only blanks and alphanumeric characters\n"), out);
+       fputs(_(" -f, --ignore-case        ignore case differences when comparing\n"), out);
+       fputs(_(" -t, --terminate <char>   define the string-termination character\n"), out);
+
+       fputs(USAGE_SEPARATOR, out);
+       printf(USAGE_HELP_OPTIONS(26));
+       printf(USAGE_MAN_TAIL("look(1)"));
+
+       exit(EXIT_SUCCESS);
 }