[BACK]Return to tput.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / tput

Diff for /src/usr.bin/tput/tput.c between version 1.29 and 1.30

version 1.29, 2023/09/06 05:04:07 version 1.30, 2023/10/17 09:52:11
Line 1 
Line 1 
 /*      $OpenBSD$       */  /*      $OpenBSD$       */
   
   /****************************************************************************
    * Copyright 2018-2022,2023 Thomas E. Dickey                                *
    * Copyright 1998-2016,2017 Free Software Foundation, Inc.                  *
    *                                                                          *
    * Permission is hereby granted, free of charge, to any person obtaining a  *
    * copy of this software and associated documentation files (the            *
    * "Software"), to deal in the Software without restriction, including      *
    * without limitation the rights to use, copy, modify, merge, publish,      *
    * distribute, distribute with modifications, sublicense, and/or sell       *
    * copies of the Software, and to permit persons to whom the Software is    *
    * furnished to do so, subject to the following conditions:                 *
    *                                                                          *
    * The above copyright notice and this permission notice shall be included  *
    * in all copies or substantial portions of the Software.                   *
    *                                                                          *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
    * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
    * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
    * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
    * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
    * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
    * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
    *                                                                          *
    * Except as contained in this notice, the name(s) of the above copyright   *
    * holders shall not be used in advertising or otherwise to promote the     *
    * sale, use or other dealings in this Software without prior written       *
    * authorization.                                                           *
    ****************************************************************************/
   
   /****************************************************************************
    *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
    *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
    *     and: Thomas E. Dickey                        1996-on                 *
    ****************************************************************************/
   
 /*  /*
  * Copyright (c) 1999 Todd C. Miller <millert@openbsd.org>   * tput.c -- shellscript access to terminal capabilities
  *   *
  * Permission to use, copy, modify, and distribute this software for any   * by Eric S. Raymond <esr@snark.thyrsus.com>, portions based on code from
  * purpose with or without fee is hereby granted, provided that the above   * Ross Ridge's mytinfo package.
  * copyright notice and this permission notice appear in all copies.  
  *  
  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES  
  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF  
  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR  
  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES  
  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN  
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF  
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.  
  */   */
 /*-  
  * Copyright (c) 1980, 1988, 1993  
  *      The Regents of the University of California.  All rights reserved.  
  *  
  * Redistribution and use in source and binary forms, with or without  
  * modification, are permitted provided that the following conditions  
  * are met:  
  * 1. Redistributions of source code must retain the above copyright  
  *    notice, this list of conditions and the following disclaimer.  
  * 2. Redistributions in binary form must reproduce the above copyright  
  *    notice, this list of conditions and the following disclaimer in the  
  *    documentation and/or other materials provided with the distribution.  
  * 3. Neither the name of the University nor the names of its contributors  
  *    may be used to endorse or promote products derived from this software  
  *    without specific prior written permission.  
  *  
  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND  
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE  
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS  
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)  
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT  
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY  
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF  
  * SUCH DAMAGE.  
  */  
   
 #include <sys/wait.h>  #include <tparm_type.h>
 #include <ctype.h>  #include <clear_cmd.h>
 #include <err.h>  #include <reset_cmd.h>
 #include <curses.h>  
 #include <term.h>  
 #include <stdio.h>  
 #include <stdlib.h>  
 #include <unistd.h>  
 #include <errno.h>  
 #include <limits.h>  
 #include <string.h>  
   
 #define MAXIMUM(a, b)   (((a) > (b)) ? (a) : (b))  #include <transform.h>
   #include <tty_settings.h>
   
 #define NUM_PARM        9       /* must match tic.h */  
   
 static void   init(void);  
 static char **process(char *, char *, char **);  
 static void   reset(void);  
 static void   set_margins(void);  
 static void   usage(void);  
   
 extern char  *__progname;  #define PUTS(s)         fputs(s, stdout)
 extern int _nc_tparm_analyze(const char *string, char *p_is_s[NUM_PARM], int *popcount);  
   
 int  const char *_nc_progname = "tput";
 main(int argc, char *argv[])  
 {  
         int ch, exitval, n, Sflag;  
         size_t len;  
         char *p, *term, *str;  
         char **oargv;  
   
         if (pledge("stdio rpath wpath tty", NULL) == -1)  static bool opt_v = FALSE;      /* quiet, do not show warnings */
                 err(1, "pledge");  static bool opt_x = FALSE;      /* clear scrollback if possible */
   
         oargv = argv;  static bool is_init = FALSE;
         term = NULL;  static bool is_reset = FALSE;
         Sflag = exitval = 0;  static bool is_clear = FALSE;
         while ((ch = getopt(argc, argv, "ST:")) != -1)  
                 switch(ch) {  
                 case 'T':  
                         term = optarg;  
                         break;  
                 case 'S':  
                         Sflag = 1;  
                         break;  
                 default:  
                         usage();  
                 }  
         argc -= optind;  
         argv += optind;  
   
         if (Sflag && argc > 0)  static GCC_NORETURN void
                 usage();  quit(int status, const char *fmt, ...)
   {
       va_list argp;
   
         if (!term && !(term = getenv("TERM")))      va_start(argp, fmt);
                 errx(2, "No value for $TERM and no -T specified");      fprintf(stderr, "%s: ", _nc_progname);
       vfprintf(stderr, fmt, argp);
       fprintf(stderr, "\n");
       va_end(argp);
       ExitProgram(status);
   }
   
         /*  static GCC_NORETURN void
          * NOTE: tgetent() will call setupterm() and set ospeed for us  usage(const char *optstring)
          * (this is ncurses-specific behavior)  {
          */  #define KEEP(s) s "\n"
         if (tgetent(NULL, term) != 1)      static const char msg[] =
                 errx(3, "Unknown terminal type `%s'", term);      {
           KEEP("")
         if (strcmp(__progname, "clear") == 0) {          KEEP("Options:")
                 if (Sflag)          KEEP("  -S <<       read commands from standard input")
                         usage();          KEEP("  -T TERM     use this instead of $TERM")
                 argv = oargv;          KEEP("  -V          print curses-version")
                 *argv = __progname;          KEEP("  -v          verbose, show warnings")
                 *(argv+1) = NULL;          KEEP("  -x          do not try to clear scrollback")
           KEEP("")
           KEEP("Commands:")
           KEEP("  clear       clear the screen")
           KEEP("  init        initialize the terminal")
           KEEP("  reset       reinitialize the terminal")
           KEEP("  capname     unlike clear/init/reset, print value for capability \"capname\"")
       };
   #undef KEEP
       (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;
         }          }
         if (Sflag) {      } else {
                 char **av;          fputs(msg, stderr);
       }
       ExitProgram(ErrUsage);
   }
   
                 /* Build new argv based on stdin */  static char *
                 argc = n = 0;  check_aliases(char *name, bool program)
                 av = NULL;  {
                 while ((str = fgetln(stdin, &len)) != NULL) {      static char my_init[] = "init";
                         if (str[len-1] != '\n')      static char my_reset[] = "reset";
                                 errx(1, "premature EOF");      static char my_clear[] = "clear";
                         str[len-1] = '\0';  
                         while ((p = strsep(&str, " \t")) != NULL) {  
                                 /* grow av as needed */  
                                 if (argc + 1 >= n) {  
                                         n += 64;  
                                         av = reallocarray(av, n,  
                                             sizeof(char *));  
                                         if (av == NULL)  
                                                 errx(1, "out of memory");  
                                 }  
                                 if (*p != '\0' &&  
                                     (av[argc++] = strdup(p)) == NULL)  
                                         errx(1, "out of memory");  
                         }  
                 }  
                 if (argc > 0) {  
                         av[argc] = NULL;  
                         argv = av;  
                 }  
         }  
         while ((p = *argv++)) {  
                 switch (*p) {  
                 case 'i':  
                         if (!strcmp(p, "init")) {  
                                 init();  
                                 continue;  
                         }  
                         break;  
                 case 'l':  
                         if (!strcmp(p, "longname")) {  
                                 puts(longname());  
                                 continue;  
                         }  
                         break;  
                 case 'r':  
                         if (!strcmp(p, "reset")) {  
                                 reset();  
                                 continue;  
                         }  
                         break;  
                 }  
   
                 /* First try as terminfo */      char *result = name;
                 if ((str = tigetstr(p)) && str != (char *)-1)      if ((is_init = same_program(name, program ? PROG_INIT : my_init)))
                         argv = process(p, str, argv);          result = my_init;
                 else if ((n = tigetnum(p)) != -2)      if ((is_reset = same_program(name, program ? PROG_RESET : my_reset)))
                         (void)printf("%d\n", n);          result = my_reset;
                 else if ((n = tigetflag(p)) != -1)      if ((is_clear = same_program(name, program ? PROG_CLEAR : my_clear)))
                         exitval = !n;          result = my_clear;
                 /* Then fall back on termcap */      return result;
                 else if ((str = tgetstr(p, NULL)))  
                         argv = process(p, str, argv);  
                 else if ((n = tgetnum(p)) != -1)  
                         (void)printf("%d\n", n);  
                 else if ((exitval = tgetflag(p)) != 0)  
                         exitval = !exitval;  
                 else {  
                         warnx("Unknown terminfo capability `%s'", p);  
                         exitval = 4;  
                 }  
         }  
         exit(exitval);  
 }  }
   
 static char **  static int
 process(char *cap, char *str, char **argv)  exit_code(int token, int value)
 {  {
         char *s, *nargv[NUM_PARM] = {0};      int result = 99;
         char *p_is_s[NUM_PARM];  
         int arg_need, i;  
   
         /* Count how many values we need for this capability. */      switch (token) {
         i = _nc_tparm_analyze(str, p_is_s, &arg_need);      case BOOLEAN:
         if (arg_need == 0)          result = !value;        /* TRUE=0, FALSE=1 */
                 arg_need = i;          break;
         if (arg_need > NUM_PARM)      case NUMBER:
                 errx(2, "too many arguments (%d) for capability `%s'",          result = 0;             /* always zero */
                     arg_need, cap);          break;
       case STRING:
         for (i = 0; i < arg_need; i++) {          result = value;         /* 0=normal, 1=missing */
                 const char *errstr;          break;
                 long l;      }
       return result;
   }
   
                 if (argv[i] == NULL)  /*
                         errx(2, "not enough arguments (%d) for capability `%s'",   * Returns nonzero on error.
                             arg_need, cap);   */
   static int
   tput_cmd(int fd, TTY * settings, int argc, char **argv, int *used)
   {
       NCURSES_CONST char *name;
       char *s;
       int status;
   #if !PURE_TERMINFO
       bool termcap = FALSE;
   #endif
   
                 if (p_is_s[i] != 0) {      name = check_aliases(argv[0], FALSE);
                         nargv[i] = argv[i];      *used = 1;
                 } else {      if (is_reset || is_init) {
                         /* convert ascii representation of numbers to longs */          TTY oldmode = *settings;
                         l = strtonum(argv[i], LONG_MIN, LONG_MAX, &errstr);  
                         if (errstr != NULL)          int terasechar = -1;    /* new erase character */
                                 errx(2, "capability `%s' is %s", cap, errstr);          int intrchar = -1;      /* new interrupt character */
                         nargv[i] = (char *)l;          int tkillchar = -1;     /* new kill character */
                 }  
           if (is_reset) {
               reset_start(stdout, TRUE, FALSE);
               reset_tty_settings(fd, settings, FALSE);
           } else {
               reset_start(stdout, FALSE, TRUE);
         }          }
   
         s = tparm(str, nargv[0], nargv[1], nargv[2], nargv[3],  #if HAVE_SIZECHANGE
             nargv[4], nargv[5], nargv[6], nargv[7], nargv[8]);          set_window_size(fd, &lines, &columns);
         putp(s);  #else
         fflush(stdout);          (void) fd;
   #endif
           set_control_chars(settings, terasechar, intrchar, tkillchar);
           set_conversions(settings);
   
         return (argv + arg_need);          if (send_init_strings(fd, &oldmode)) {
 }              reset_flush();
           }
   
 static void          update_tty_settings(&oldmode, settings);
 init(void)          return 0;
 {      }
         FILE *ifile;  
         size_t len;  
         char *buf;  
         int wstatus;  
         pid_t pid;  
   
         if (init_prog && !issetugid()) {      if (strcmp(name, "longname") == 0) {
                 switch (pid = vfork()) {          PUTS(longname());
                 case -1:          return 0;
                         err(4, "vfork");      }
                         break;  #if !PURE_TERMINFO
                 case 0:    retry:
                         /* child */  #endif
                         execl(init_prog, init_prog, (char *)NULL);      if (strcmp(name, "clear") == 0) {
                         _exit(127);          return (clear_cmd(opt_x) == ERR) ? ErrUsage : 0;
                         break;      } else if ((status = tigetflag(name)) != -1) {
                 default:          return exit_code(BOOLEAN, status);
                         while (waitpid(pid, &wstatus, 0) == -1) {      } else if ((status = tigetnum(name)) != CANCELLED_NUMERIC) {
                                 if (errno != EINTR)          (void) printf("%d\n", status);
                                         break;          return exit_code(NUMBER, 0);
                         }      } else if ((s = tigetstr(name)) == CANCELLED_STRING) {
                         /* parent */  #if !PURE_TERMINFO
                         break;          if (!termcap) {
               const struct name_table_entry *np;
   
               termcap = TRUE;
               if ((np = _nc_find_entry(name, _nc_get_hash_table(termcap))) != 0) {
                   switch (np->nte_type) {
                   case BOOLEAN:
                       name = boolnames[np->nte_index];
                       break;
   
                   case NUMBER:
                       name = numnames[np->nte_index];
                       break;
   
                   case STRING:
                       name = strnames[np->nte_index];
                       break;
                 }                  }
                   goto retry;
               }
         }          }
         if (init_1string)  #endif
                 putp(init_1string);          quit(ErrCapName, "unknown terminfo capability '%s'", name);
         if (init_2string)      } else if (VALID_STRING(s)) {
                 putp(init_2string);          if (argc > 1) {
         set_margins();              int k;
         /* always use 8 space tabs */              int narg;
         if (init_tabs != 8 && clear_all_tabs && set_tab) {              int analyzed;
                 int i;              int provided;
               int popcount;
               long numbers[1 + NUM_PARM];
               char *strings[1 + NUM_PARM];
               char *p_is_s[NUM_PARM];
               TParams paramType;
   
                 putp(clear_all_tabs);              /* Nasty hack time. The tparm function needs to see numeric
                 for (i = 0; i < (columns - 1) / 8; i++) {               * parameters as numbers, not as pointers to their string
                         if (parm_right_cursor)               * representations
                                 putp(tparm(parm_right_cursor, 8));               */
                         else  
                                 fputs("        ", stdout);              for (k = 1; (k < argc) && (k <= NUM_PARM); k++) {
                         putp(set_tab);                  char *tmp = 0;
                   strings[k] = argv[k];
                   numbers[k] = strtol(argv[k], &tmp, 0);
                   if (tmp == 0 || *tmp != 0)
                       numbers[k] = 0;
               }
               for (k = argc; k <= NUM_PARM; k++) {
                   numbers[k] = 0;
                   strings[k] = 0;
               }
   
               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, 10);
                   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),
                                myParam(2),
                                myParam(3),
                                myParam(4),
                                myParam(5),
                                myParam(6),
                                myParam(7),
                                myParam(8),
                                myParam(9));
   #undef myParam
                   break;
               case Other:
                   /* FALLTHRU */
               default:
                   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),
                               myParam(2),
                               myParam(3),
                               myParam(4),
                               myParam(5),
                               myParam(6),
                               myParam(7),
                               myParam(8),
                               myParam(9));
   #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;
         }          }
         if (init_file && !issetugid() && (ifile = fopen(init_file, "r"))) {  
                 while ((buf = fgetln(ifile, &len)) != NULL) {          /* use putp() in order to perform padding */
                         if (buf[len-1] != '\n')          putp(s);
                                 errx(1, "premature EOF reading %s", init_file);          return exit_code(STRING, 0);
                         buf[len-1] = '\0';      }
                         putp(buf);      return exit_code(STRING, 1);
                 }  
                 fclose(ifile);  
         }  
         if (init_3string)  
                 putp(init_3string);  
         fflush(stdout);  
 }  }
   
 static void  int
 reset(void)  main(int argc, char **argv)
 {  {
         FILE *rfile;      char *term;
         size_t len;      int errret;
         char *buf;      bool cmdline = TRUE;
       int c;
       char buf[BUFSIZ];
       int result = 0;
       int fd;
       int used;
       TTY old_settings;
       TTY tty_settings;
       bool is_alias;
       bool need_tty;
   
         if (reset_1string)      if (pledge("stdio rpath wpath tty", NULL) == -1) {
                 putp(reset_1string);          perror("pledge");
         if (reset_2string)          exit(1);
                 putp(reset_2string);      }
         set_margins();  
         if (reset_file && !issetugid() && (rfile = fopen(reset_file, "r"))) {      _nc_progname = check_aliases(_nc_rootname(argv[0]), TRUE);
                 while ((buf = fgetln(rfile, &len)) != NULL) {      is_alias = (is_clear || is_reset || is_init);
                         if (buf[len-1] != '\n')  
                                 errx(1, "premature EOF reading %s", reset_file);      term = getenv("TERM");
                         buf[len-1] = '\0';  
                         putp(buf);      while ((c = getopt(argc, argv, is_alias ? "T:Vvx" : "ST:Vvx")) != -1) {
                 }          switch (c) {
                 fclose(rfile);          case 'S':
               cmdline = FALSE;
               break;
           case 'T':
               use_env(FALSE);
               use_tioctl(TRUE);
               term = optarg;
               break;
           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(is_alias ? "TVx" : NULL);
               /* NOTREACHED */
         }          }
         if (reset_3string)      }
                 putp(reset_3string);  
         fflush(stdout);  
 }  
   
 static void      need_tty = ((is_reset || is_init) ||
 set_margins(void)                  (optind < argc &&
 {                   (!strcmp(argv[optind], "reset") ||
                     !strcmp(argv[optind], "init"))));
   
         /*      /*
          * Four possibilities:       * Modify the argument list to omit the options we processed.
          *      1) we have set_lr_margin and can set things with one call       */
          *      2) we have set_{left,right}_margin_parm, use two calls      if (is_alias) {
          *      3) we have set_{left,right}_margin, set based on position          if (optind-- < argc) {
          *      4) none of the above, leave things the way they are              argc -= optind;
          */              argv += optind;
         if (set_lr_margin) {          }
                 putp(tparm(set_lr_margin, 0, columns - 1));          argv[0] = strdup(_nc_progname);
         } else if (set_left_margin_parm && set_right_margin_parm) {      } else {
                 putp(tparm(set_left_margin_parm, 0));          argc -= optind;
                 putp(tparm(set_right_margin_parm, columns - 1));          argv += optind;
         } else if (set_left_margin && set_right_margin && clear_margins) {      }
                 putp(clear_margins);  
   
                 /* go to column 0 and set the left margin */      if (term == 0 || *term == '\0')
                 putp(carriage_return ? carriage_return : "\r");          quit(ErrUsage, "No value for $TERM and no -T specified");
                 putp(set_left_margin);  
   
                 /* go to last column and set the right margin */      fd = save_tty_settings(&tty_settings, need_tty);
                 if (parm_right_cursor)      old_settings = tty_settings;
                         putp(tparm(parm_right_cursor, columns - 1));  
                 else      if (setupterm(term, fd, &errret) != OK && errret <= 0)
                         printf("%*s", columns - 1, " ");          quit(ErrTermType, "unknown terminal \"%s\"", term);
                 putp(set_right_margin);  
                 putp(carriage_return ? carriage_return : "\r");      if (cmdline) {
           int code = 0;
           if ((argc <= 0) && !is_alias)
               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;
         }          }
         fflush(stdout);          ExitProgram(code);
 }      }
   
 static void      while (fgets(buf, sizeof(buf), stdin) != 0) {
 usage(void)          size_t need = strlen(buf);
 {          char **argvec = typeCalloc(char *, need + 1);
           char **argnow;
           int argnum = 0;
           char *cp;
   
         if (strcmp(__progname, "clear") == 0)          if (argvec == NULL) {
                 (void)fprintf(stderr, "usage: %s [-T term]\n", __progname);              quit(ErrSystem(1), strerror(errno));
         else          }
                 (void)fprintf(stderr,  
                     "usage: %s [-T term] attribute [attribute-arg ...] ...\n"          /* split the buffer into tokens */
                     "       %s [-T term] -S\n", __progname, __progname);          for (cp = buf; *cp; cp++) {
         exit(1);              if (isspace(UChar(*cp))) {
                   *cp = '\0';
               } else if (cp == buf || cp[-1] == '\0') {
                   argvec[argnum++] = cp;
                   if (argnum >= (int) need)
                       break;
               }
           }
   
           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);
 }  }

Legend:
Removed from v.1.29  
changed lines
  Added in v.1.30