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