[PATCH 2/3] more: support for long options

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This fix will also introduce warning. More has been setting
option --no-scroll on if binary is has been called `page'. Since
this was not documented, and rather well hide to the source, the
functionality should be removed in future.

Environment variable PAGE is after this commit examined by
getopt_long, which will mean that some previously broken ways to
execute the command now work. For example one bellow.

MORE='+10' more /etc/services

Signed-off-by: Sami Kerola <kerolasa@xxxxxx>
---
 text-utils/Makefile.am |    2 +
 text-utils/more.c      |  304 ++++++++++++++++++++++++++++++++----------------
 2 files changed, 205 insertions(+), 101 deletions(-)

diff --git a/text-utils/Makefile.am b/text-utils/Makefile.am
index eee00c3..95dcf42 100644
--- a/text-utils/Makefile.am
+++ b/text-utils/Makefile.am
@@ -7,6 +7,8 @@ usrbin_exec_PROGRAMS = col colcrt colrm column hexdump rev line tailf
 hexdump_SOURCES = hexdump.c conv.c display.c hexsyntax.c parse.c \
 		  hexdump.h
 
+more_SOURCES = more.c $(top_srcdir)/lib/strutils.c
+
 dist_man_MANS = col.1 colcrt.1 colrm.1 column.1 hexdump.1 rev.1 line.1 tailf.1
 
 if HAVE_NCURSES
diff --git a/text-utils/more.c b/text-utils/more.c
index add2b94..ab102f8 100644
--- a/text-utils/more.c
+++ b/text-utils/more.c
@@ -56,6 +56,7 @@
 #include <sys/stat.h>
 #include <sys/file.h>
 #include <sys/wait.h>
+#include <getopt.h>
 #include "strutils.h"
 
 #include "nls.h"
@@ -94,7 +95,6 @@ void error (char *mess);
 void do_shell (char *filename);
 int  colon (char *filename, int cmd, int nlines);
 int  expand (char **outbuf, char *inbuf);
-void argscan(char *s);
 void rdline (register FILE *f);
 void copy_file(register FILE *f);
 void search(char buf[], FILE *file, register int n);
@@ -114,14 +114,45 @@ void prbuf (register char *s, register int n);
 void execute (char *filename, char *cmd, ...);
 FILE *checkf (char *, int *);
 void prepare_line_buffer(void);
+static void __attribute__ ((__noreturn__)) print_version (void);
+static void __attribute__ ((__noreturn__)) usage(FILE *out);
 
 #define TBUFSIZ	1024
 #define LINSIZ	256	/* minimal Line buffer size */
+#define INIT_SEARCH_BUFFER_SIZE 80
 #define ctrl(letter)	(letter & 077)
 #define RUBOUT	'\177'
 #define ESC	'\033'
 #define QUIT	'\034'
 
+enum
+{
+  DISPLAY_LINES_OPTION = CHAR_MAX + 1,
+  START_LINE_OPTION,
+  SEARCH_LINE_OPTION,
+  HELP_OPTION,
+  VERSION_OPTION
+};
+static struct option const long_options[] =
+{
+  {"visible-bell", no_argument, NULL, 'd'},
+  {"logical-count", no_argument, NULL, 'f'},
+  {"ignore-form-feed", no_argument, NULL, 'l'},
+  {"no-scroll", no_argument, NULL, 'p'},
+  {"clean-ends", no_argument, NULL, 'c'},
+  {"no-underlining", no_argument, NULL, 'u'},
+  {"squeeze", no_argument, NULL, 's'},
+  {"lines", required_argument, NULL, DISPLAY_LINES_OPTION},
+  {"start-line", required_argument, NULL, START_LINE_OPTION},
+  {"search", required_argument, NULL, SEARCH_LINE_OPTION},
+  {"help", no_argument, NULL, HELP_OPTION},
+  {"version", no_argument, NULL, VERSION_OPTION},
+  {NULL, 0, NULL, 0}
+};
+char short_opt_lines[] = "--lines";
+char short_opt_start_line[] = "--start-line";
+char short_opt_search[] = "--search";
+
 struct termios	otty, savetty0;
 long		file_pos, file_size;
 int		fnum, no_intty, no_tty, slow_tty;
@@ -297,11 +328,61 @@ my_tgoto(char *cap, int col, int row) {
 
 #endif /* HAVE_LIBTERMCAP */
 
-static void
-usage() {
-	fprintf(stderr,
-		_("usage: %s [-dflpcsu] [+linenum | +/pattern] name1 name2 ...\n"),
+static void __attribute__ ((__noreturn__)) print_version (void)
+{
+        printf(_("more (%s)\n"), PACKAGE_STRING);
+        exit(EXIT_SUCCESS);
+}
+
+static void __attribute__ ((__noreturn__)) usage(FILE *out)
+{
+	fprintf(out,
+		_("Usage: %s [options] file...\n\n"),
 		program_invocation_short_name);
+	fprintf(out,
+		_("Options:\n"
+		  "  -d,   --visible-bell       display help instead of ring bell \n"
+		  "  -f,   --logical-count      count logical, rather than screen lines\n"
+		  "  -l,   --ignore-form-feed   suppress pause after form feed\n"
+		  "  -p,   --no-scroll          suppress scroll, clean screen and disblay text\n"
+		  "  -c,   --clean-ends         suppress scroll, display text and clean line ends\n"
+		  "  -u,   --no-underlining     suppress underlining\n"
+		  "  -s,   --squeeze            squeeze multiple blank lines into one\n"
+		  "  -NUM, --lines=NUM          set number of screen lines\n"
+		  "  +NUM, --start-line=NUM     display beginning from line number NUM\n"
+		  "  +/STRING, --search=STRING  display beginning where search match\n"
+		  "        --help               display this help and exit \n"
+		  "        --version            output version information and exit\n"));
+	exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
+}
+
+int getoptify_old_format(char *argv, char **new_argv, int new_argc, int *new_argc_optsp, int *old_opt_formatp) {
+    if (argv[0] == '+') {
+	if (argv[1] == '/') {
+	    new_argv[new_argc] = (char *) &short_opt_search;
+	    new_argc++;
+	    new_argv[new_argc] = (char *) &argv[2];
+	    new_argc++;
+	    ++*old_opt_formatp;
+	} else {
+	    new_argv[new_argc] = (char *) &short_opt_start_line;
+	    new_argc++;
+	    new_argv[new_argc] = (char *) &argv[1];
+	    new_argc++;
+	    ++*old_opt_formatp;
+	}
+    } else if (argv[0] == '-' && isdigit(argv[1])) {
+	new_argv[new_argc] = (char *) &short_opt_lines;
+	new_argc++;
+	new_argv[new_argc] = (char *) &argv[1];
+	new_argc++;
+    } else {
+	new_argv[new_argc] = argv;
+	new_argc++;
+    }
+
+    ++*new_argc_optsp;
+    return(new_argc);
 }
 
 int main(int argc, char **argv) {
@@ -315,14 +396,18 @@ int main(int argc, char **argv) {
     int		srchopt = 0;
     int		clearit = 0;
     int		initline = 0;
-    char	initbuf[80];
+    char	*initbuf = NULL;
+    char        **new_argv;
+    int         new_argc = 1;
+    int         new_argc_opts = 0;
+    int		*new_argc_optsp;
+    int         old_opt_format;
+    int         *old_opt_formatp;
 
     setlocale(LC_ALL, "");
     bindtextdomain(PACKAGE, LOCALEDIR);
     textdomain(PACKAGE);
-    
-    nfiles = argc;
-    fnames = argv;
+
     setlocale(LC_ALL, "");
     initterm ();
     prepare_line_buffer();
@@ -330,29 +415,114 @@ int main(int argc, char **argv) {
     nscroll = Lpp/2 - 1;
     if (nscroll <= 0)
 	nscroll = 1;
-    if((s = getenv("MORE")) != NULL) argscan(s);
-    while (--nfiles > 0) {
-	if ((ch = (*++fnames)[0]) == '-') {
-	    argscan(*fnames+1);
-	}
-	else if (ch == '+') {
-	    s = *fnames;
-	    if (*++s == '/') {
-		srchopt++;
-		for (++s, p = initbuf; p < initbuf + 79 && *s != '\0';)
-		    *p++ = *s++;
-		*p = '\0';
+
+    /* This used to be done in initterm with function tailequ.
+     * Setting an option on basis of a binary name is dirty trick,
+     * and should be removed in future. */
+    if (!(strcmp(program_invocation_short_name, "page"))) {
+	warnx(_("option --no-scroll is set because the binary has name `page'"));
+	noscroll++;
+    }
+
+    /* FIXME make fully dynamic; think about linux/limits.h ARG_MAX */
+    new_argv = (char **) xmalloc(sizeof(char *) * 256);
+    new_argc_optsp = &new_argc_opts;
+    old_opt_formatp = &old_opt_format;
+
+    /* Convert environment string to look like option from
+     * command line. */
+    s = getenv("MORE");
+    if (s != NULL) {
+	int i;
+	i = 0;
+	while (s[0] != '\0' && new_argc < 256) {
+	    if(isblank(s[0])) {
+		s[0] = '\0';
+		i = 0;
+	    } else {
+		if (i == 0) {
+		    new_argc = getoptify_old_format(s, new_argv, new_argc, new_argc_optsp, old_opt_formatp);
+		    i = 1;
+		}
 	    }
-	    else {
+	    s++;
+	}
+    }
+    old_opt_format *= 2;
+
+    /* Make old style arguments to be long options, and copy
+     * other options to new argv. */
+    for (int i = 0; i < argc && new_argc < 256; i++) {
+        if (i == 0) {
+            new_argv[0] = argv[i];
+        } else {
+            new_argc = getoptify_old_format(argv[i], new_argv, new_argc, new_argc_optsp, old_opt_formatp);
+        }
+    }
+    /* FIXME make fully dynamic */
+    if (new_argc == 256) {
+	fprintf(stderr, _("too many (%d) arguments"), new_argc);
+	exit(EXIT_FAILURE);
+    }
+    new_argv[new_argc] = NULL;
+
+    while (1) {
+	int optind = -1;
+	int c = getopt_long (new_argc, new_argv, "dflpcus",
+		     long_options, &optind);
+	if (c == -1)
+	    break;
+	switch (c) {
+	    case 'd':
+		dum_opt = 1;
+		break;
+	    case 'l':
+		stop_opt = 0;
+		break;
+	    case 'f':
+		fold_opt = 0;
+		break;
+	    case 'p':
+		noscroll++;
+		break;
+	    case 'c':
+		clreol++;
+		break;
+	    case 's':
+		ssp_opt = 1;
+		break;
+	    case 'u':
+		ul_opt = 0;
+		break;
+	    case DISPLAY_LINES_OPTION:
+		dlines = strtol_or_err(optarg, _("number conversion"));
+		break;
+	    case START_LINE_OPTION:
 		initopt++;
-		for (initline = 0; *s != '\0'; s++)
-		    if (isdigit (*s))
-			initline = initline*10 + *s -'0';
-		--initline;
-	    }
+		initline = strtol_or_err(optarg, _("number conversion"));
+		initline--;
+		break;
+	    case SEARCH_LINE_OPTION:
+		srchopt++;
+		initbuf = xmalloc(sizeof(char) * strlen(optarg) + 1);
+		strcpy(initbuf, optarg);
+		break;
+	    case HELP_OPTION:
+		usage(stdout);
+		break;
+	    case VERSION_OPTION:
+		print_version();
+		break;
+	    default:
+		usage(stderr);
 	}
-	else break;
     }
