diff options
Diffstat (limited to 'progs/tput.c')
| -rw-r--r-- | progs/tput.c | 195 | 
1 files changed, 153 insertions, 42 deletions
diff --git a/progs/tput.c b/progs/tput.c index cac8d292a94b..f9321b60a8d3 100644 --- a/progs/tput.c +++ b/progs/tput.c @@ -1,5 +1,5 @@  /**************************************************************************** - * Copyright 2018-2019,2020 Thomas E. Dickey                                * + * Copyright 2018-2023,2024 Thomas E. Dickey                                *   * Copyright 1998-2016,2017 Free Software Foundation, Inc.                  *   *                                                                          *   * Permission is hereby granted, free of charge, to any person obtaining a  * @@ -44,39 +44,37 @@  #include <clear_cmd.h>  #include <reset_cmd.h> -#if !PURE_TERMINFO -#include <dump_entry.h> -#include <termsort.c> -#endif  #include <transform.h>  #include <tty_settings.h> -MODULE_ID("$Id: tput.c,v 1.84 2020/10/24 18:29:38 tom Exp $") +MODULE_ID("$Id: tput.c,v 1.104 2024/04/20 22:20:51 tom Exp $")  #define PUTS(s)		fputs(s, stdout)  const char *_nc_progname = "tput"; -static char *prg_name; +static bool opt_v = FALSE;	/* quiet, do not show warnings */ +static bool opt_x = FALSE;	/* clear scrollback if possible */ +  static bool is_init = FALSE;  static bool is_reset = FALSE;  static bool is_clear = FALSE; -static void +static GCC_NORETURN void  quit(int status, const char *fmt, ...)  {      va_list argp;      va_start(argp, fmt); -    fprintf(stderr, "%s: ", prg_name); +    fprintf(stderr, "%s: ", _nc_progname);      vfprintf(stderr, fmt, argp);      fprintf(stderr, "\n");      va_end(argp);      ExitProgram(status);  } -static void -usage(void) +static GCC_NORETURN void +usage(const char *optstring)  {  #define KEEP(s) s "\n"      static const char msg[] = @@ -86,6 +84,7 @@ usage(void)  	KEEP("  -S <<       read commands from standard input")  	KEEP("  -T TERM     use this instead of $TERM")  	KEEP("  -V          print curses-version") +	KEEP("  -v          verbose, show warnings")  	KEEP("  -x          do not try to clear scrollback")  	KEEP("")  	KEEP("Commands:") @@ -95,8 +94,21 @@ usage(void)  	KEEP("  capname     unlike clear/init/reset, print value for capability \"capname\"")      };  #undef KEEP -    (void) fprintf(stderr, "Usage: %s [options] [command]\n", prg_name); -    fputs(msg, stderr); +    (void) fprintf(stderr, "Usage: %s [options] [command]\n", _nc_progname); +    if (optstring != NULL) { +	const char *s = msg; +	while (*s != '\0') { +	    fputc(UChar(*s), stderr); +	    if (!strncmp(s, "  -", 3)) { +		if (strchr(optstring, s[3]) == NULL) +		    s = strchr(s, '\n') + 1; +	    } else if (!strncmp(s, "\n\nC", 3)) +		break; +	    ++s; +	} +    } else { +	fputs(msg, stderr); +    }      ExitProgram(ErrUsage);  } @@ -140,7 +152,7 @@ exit_code(int token, int value)   * Returns nonzero on error.   */  static int -tput_cmd(int fd, TTY * saved_settings, bool opt_x, int argc, char *argv[]) +tput_cmd(int fd, TTY * settings, int argc, char **argv, int *used)  {      NCURSES_CONST char *name;      char *s; @@ -150,8 +162,9 @@ tput_cmd(int fd, TTY * saved_settings, bool opt_x, int argc, char *argv[])  #endif      name = check_aliases(argv[0], FALSE); +    *used = 1;      if (is_reset || is_init) { -	TTY oldmode; +	TTY oldmode = *settings;  	int terasechar = -1;	/* new erase character */  	int intrchar = -1;	/* new interrupt character */ @@ -159,23 +172,30 @@ tput_cmd(int fd, TTY * saved_settings, bool opt_x, int argc, char *argv[])  	if (is_reset) {  	    reset_start(stdout, TRUE, FALSE); -	    reset_tty_settings(fd, saved_settings); +	    reset_tty_settings(fd, settings, FALSE);  	} else {  	    reset_start(stdout, FALSE, TRUE);  	}  #if HAVE_SIZECHANGE -	set_window_size(fd, &lines, &columns); +	{ +	    NCURSES_INT2 my_rows = lines; +	    NCURSES_INT2 my_cols = columns; +	    set_window_size(fd, &my_rows, &my_cols); +	    lines = my_rows; +	    columns = my_cols; +	}  #else  	(void) fd;  #endif -	set_control_chars(saved_settings, terasechar, intrchar, tkillchar); -	set_conversions(saved_settings); +	set_control_chars(settings, terasechar, intrchar, tkillchar); +	set_conversions(settings); +  	if (send_init_strings(fd, &oldmode)) {  	    reset_flush();  	} -	update_tty_settings(&oldmode, saved_settings); +	update_tty_settings(&oldmode, settings);  	return 0;      } @@ -221,17 +241,21 @@ tput_cmd(int fd, TTY * saved_settings, bool opt_x, int argc, char *argv[])      } else if (VALID_STRING(s)) {  	if (argc > 1) {  	    int k; -	    int ignored; +	    int narg; +	    int analyzed; +	    int provided; +	    int popcount;  	    long numbers[1 + NUM_PARM];  	    char *strings[1 + NUM_PARM];  	    char *p_is_s[NUM_PARM]; +	    TParams paramType;  	    /* Nasty hack time. The tparm function needs to see numeric  	     * parameters as numbers, not as pointers to their string  	     * representations  	     */ -	    for (k = 1; (k < argc) && (k < NUM_PARM); k++) { +	    for (k = 1; (k < argc) && (k <= NUM_PARM); k++) {  		char *tmp = 0;  		strings[k] = argv[k];  		numbers[k] = strtol(argv[k], &tmp, 0); @@ -243,14 +267,64 @@ tput_cmd(int fd, TTY * saved_settings, bool opt_x, int argc, char *argv[])  		strings[k] = 0;  	    } -	    switch (tparm_type(name)) { +	    paramType = tparm_type(name); +#if NCURSES_XNAMES +	    /* +	     * If the capability is an extended one, analyze the string. +	     */ +	    if (paramType == Numbers) { +		struct name_table_entry const *entry_ptr; +		entry_ptr = _nc_find_type_entry(name, STRING, FALSE); +		if (entry_ptr == NULL) { +		    paramType = Other; +		} +	    } +#endif + +	    popcount = 0; +	    _nc_reset_tparm(NULL); +	    /* +	     * Count the number of numeric parameters which are provided. +	     */ +	    provided = 0; +	    for (narg = 1; narg < argc; ++narg) { +		char *ending = NULL; +		long check = strtol(argv[narg], &ending, 0); +		if (check < 0 || ending == argv[narg] || *ending != '\0') +		    break; +		provided = narg; +	    } +	    switch (paramType) { +	    case Str: +		s = TPARM_1(s, strings[1]); +		analyzed = 1; +		if (provided == 0 && argc >= 1) +		    provided++; +		break; +	    case Str_Str: +		s = TPARM_2(s, strings[1], strings[2]); +		analyzed = 2; +		if (provided == 0 && argc >= 1) +		    provided++; +		if (provided == 1 && argc >= 2) +		    provided++; +		break;  	    case Num_Str:  		s = TPARM_2(s, numbers[1], strings[2]); +		analyzed = 2; +		if (provided == 1 && argc >= 2) +		    provided++;  		break;  	    case Num_Str_Str:  		s = TPARM_3(s, numbers[1], strings[2], strings[3]); +		analyzed = 3; +		if (provided == 1 && argc >= 2) +		    provided++; +		if (provided == 2 && argc >= 3) +		    provided++;  		break;  	    case Numbers: +		analyzed = _nc_tparm_analyze(NULL, s, p_is_s, &popcount);  #define myParam(n) numbers[n]  		s = TIPARM_9(s,  			     myParam(1), @@ -267,7 +341,7 @@ tput_cmd(int fd, TTY * saved_settings, bool opt_x, int argc, char *argv[])  	    case Other:  		/* FALLTHRU */  	    default: -		(void) _nc_tparm_analyze(s, p_is_s, &ignored); +		analyzed = _nc_tparm_analyze(NULL, s, p_is_s, &popcount);  #define myParam(n) (p_is_s[n - 1] != 0 ? ((TPARM_ARG) strings[n]) : numbers[n])  		s = TPARM_9(s,  			    myParam(1), @@ -282,6 +356,16 @@ tput_cmd(int fd, TTY * saved_settings, bool opt_x, int argc, char *argv[])  #undef myParam  		break;  	    } +	    if (analyzed < popcount) { +		analyzed = popcount; +	    } +	    if (opt_v && (analyzed != provided)) { +		fprintf(stderr, "%s: %s parameters for \"%s\"\n", +			_nc_progname, +			(analyzed < provided ? "extra" : "missing"), +			argv[0]); +	    } +	    *used += provided;  	}  	/* use putp() in order to perform padding */ @@ -301,16 +385,18 @@ main(int argc, char **argv)      char buf[BUFSIZ];      int result = 0;      int fd; +    int used; +    TTY old_settings;      TTY tty_settings; -    bool opt_x = FALSE;		/* clear scrollback if possible */      bool is_alias;      bool need_tty; -    prg_name = check_aliases(_nc_rootname(argv[0]), TRUE); +    _nc_progname = check_aliases(_nc_rootname(argv[0]), TRUE); +    is_alias = (is_clear || is_reset || is_init);      term = getenv("TERM"); -    while ((c = getopt(argc, argv, "ST:Vx")) != -1) { +    while ((c = getopt(argc, argv, is_alias ? "T:Vvx" : "ST:Vvx")) != -1) {  	switch (c) {  	case 'S':  	    cmdline = FALSE; @@ -323,16 +409,18 @@ main(int argc, char **argv)  	case 'V':  	    puts(curses_version());  	    ExitProgram(EXIT_SUCCESS); +	case 'v':		/* verbose */ +	    opt_v = TRUE; +	    break;  	case 'x':		/* do not try to clear scrollback */  	    opt_x = TRUE;  	    break;  	default: -	    usage(); +	    usage(is_alias ? "TVx" : NULL);  	    /* NOTREACHED */  	}      } -    is_alias = (is_clear || is_reset || is_init);      need_tty = ((is_reset || is_init) ||  		(optind < argc &&  		 (!strcmp(argv[optind], "reset") || @@ -346,7 +434,7 @@ main(int argc, char **argv)  	    argc -= optind;  	    argv += optind;  	} -	argv[0] = prg_name; +	argv[0] = strdup(_nc_progname);      } else {  	argc -= optind;  	argv += optind; @@ -356,39 +444,62 @@ main(int argc, char **argv)  	quit(ErrUsage, "No value for $TERM and no -T specified");      fd = save_tty_settings(&tty_settings, need_tty); +    old_settings = tty_settings;      if (setupterm(term, fd, &errret) != OK && errret <= 0)  	quit(ErrTermType, "unknown terminal \"%s\"", term);      if (cmdline) { +	int code = 0;  	if ((argc <= 0) && !is_alias) -	    usage(); -	ExitProgram(tput_cmd(fd, &tty_settings, opt_x, argc, argv)); +	    usage(NULL); +	while (argc > 0) { +	    tty_settings = old_settings; +	    code = tput_cmd(fd, &tty_settings, argc, argv, &used); +	    if (code != 0) +		break; +	    argc -= used; +	    argv += used; +	} +	ExitProgram(code);      }      while (fgets(buf, sizeof(buf), stdin) != 0) { -	char *argvec[16];	/* command, 9 parms, null, & slop */ +	size_t need = strlen(buf); +	char **argvec = typeCalloc(char *, need + 1); +	char **argnow;  	int argnum = 0;  	char *cp; -	/* crack the argument list into a dope vector */ +	if (argvec == NULL) { +	    quit(ErrSystem(1), strerror(errno)); +	} + +	/* split the buffer into tokens */  	for (cp = buf; *cp; cp++) {  	    if (isspace(UChar(*cp))) {  		*cp = '\0'; -	    } else if (cp == buf || cp[-1] == 0) { +	    } else if (cp == buf || cp[-1] == '\0') {  		argvec[argnum++] = cp; -		if (argnum >= (int) SIZEOF(argvec) - 1) +		if (argnum >= (int) need)  		    break;  	    }  	} -	argvec[argnum] = 0; -	if (argnum != 0 -	    && tput_cmd(fd, &tty_settings, opt_x, argnum, argvec) != 0) { -	    if (result == 0) -		result = ErrSystem(0);	/* will return value >4 */ -	    ++result; +	argnow = argvec; +	while (argnum > 0) { +	    int code; +	    tty_settings = old_settings; +	    code = tput_cmd(fd, &tty_settings, argnum, argnow, &used); +	    if (code != 0) { +		if (result == 0) +		    result = ErrSystem(0);	/* will return value >4 */ +		++result; +	    } +	    argnum -= used; +	    argnow += used;  	} +	free(argvec);      }      ExitProgram(result);  | 
