119304Speter/*- 219304Speter * Copyright (c) 1993, 1994 319304Speter * The Regents of the University of California. All rights reserved. 419304Speter * Copyright (c) 1993, 1994, 1995, 1996 519304Speter * Keith Bostic. All rights reserved. 619304Speter * 719304Speter * See the LICENSE file for redistribution information. 886201Srwatson * 986201Srwatson * $FreeBSD$ 1019304Speter */ 1119304Speter 1219304Speter#include "config.h" 1319304Speter 1419304Speter#ifndef lint 1519304Speterstatic const char sccsid[] = "@(#)cl_screen.c 10.49 (Berkeley) 9/24/96"; 1619304Speter#endif /* not lint */ 1719304Speter 1819304Speter#include <sys/types.h> 1919304Speter#include <sys/queue.h> 2019304Speter 2119304Speter#include <bitstring.h> 2219304Speter#include <curses.h> 2319304Speter#include <errno.h> 2419304Speter#include <signal.h> 2519304Speter#include <stdio.h> 2619304Speter#include <stdlib.h> 2719304Speter#include <string.h> 28170371Srafan#include <term.h> 2919304Speter#include <termios.h> 3019304Speter#include <unistd.h> 3119304Speter 3219304Speter#include "../common/common.h" 3319304Speter#include "cl.h" 3419304Speter 3519304Speterstatic int cl_ex_end __P((GS *)); 3619304Speterstatic int cl_ex_init __P((SCR *)); 3719304Speterstatic void cl_freecap __P((CL_PRIVATE *)); 3819304Speterstatic int cl_vi_end __P((GS *)); 3919304Speterstatic int cl_vi_init __P((SCR *)); 4019304Speterstatic int cl_putenv __P((char *, char *, u_long)); 4119304Speter 4219304Speter/* 4319304Speter * cl_screen -- 4419304Speter * Switch screen types. 4519304Speter * 4619304Speter * PUBLIC: int cl_screen __P((SCR *, u_int32_t)); 4719304Speter */ 4819304Speterint 4919304Spetercl_screen(sp, flags) 5019304Speter SCR *sp; 5119304Speter u_int32_t flags; 5219304Speter{ 5319304Speter CL_PRIVATE *clp; 5419304Speter GS *gp; 5519304Speter 5619304Speter gp = sp->gp; 5719304Speter clp = CLP(sp); 5819304Speter 5919304Speter /* See if the current information is incorrect. */ 6019304Speter if (F_ISSET(gp, G_SRESTART)) { 6119304Speter if (cl_quit(gp)) 6219304Speter return (1); 6319304Speter F_CLR(gp, G_SRESTART); 6419304Speter } 6519304Speter 6619304Speter /* See if we're already in the right mode. */ 6719304Speter if (LF_ISSET(SC_EX) && F_ISSET(sp, SC_SCR_EX) || 6819304Speter LF_ISSET(SC_VI) && F_ISSET(sp, SC_SCR_VI)) 6919304Speter return (0); 7019304Speter 7119304Speter /* 7219304Speter * Fake leaving ex mode. 7319304Speter * 7419304Speter * We don't actually exit ex or vi mode unless forced (e.g. by a window 7519304Speter * size change). This is because many curses implementations can't be 7619304Speter * called twice in a single program. Plus, it's faster. If the editor 7719304Speter * "leaves" vi to enter ex, when it exits ex we'll just fall back into 7819304Speter * vi. 7919304Speter */ 8019304Speter if (F_ISSET(sp, SC_SCR_EX)) 8119304Speter F_CLR(sp, SC_SCR_EX); 8219304Speter 8319304Speter /* 8419304Speter * Fake leaving vi mode. 8519304Speter * 8619304Speter * Clear out the rest of the screen if we're in the middle of a split 8719304Speter * screen. Move to the last line in the current screen -- this makes 8819304Speter * terminal scrolling happen naturally. Note: *don't* move past the 8919304Speter * end of the screen, as there are ex commands (e.g., :read ! cat file) 9019304Speter * that don't want to. Don't clear the info line, its contents may be 9119304Speter * valid, e.g. :file|append. 9219304Speter */ 9319304Speter if (F_ISSET(sp, SC_SCR_VI)) { 9419304Speter F_CLR(sp, SC_SCR_VI); 9519304Speter 9619304Speter if (sp->q.cqe_next != (void *)&gp->dq) { 9719304Speter (void)move(RLNO(sp, sp->rows), 0); 9819304Speter clrtobot(); 9919304Speter } 10019304Speter (void)move(RLNO(sp, sp->rows) - 1, 0); 10119304Speter refresh(); 10219304Speter } 10319304Speter 10419304Speter /* Enter the requested mode. */ 10519304Speter if (LF_ISSET(SC_EX)) { 10619304Speter if (cl_ex_init(sp)) 10719304Speter return (1); 10819304Speter F_SET(clp, CL_IN_EX | CL_SCR_EX_INIT); 10919304Speter 11019304Speter /* 11119304Speter * If doing an ex screen for ex mode, move to the last line 11219304Speter * on the screen. 11319304Speter */ 11419304Speter if (F_ISSET(sp, SC_EX) && clp->cup != NULL) 11519304Speter tputs(tgoto(clp->cup, 11619304Speter 0, O_VAL(sp, O_LINES) - 1), 1, cl_putchar); 11719304Speter } else { 11819304Speter if (cl_vi_init(sp)) 11919304Speter return (1); 12019304Speter F_CLR(clp, CL_IN_EX); 12119304Speter F_SET(clp, CL_SCR_VI_INIT); 12219304Speter } 12319304Speter return (0); 12419304Speter} 12519304Speter 12619304Speter/* 12719304Speter * cl_quit -- 12819304Speter * Shutdown the screens. 12919304Speter * 13019304Speter * PUBLIC: int cl_quit __P((GS *)); 13119304Speter */ 13219304Speterint 13319304Spetercl_quit(gp) 13419304Speter GS *gp; 13519304Speter{ 13619304Speter CL_PRIVATE *clp; 13719304Speter int rval; 13819304Speter 13919304Speter rval = 0; 14019304Speter clp = GCLP(gp); 14119304Speter 14219304Speter /* 14319304Speter * If we weren't really running, ignore it. This happens if the 14419304Speter * screen changes size before we've called curses. 14519304Speter */ 14619304Speter if (!F_ISSET(clp, CL_SCR_EX_INIT | CL_SCR_VI_INIT)) 14719304Speter return (0); 14819304Speter 14919304Speter /* Clean up the terminal mappings. */ 15019304Speter if (cl_term_end(gp)) 15119304Speter rval = 1; 15219304Speter 15319304Speter /* Really leave vi mode. */ 15419304Speter if (F_ISSET(clp, CL_STDIN_TTY) && 15519304Speter F_ISSET(clp, CL_SCR_VI_INIT) && cl_vi_end(gp)) 15619304Speter rval = 1; 15719304Speter 15819304Speter /* Really leave ex mode. */ 15919304Speter if (F_ISSET(clp, CL_STDIN_TTY) && 16019304Speter F_ISSET(clp, CL_SCR_EX_INIT) && cl_ex_end(gp)) 16119304Speter rval = 1; 16219304Speter 16319304Speter /* 16419304Speter * If we were running ex when we quit, or we're using an implementation 16519304Speter * of curses where endwin() doesn't get this right, restore the original 16619304Speter * terminal modes. 16719304Speter * 16819304Speter * XXX 16919304Speter * We always do this because it's too hard to figure out what curses 17019304Speter * implementations get it wrong. It may discard type-ahead characters 17119304Speter * from the tty queue. 17219304Speter */ 17319304Speter (void)tcsetattr(STDIN_FILENO, TCSADRAIN | TCSASOFT, &clp->orig); 17419304Speter 17519304Speter F_CLR(clp, CL_SCR_EX_INIT | CL_SCR_VI_INIT); 17619304Speter return (rval); 17719304Speter} 17819304Speter 17919304Speter/* 18019304Speter * cl_vi_init -- 18119304Speter * Initialize the curses vi screen. 18219304Speter */ 18319304Speterstatic int 18419304Spetercl_vi_init(sp) 18519304Speter SCR *sp; 18619304Speter{ 18719304Speter CL_PRIVATE *clp; 18819304Speter GS *gp; 18919304Speter char *o_cols, *o_lines, *o_term, *ttype; 19019304Speter 19119304Speter gp = sp->gp; 19219304Speter clp = CLP(sp); 19319304Speter 19419304Speter /* If already initialized, just set the terminal modes. */ 19519304Speter if (F_ISSET(clp, CL_SCR_VI_INIT)) 19619304Speter goto fast; 19719304Speter 19819304Speter /* Curses vi always reads from (and writes to) a terminal. */ 19919304Speter if (!F_ISSET(clp, CL_STDIN_TTY) || !isatty(STDOUT_FILENO)) { 20019304Speter msgq(sp, M_ERR, 20119304Speter "016|Vi's standard input and output must be a terminal"); 20219304Speter return (1); 20319304Speter } 20419304Speter 20519304Speter /* We'll need a terminal type. */ 20619304Speter if (opts_empty(sp, O_TERM, 0)) 20719304Speter return (1); 20819304Speter ttype = O_STR(sp, O_TERM); 20919304Speter 21019304Speter /* 21119304Speter * XXX 21219304Speter * Changing the row/column and terminal values is done by putting them 21319304Speter * into the environment, which is then read by curses. What this loses 21419304Speter * in ugliness, it makes up for in stupidity. We can't simply put the 21519304Speter * values into the environment ourselves, because in the presence of a 21619304Speter * kernel mechanism for returning the window size, entering values into 21719304Speter * the environment will screw up future screen resizing events, e.g. if 21819304Speter * the user enters a :shell command and then resizes their window. So, 21919304Speter * if they weren't already in the environment, we make sure to delete 22019304Speter * them immediately after setting them. 22119304Speter * 22219304Speter * XXX 22319304Speter * Putting the TERM variable into the environment is necessary, even 22419304Speter * though we're using newterm() here. We may be using initscr() as 22519304Speter * the underlying function. 22619304Speter */ 22719304Speter o_term = getenv("TERM"); 22819304Speter cl_putenv("TERM", ttype, 0); 22919304Speter o_lines = getenv("LINES"); 23019304Speter cl_putenv("LINES", NULL, (u_long)O_VAL(sp, O_LINES)); 23119304Speter o_cols = getenv("COLUMNS"); 23219304Speter cl_putenv("COLUMNS", NULL, (u_long)O_VAL(sp, O_COLUMNS)); 23319304Speter 23419304Speter /* 23519304Speter * We don't care about the SCREEN reference returned by newterm, we 23619304Speter * never have more than one SCREEN at a time. 23719304Speter * 23819304Speter * XXX 23919304Speter * The SunOS initscr() can't be called twice. Don't even think about 24019304Speter * using it. It fails in subtle ways (e.g. select(2) on fileno(stdin) 24119304Speter * stops working). (The SVID notes that applications should only call 24219304Speter * initscr() once.) 24319304Speter * 24419304Speter * XXX 24519304Speter * The HP/UX newterm doesn't support the NULL first argument, so we 24619304Speter * have to specify the terminal type. 24719304Speter */ 24819304Speter errno = 0; 24919304Speter if (newterm(ttype, stdout, stdin) == NULL) { 25019304Speter if (errno) 25119304Speter msgq(sp, M_SYSERR, "%s", ttype); 25219304Speter else 25319304Speter msgq(sp, M_ERR, "%s: unknown terminal type", ttype); 25419304Speter return (1); 25519304Speter } 25619304Speter 25719304Speter if (o_term == NULL) 25819304Speter unsetenv("TERM"); 25919304Speter if (o_lines == NULL) 26019304Speter unsetenv("LINES"); 26119304Speter if (o_cols == NULL) 26219304Speter unsetenv("COLUMNS"); 26319304Speter 26419304Speter /* 26519304Speter * XXX 26619304Speter * Someone got let out alone without adult supervision -- the SunOS 26719304Speter * newterm resets the signal handlers. There's a race, but it's not 26819304Speter * worth closing. 26919304Speter */ 27019304Speter (void)sig_init(sp->gp, sp); 27119304Speter 27219304Speter /* 27319304Speter * We use raw mode. What we want is 8-bit clean, however, signals 27419304Speter * and flow control should continue to work. Admittedly, it sounds 27519304Speter * like cbreak, but it isn't. Using cbreak() can get you additional 27619304Speter * things like IEXTEN, which turns on flags like DISCARD and LNEXT. 27719304Speter * 27819304Speter * !!! 27919304Speter * If raw isn't turning off echo and newlines, something's wrong. 28019304Speter * However, it shouldn't hurt. 28119304Speter */ 28219304Speter noecho(); /* No character echo. */ 28319304Speter nonl(); /* No CR/NL translation. */ 28419304Speter raw(); /* 8-bit clean. */ 28519304Speter idlok(stdscr, 1); /* Use hardware insert/delete line. */ 28619304Speter 28719304Speter /* Put the cursor keys into application mode. */ 28819304Speter (void)keypad(stdscr, TRUE); 28919304Speter 29019304Speter /* 29119304Speter * XXX 29219304Speter * The screen TI sequence just got sent. See the comment in 29319304Speter * cl_funcs.c:cl_attr(). 29419304Speter */ 29519304Speter clp->ti_te = TI_SENT; 29619304Speter 29719304Speter /* 29819304Speter * XXX 29919304Speter * Historic implementations of curses handled SIGTSTP signals 30019304Speter * in one of three ways. They either: 30119304Speter * 30219304Speter * 1: Set their own handler, regardless. 30319304Speter * 2: Did not set a handler if a handler was already installed. 30419304Speter * 3: Set their own handler, but then called any previously set 30519304Speter * handler after completing their own cleanup. 30619304Speter * 30719304Speter * We don't try and figure out which behavior is in place, we force 30819304Speter * it to SIG_DFL after initializing the curses interface, which means 30919304Speter * that curses isn't going to take the signal. Since curses isn't 31019304Speter * reentrant (i.e., the whole curses SIGTSTP interface is a fantasy), 31119304Speter * we're doing The Right Thing. 31219304Speter */ 31319304Speter (void)signal(SIGTSTP, SIG_DFL); 31419304Speter 31519304Speter /* 31619304Speter * If flow control was on, turn it back on. Turn signals on. ISIG 31719304Speter * turns on VINTR, VQUIT, VDSUSP and VSUSP. The main curses code 31819304Speter * already installed a handler for VINTR. We're going to disable the 31919304Speter * other three. 32019304Speter * 32119304Speter * XXX 32219304Speter * We want to use ^Y as a vi scrolling command. If the user has the 32319304Speter * DSUSP character set to ^Y (common practice) clean it up. As it's 32419304Speter * equally possible that the user has VDSUSP set to 'a', we disable 32519304Speter * it regardless. It doesn't make much sense to suspend vi at read, 32619304Speter * so I don't think anyone will care. Alternatively, we could look 32719304Speter * it up in the table of legal command characters and turn it off if 32819304Speter * it matches one. VDSUSP wasn't in POSIX 1003.1-1990, so we test for 32919304Speter * it. 33019304Speter * 33119304Speter * XXX 33219304Speter * We don't check to see if the user had signals enabled originally. 33319304Speter * If they didn't, it's unclear what we're supposed to do here, but 33419304Speter * it's also pretty unlikely. 33519304Speter */ 33619304Speter if (tcgetattr(STDIN_FILENO, &clp->vi_enter)) { 33719304Speter msgq(sp, M_SYSERR, "tcgetattr"); 33819304Speter goto err; 33919304Speter } 34019304Speter if (clp->orig.c_iflag & IXON) 34119304Speter clp->vi_enter.c_iflag |= IXON; 34219304Speter if (clp->orig.c_iflag & IXOFF) 34319304Speter clp->vi_enter.c_iflag |= IXOFF; 34419304Speter 34519304Speter clp->vi_enter.c_lflag |= ISIG; 34619304Speter#ifdef VDSUSP 34719304Speter clp->vi_enter.c_cc[VDSUSP] = _POSIX_VDISABLE; 34819304Speter#endif 34919304Speter clp->vi_enter.c_cc[VQUIT] = _POSIX_VDISABLE; 35019304Speter clp->vi_enter.c_cc[VSUSP] = _POSIX_VDISABLE; 35119304Speter 35219304Speter /* 35319304Speter * XXX 35419304Speter * OSF/1 doesn't turn off the <discard>, <literal-next> or <status> 35519304Speter * characters when curses switches into raw mode. It should be OK 35619304Speter * to do it explicitly for everyone. 35719304Speter */ 35819304Speter#ifdef VDISCARD 35919304Speter clp->vi_enter.c_cc[VDISCARD] = _POSIX_VDISABLE; 36019304Speter#endif 36119304Speter#ifdef VLNEXT 36219304Speter clp->vi_enter.c_cc[VLNEXT] = _POSIX_VDISABLE; 36319304Speter#endif 36419304Speter#ifdef VSTATUS 36519304Speter clp->vi_enter.c_cc[VSTATUS] = _POSIX_VDISABLE; 36619304Speter#endif 36719304Speter 36819304Speter /* Initialize terminal based information. */ 36919304Speter if (cl_term_init(sp)) 37019304Speter goto err; 37119304Speter 37219304Speterfast: /* Set the terminal modes. */ 37319304Speter if (tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &clp->vi_enter)) { 37486201Srwatson if (errno == EINTR) 37586201Srwatson goto fast; 37619304Speter msgq(sp, M_SYSERR, "tcsetattr"); 37719304Spetererr: (void)cl_vi_end(sp->gp); 37819304Speter return (1); 37919304Speter } 38019304Speter return (0); 38119304Speter} 38219304Speter 38319304Speter/* 38419304Speter * cl_vi_end -- 38519304Speter * Shutdown the vi screen. 38619304Speter */ 38719304Speterstatic int 38819304Spetercl_vi_end(gp) 38919304Speter GS *gp; 39019304Speter{ 39119304Speter CL_PRIVATE *clp; 39219304Speter 39319304Speter clp = GCLP(gp); 39419304Speter 39519304Speter /* Restore the cursor keys to normal mode. */ 39619304Speter (void)keypad(stdscr, FALSE); 39719304Speter 39819304Speter /* 39919304Speter * If we were running vi when we quit, scroll the screen up a single 40019304Speter * line so we don't lose any information. 40119304Speter * 40219304Speter * Move to the bottom of the window (some endwin implementations don't 40319304Speter * do this for you). 40419304Speter */ 40519304Speter if (!F_ISSET(clp, CL_IN_EX)) { 40619304Speter (void)move(0, 0); 40719304Speter (void)deleteln(); 40819304Speter (void)move(LINES - 1, 0); 40919304Speter (void)refresh(); 41019304Speter } 41119304Speter 41219304Speter cl_freecap(clp); 41319304Speter 41419304Speter /* End curses window. */ 41519304Speter (void)endwin(); 41619304Speter 41719304Speter /* 41819304Speter * XXX 41919304Speter * The screen TE sequence just got sent. See the comment in 42019304Speter * cl_funcs.c:cl_attr(). 42119304Speter */ 42219304Speter clp->ti_te = TE_SENT; 42319304Speter 42419304Speter return (0); 42519304Speter} 42619304Speter 42719304Speter/* 42819304Speter * cl_ex_init -- 42919304Speter * Initialize the ex screen. 43019304Speter */ 43119304Speterstatic int 43219304Spetercl_ex_init(sp) 43319304Speter SCR *sp; 43419304Speter{ 43519304Speter CL_PRIVATE *clp; 43619304Speter 43719304Speter clp = CLP(sp); 43819304Speter 43919304Speter /* If already initialized, just set the terminal modes. */ 44019304Speter if (F_ISSET(clp, CL_SCR_EX_INIT)) 44119304Speter goto fast; 44219304Speter 44319304Speter /* If not reading from a file, we're done. */ 44419304Speter if (!F_ISSET(clp, CL_STDIN_TTY)) 44519304Speter return (0); 44619304Speter 44719304Speter /* Get the ex termcap/terminfo strings. */ 44819304Speter (void)cl_getcap(sp, "cup", &clp->cup); 44919304Speter (void)cl_getcap(sp, "smso", &clp->smso); 45019304Speter (void)cl_getcap(sp, "rmso", &clp->rmso); 45119304Speter (void)cl_getcap(sp, "el", &clp->el); 45219304Speter (void)cl_getcap(sp, "cuu1", &clp->cuu1); 45319304Speter 45419304Speter /* Enter_standout_mode and exit_standout_mode are paired. */ 45519304Speter if (clp->smso == NULL || clp->rmso == NULL) { 45619304Speter if (clp->smso != NULL) { 45719304Speter free(clp->smso); 45819304Speter clp->smso = NULL; 45919304Speter } 46019304Speter if (clp->rmso != NULL) { 46119304Speter free(clp->rmso); 46219304Speter clp->rmso = NULL; 46319304Speter } 46419304Speter } 46519304Speter 46619304Speter /* 46719304Speter * Turn on canonical mode, with normal input and output processing. 46819304Speter * Start with the original terminal settings as the user probably 46919304Speter * had them (including any local extensions) set correctly for the 47019304Speter * current terminal. 47119304Speter * 47219304Speter * !!! 47319304Speter * We can't get everything that we need portably; for example, ONLCR, 47419304Speter * mapping <newline> to <carriage-return> on output isn't required 47519304Speter * by POSIX 1003.1b-1993. If this turns out to be a problem, then 47619304Speter * we'll either have to play some games on the mapping, or we'll have 47719304Speter * to make all ex printf's output \r\n instead of \n. 47819304Speter */ 47919304Speter clp->ex_enter = clp->orig; 48019304Speter clp->ex_enter.c_lflag |= ECHO | ECHOE | ECHOK | ICANON | IEXTEN | ISIG; 48119304Speter#ifdef ECHOCTL 48219304Speter clp->ex_enter.c_lflag |= ECHOCTL; 48319304Speter#endif 48419304Speter#ifdef ECHOKE 48519304Speter clp->ex_enter.c_lflag |= ECHOKE; 48619304Speter#endif 48719304Speter clp->ex_enter.c_iflag |= ICRNL; 48819304Speter clp->ex_enter.c_oflag |= OPOST; 48919304Speter#ifdef ONLCR 49019304Speter clp->ex_enter.c_oflag |= ONLCR; 49119304Speter#endif 49219304Speter 49319304Speterfast: if (tcsetattr(STDIN_FILENO, TCSADRAIN | TCSASOFT, &clp->ex_enter)) { 49486201Srwatson if (errno == EINTR) 49586201Srwatson goto fast; 49619304Speter msgq(sp, M_SYSERR, "tcsetattr"); 49719304Speter return (1); 49819304Speter } 49919304Speter return (0); 50019304Speter} 50119304Speter 50219304Speter/* 50319304Speter * cl_ex_end -- 50419304Speter * Shutdown the ex screen. 50519304Speter */ 50619304Speterstatic int 50719304Spetercl_ex_end(gp) 50819304Speter GS *gp; 50919304Speter{ 51019304Speter CL_PRIVATE *clp; 51119304Speter 51219304Speter clp = GCLP(gp); 51319304Speter 51419304Speter cl_freecap(clp); 51519304Speter 51619304Speter return (0); 51719304Speter} 51819304Speter 51919304Speter/* 52019304Speter * cl_getcap -- 52119304Speter * Retrieve termcap/terminfo strings. 52219304Speter * 52319304Speter * PUBLIC: int cl_getcap __P((SCR *, char *, char **)); 52419304Speter */ 52519304Speterint 52619304Spetercl_getcap(sp, name, elementp) 52719304Speter SCR *sp; 52819304Speter char *name, **elementp; 52919304Speter{ 53019304Speter size_t len; 53119304Speter char *t; 53219304Speter 53319304Speter if ((t = tigetstr(name)) != NULL && 53419304Speter t != (char *)-1 && (len = strlen(t)) != 0) { 53519304Speter MALLOC_RET(sp, *elementp, char *, len + 1); 53619304Speter memmove(*elementp, t, len + 1); 53719304Speter } 53819304Speter return (0); 53919304Speter} 54019304Speter 54119304Speter/* 54219304Speter * cl_freecap -- 54319304Speter * Free any allocated termcap/terminfo strings. 54419304Speter */ 54519304Speterstatic void 54619304Spetercl_freecap(clp) 54719304Speter CL_PRIVATE *clp; 54819304Speter{ 54919304Speter if (clp->el != NULL) { 55019304Speter free(clp->el); 55119304Speter clp->el = NULL; 55219304Speter } 55319304Speter if (clp->cup != NULL) { 55419304Speter free(clp->cup); 55519304Speter clp->cup = NULL; 55619304Speter } 55719304Speter if (clp->cuu1 != NULL) { 55819304Speter free(clp->cuu1); 55919304Speter clp->cuu1 = NULL; 56019304Speter } 56119304Speter if (clp->rmso != NULL) { 56219304Speter free(clp->rmso); 56319304Speter clp->rmso = NULL; 56419304Speter } 56519304Speter if (clp->smso != NULL) { 56619304Speter free(clp->smso); 56719304Speter clp->smso = NULL; 56819304Speter } 56919304Speter} 57019304Speter 57119304Speter/* 57219304Speter * cl_putenv -- 57319304Speter * Put a value into the environment. 57419304Speter */ 57519304Speterstatic int 57619304Spetercl_putenv(name, str, value) 57719304Speter char *name, *str; 57819304Speter u_long value; 57919304Speter 58019304Speter{ 58119304Speter char buf[40]; 58219304Speter 58319304Speter if (str == NULL) { 58419304Speter (void)snprintf(buf, sizeof(buf), "%lu", value); 58519304Speter return (setenv(name, buf, 1)); 58619304Speter } else 58719304Speter return (setenv(name, str, 1)); 58819304Speter} 589