+    optind -= old_opt_format;
+
+    fnames = xmalloc(sizeof(char *) * new_argc - optind);
+    for (nfiles = 0; optind < new_argc;)
+	fnames[nfiles++] = argv[optind++];
+
     /* allow clreol only if Home and eraseln and EodClr strings are
      *  defined, and in that case, make sure we are in noscroll mode
      */
@@ -369,11 +539,13 @@ int main(int argc, char **argv) {
     if (nfiles > 1)
 	prnames++;
     if (!no_intty && nfiles == 0) {
-	usage();
+        warnx(_("no input files specified"));
+	usage(stderr);
 	exit(EXIT_FAILURE);
     }
     else
 	f = stdin;
+
     if (!no_tty) {
 	signal(SIGQUIT, onquit);
 	signal(SIGINT, end_it);
@@ -416,7 +588,7 @@ int main(int argc, char **argv) {
 	firstf = 0;
     }
 
-    while (fnum < nfiles) {
+    while (fnames[fnum] != NULL && fnum < nfiles) {
 	if ((f = checkf (fnames[fnum], &clearit)) != NULL) {
 	    context.line = context.chrctr = 0;
 	    Currline = 0;
@@ -475,60 +647,11 @@ int main(int argc, char **argv) {
 	fnum++;
 	firstf = 0;
     }
+    free(fnames);
     reset_tty ();
     exit(EXIT_SUCCESS);
 }
 
-void argscan(char *s) {
-	int seen_num = 0;
-
-	while (*s != '\0') {
-		switch (*s) {
-		  case '0': case '1': case '2':
-		  case '3': case '4': case '5':
-		  case '6': case '7': case '8':
-		  case '9':
-			if (!seen_num) {
-				dlines = 0;
-				seen_num = 1;
-			}
-			dlines = dlines*10 + *s - '0';
-			break;
-		  case 'd':
-			dum_opt = 1;
-			break;
-		  case 'l':
-			stop_opt = 0;
-			break;
-		  case 'f':
-			fold_opt = 0;
-			break;
-		  case 'p':
-			noscroll++;
-			break;
-		  case 'c':
-			clreol++;
-			break;
-		  case 's':
-			ssp_opt = 1;
-			break;
-		  case 'u':
-			ul_opt = 0;
-			break;
-		  case '-': case ' ': case '\t':
-			break;
-		  default:
-			fprintf(stderr,
-				_("%s: unknown option \"-%c\"\n"), program_invocation_short_name, *s);
-			usage();
-			exit(EXIT_FAILURE);
-			break;
-		}
-		s++;
-	}
-}
-
-
 /*
 ** Check whether the file named by fs is an ASCII file which the user may
 ** access.  If it is, return the opened file. Otherwise return NULL.
@@ -763,25 +886,6 @@ void copy_file(register FILE *f) {
 
 #define ringbell()	putcerr('\007')
 
-/* See whether the last component of the path name "path" is equal to the
-** string "string"
-*/
-
-static int tailequ (char *path, register char *string)
-{
-	register char *tail;
-
-	tail = path + strlen(path);
-	while (--tail >= path)
-		if (*tail == '/')
-			break;
-	++tail;
-	while (*tail++ == *string++)
-		if (*tail == '\0')
-			return(1);
-	return(0);
-}
-
 static void prompt (char *filename)
 {
     if (clreol)
@@ -1825,8 +1929,6 @@ retry:
 	    if (Mcol <= 0)
 		Mcol = 80;
 
-	    if (tailequ (fnames[0], "page"))
-		noscroll++;
 	    Wrap = my_tgetflag(TERM_AUTO_RIGHT_MARGIN);
 	    bad_so = my_tgetflag (TERM_CEOL);
 	    eraseln = my_tgetstr(TERM_CLEAR_TO_LINE_END);
-- 
1.7.3.5

--
To unsubscribe from this list: send the line "unsubscribe util-linux" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux