xref: /illumos-gate/usr/src/cmd/captoinfo/otermcap.c (revision 2a8bcb4e)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
27*b5514887Smuffin /*	Copyright (c) 1988 AT&T	*/
28*b5514887Smuffin /*	  All Rights Reserved  	*/
29*b5514887Smuffin 
307c478bd9Sstevel@tonic-gate /* Copyright (c) 1979 Regents of the University of California	*/
317c478bd9Sstevel@tonic-gate /* Modified to:							*/
327c478bd9Sstevel@tonic-gate /* 1) remember the name of the first tc= parameter		*/
337c478bd9Sstevel@tonic-gate /*	encountered during parsing.				*/
347c478bd9Sstevel@tonic-gate /* 2) handle multiple invocations of tgetent().			*/
357c478bd9Sstevel@tonic-gate /* 3) tskip() is now available outside of the library.		*/
367c478bd9Sstevel@tonic-gate /* 4) remember $TERM name for error messages.			*/
377c478bd9Sstevel@tonic-gate /* 5) have a larger buffer.					*/
387c478bd9Sstevel@tonic-gate /* 6) really fix the bug that 5) got around. This fix by	*/
397c478bd9Sstevel@tonic-gate /*		Marion Hakanson, orstcs!hakanson		*/
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate #include "otermcap.h"
437c478bd9Sstevel@tonic-gate #define	MAXHOP	32	/* max number of tc= indirections */
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate #include <sys/types.h>
467c478bd9Sstevel@tonic-gate #include <sys/stat.h>
477c478bd9Sstevel@tonic-gate #include <fcntl.h>
487c478bd9Sstevel@tonic-gate #include <sys/uio.h>
497c478bd9Sstevel@tonic-gate #include <unistd.h>
507c478bd9Sstevel@tonic-gate #include <stdio.h>
517c478bd9Sstevel@tonic-gate #include <stdlib.h>
527c478bd9Sstevel@tonic-gate #include <string.h>
537c478bd9Sstevel@tonic-gate #include <ctype.h>
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate #include <signal.h>   /* use this file to determine if this is SVR4.0 system */
567c478bd9Sstevel@tonic-gate #ifdef SIGSTOP /* SVR4.0 and beyond */
577c478bd9Sstevel@tonic-gate #define	E_TERMCAP "/usr/share/lib/termcap"
587c478bd9Sstevel@tonic-gate #else
597c478bd9Sstevel@tonic-gate #define	E_TERMCAP "/etc/termcap"
607c478bd9Sstevel@tonic-gate #endif
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate /*
637c478bd9Sstevel@tonic-gate  * termcap - routines for dealing with the terminal capability data base
647c478bd9Sstevel@tonic-gate  *
657c478bd9Sstevel@tonic-gate  * BUG:		Should use a "last" pointer in tbuf, so that searching
667c478bd9Sstevel@tonic-gate  *		for capabilities alphabetically would not be a n**2/2
677c478bd9Sstevel@tonic-gate  *		process when large numbers of capabilities are given.
687c478bd9Sstevel@tonic-gate  * Note:	If we add a last pointer now we will screw up the
697c478bd9Sstevel@tonic-gate  *		tc capability. We really should compile termcap.
707c478bd9Sstevel@tonic-gate  *
717c478bd9Sstevel@tonic-gate  * Essentially all the work here is scanning and decoding escapes
727c478bd9Sstevel@tonic-gate  * in string capabilities.  We don't use stdio because the editor
737c478bd9Sstevel@tonic-gate  * doesn't, and because living w/o it is not hard.
747c478bd9Sstevel@tonic-gate  */
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate static	char *tbuf;
777c478bd9Sstevel@tonic-gate static	int hopcount;	/* detect infinite loops in termcap, init 0 */
78*b5514887Smuffin char	*tskip(char *);
79*b5514887Smuffin char	*otgetstr(char *, char **);
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate /* Tony Hansen */
827c478bd9Sstevel@tonic-gate int	TLHtcfound = 0;
837c478bd9Sstevel@tonic-gate char	TLHtcname[16];
847c478bd9Sstevel@tonic-gate static	char *termname;
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate static int _tgetent(char *, char *);
87*b5514887Smuffin static int otnchktc(void);
887c478bd9Sstevel@tonic-gate static char *tdecode(char *, char **);
897c478bd9Sstevel@tonic-gate static int otnamatch(char *);
907c478bd9Sstevel@tonic-gate /*
917c478bd9Sstevel@tonic-gate  * Get an entry for terminal name in buffer bp,
927c478bd9Sstevel@tonic-gate  * from the termcap file.  Parse is very rudimentary;
937c478bd9Sstevel@tonic-gate  * we just notice escaped newlines.
947c478bd9Sstevel@tonic-gate  */
95*b5514887Smuffin int
otgetent(char * bp,char * name)967c478bd9Sstevel@tonic-gate otgetent(char *bp, char *name)
977c478bd9Sstevel@tonic-gate {
987c478bd9Sstevel@tonic-gate 	/* Tony Hansen */
997c478bd9Sstevel@tonic-gate 	int ret;
1007c478bd9Sstevel@tonic-gate 	TLHtcfound = 0;
1017c478bd9Sstevel@tonic-gate 	hopcount = 0;
1027c478bd9Sstevel@tonic-gate 	termname = name;
1037c478bd9Sstevel@tonic-gate 	ret = _tgetent(bp, name);
1047c478bd9Sstevel@tonic-gate 	/*
1057c478bd9Sstevel@tonic-gate 	 * There is some sort of bug in the check way down below to prevent
1067c478bd9Sstevel@tonic-gate 	 * buffer overflow. I really don't want to track it down, so I
1077c478bd9Sstevel@tonic-gate 	 * upped the standard buffer size and check here to see if the created
1087c478bd9Sstevel@tonic-gate 	 * buffer is larger than the old buffer size.
1097c478bd9Sstevel@tonic-gate 	 */
1107c478bd9Sstevel@tonic-gate 	if (strlen(bp) >= 1024)
1117c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1127c478bd9Sstevel@tonic-gate 		    "tgetent(): TERM=%s: Termcap entry is too long.\n",
1137c478bd9Sstevel@tonic-gate 		    termname);
1147c478bd9Sstevel@tonic-gate 	return (ret);
1157c478bd9Sstevel@tonic-gate }
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate static int
_tgetent(char * bp,char * name)1187c478bd9Sstevel@tonic-gate _tgetent(char *bp, char *name)
1197c478bd9Sstevel@tonic-gate {
1207c478bd9Sstevel@tonic-gate 	char *cp;
1217c478bd9Sstevel@tonic-gate 	int c;
1227c478bd9Sstevel@tonic-gate 	int i = 0, cnt = 0;
1237c478bd9Sstevel@tonic-gate 	char ibuf[TBUFSIZE];
1247c478bd9Sstevel@tonic-gate 	char *cp2;
1257c478bd9Sstevel@tonic-gate 	int tf;
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 	tbuf = bp;
1287c478bd9Sstevel@tonic-gate 	tf = 0;
1297c478bd9Sstevel@tonic-gate #ifndef V6
1307c478bd9Sstevel@tonic-gate 	cp = getenv("TERMCAP");
1317c478bd9Sstevel@tonic-gate 	/*
1327c478bd9Sstevel@tonic-gate 	 * TERMCAP can have one of two things in it. It can be the
1337c478bd9Sstevel@tonic-gate 	 * name of a file to use instead of /etc/termcap. In this
1347c478bd9Sstevel@tonic-gate 	 * case it better start with a "/". Or it can be an entry to
1357c478bd9Sstevel@tonic-gate 	 * use so we don't have to read the file. In this case it
1367c478bd9Sstevel@tonic-gate 	 * has to already have the newlines crunched out.
1377c478bd9Sstevel@tonic-gate 	 */
1387c478bd9Sstevel@tonic-gate 	if (cp && *cp) {
1397c478bd9Sstevel@tonic-gate 		if (*cp != '/') {
1407c478bd9Sstevel@tonic-gate 			cp2 = getenv("TERM");
1417c478bd9Sstevel@tonic-gate 			if (cp2 == (char *)0 || strcmp(name, cp2) == 0) {
1427c478bd9Sstevel@tonic-gate 				(void) strcpy(bp, cp);
1437c478bd9Sstevel@tonic-gate 				return (otnchktc());
1447c478bd9Sstevel@tonic-gate 			} else {
1457c478bd9Sstevel@tonic-gate 				tf = open(E_TERMCAP, 0);
1467c478bd9Sstevel@tonic-gate 			}
1477c478bd9Sstevel@tonic-gate 		} else
1487c478bd9Sstevel@tonic-gate 			tf = open(cp, 0);
1497c478bd9Sstevel@tonic-gate 	}
1507c478bd9Sstevel@tonic-gate 	if (tf == 0)
1517c478bd9Sstevel@tonic-gate 		tf = open(E_TERMCAP, 0);
1527c478bd9Sstevel@tonic-gate #else
1537c478bd9Sstevel@tonic-gate 	tf = open(E_TERMCAP, 0);
1547c478bd9Sstevel@tonic-gate #endif
1557c478bd9Sstevel@tonic-gate 	if (tf < 0)
1567c478bd9Sstevel@tonic-gate 		return (-1);
1577c478bd9Sstevel@tonic-gate 	for (; ; ) {
1587c478bd9Sstevel@tonic-gate 		cp = bp;
1597c478bd9Sstevel@tonic-gate 		for (; ; ) {
1607c478bd9Sstevel@tonic-gate 			if (i == cnt) {
1617c478bd9Sstevel@tonic-gate 				cnt = read(tf, ibuf, TBUFSIZE);
1627c478bd9Sstevel@tonic-gate 				if (cnt <= 0) {
1637c478bd9Sstevel@tonic-gate 					(void) close(tf);
1647c478bd9Sstevel@tonic-gate 					return (0);
1657c478bd9Sstevel@tonic-gate 				}
1667c478bd9Sstevel@tonic-gate 				i = 0;
1677c478bd9Sstevel@tonic-gate 			}
1687c478bd9Sstevel@tonic-gate 			c = ibuf[i++];
1697c478bd9Sstevel@tonic-gate 			if (c == '\n') {
1707c478bd9Sstevel@tonic-gate 				if (cp > bp && cp[-1] == '\\') {
1717c478bd9Sstevel@tonic-gate 					cp--;
1727c478bd9Sstevel@tonic-gate 					continue;
1737c478bd9Sstevel@tonic-gate 				}
1747c478bd9Sstevel@tonic-gate 				break;
1757c478bd9Sstevel@tonic-gate 			}
1767c478bd9Sstevel@tonic-gate 			if (cp >= bp + TBUFSIZE) {
1777c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "tgetent(): TERM=%s: "
1787c478bd9Sstevel@tonic-gate 				    "Termcap entry too long\n", termname);
1797c478bd9Sstevel@tonic-gate 				break;
1807c478bd9Sstevel@tonic-gate 			} else
1817c478bd9Sstevel@tonic-gate 				*cp++ = c;
1827c478bd9Sstevel@tonic-gate 		}
1837c478bd9Sstevel@tonic-gate 		*cp = 0;
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 		/*
1867c478bd9Sstevel@tonic-gate 		 * The real work for the match.
1877c478bd9Sstevel@tonic-gate 		 */
1887c478bd9Sstevel@tonic-gate 		if (otnamatch(name)) {
1897c478bd9Sstevel@tonic-gate 			(void) close(tf);
1907c478bd9Sstevel@tonic-gate 			return (otnchktc());
1917c478bd9Sstevel@tonic-gate 		}
1927c478bd9Sstevel@tonic-gate 	}
1937c478bd9Sstevel@tonic-gate }
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate /*
1967c478bd9Sstevel@tonic-gate  * otnchktc: check the last entry, see if it's tc=xxx. If so,
1977c478bd9Sstevel@tonic-gate  * recursively find xxx and append that entry (minus the names)
1987c478bd9Sstevel@tonic-gate  * to take the place of the tc=xxx entry. This allows termcap
1997c478bd9Sstevel@tonic-gate  * entries to say "like an HP2621 but doesn't turn on the labels".
2007c478bd9Sstevel@tonic-gate  * Note that this works because of the left to right scan.
2017c478bd9Sstevel@tonic-gate  */
2027c478bd9Sstevel@tonic-gate static int
otnchktc(void)203*b5514887Smuffin otnchktc(void)
2047c478bd9Sstevel@tonic-gate {
2057c478bd9Sstevel@tonic-gate 	char *p, *q;
2067c478bd9Sstevel@tonic-gate #define	TERMNAMESIZE 16
2077c478bd9Sstevel@tonic-gate 	char tcname[TERMNAMESIZE];	/* name of similar terminal */
2087c478bd9Sstevel@tonic-gate 	char tcbuf[TBUFSIZE];
2097c478bd9Sstevel@tonic-gate 	char *holdtbuf = tbuf;
2107c478bd9Sstevel@tonic-gate 	int l;
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	p = tbuf + strlen(tbuf) - 2;	/* before the last colon */
2137c478bd9Sstevel@tonic-gate 	while (*--p != ':')
2147c478bd9Sstevel@tonic-gate 		if (p < tbuf) {
2157c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "tnchktc(): TERM=%s: Bad "
2167c478bd9Sstevel@tonic-gate 			    "termcap entry\n", termname);
2177c478bd9Sstevel@tonic-gate 			return (0);
2187c478bd9Sstevel@tonic-gate 		}
2197c478bd9Sstevel@tonic-gate 	p++;
2207c478bd9Sstevel@tonic-gate 	/* p now points to beginning of last field */
2217c478bd9Sstevel@tonic-gate 	if (p[0] != 't' || p[1] != 'c')
2227c478bd9Sstevel@tonic-gate 		return (1);
2237c478bd9Sstevel@tonic-gate 	(void) strncpy(tcname, p + 3, TERMNAMESIZE);	/* TLH */
2247c478bd9Sstevel@tonic-gate 	q = tcname;
2257c478bd9Sstevel@tonic-gate 	while (*q && *q != ':')
2267c478bd9Sstevel@tonic-gate 		q++;
2277c478bd9Sstevel@tonic-gate 	*q = 0;
2287c478bd9Sstevel@tonic-gate 	if (++hopcount > MAXHOP) {
2297c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "tnchktc(): TERM=%s: Infinite tc= "
2307c478bd9Sstevel@tonic-gate 		    "loop\n", termname);
2317c478bd9Sstevel@tonic-gate 		return (0);
2327c478bd9Sstevel@tonic-gate 	}
2337c478bd9Sstevel@tonic-gate 	if (_tgetent(tcbuf, tcname) != 1)
2347c478bd9Sstevel@tonic-gate 		return (0);
2357c478bd9Sstevel@tonic-gate 	/* Tony Hansen */
2367c478bd9Sstevel@tonic-gate 	TLHtcfound++;
2377c478bd9Sstevel@tonic-gate 	(void) strcpy(TLHtcname, tcname);
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	for (q = tcbuf; *q != ':'; q++)
2407c478bd9Sstevel@tonic-gate 		;
2417c478bd9Sstevel@tonic-gate 	l = p - holdtbuf + strlen(q);
2427c478bd9Sstevel@tonic-gate 	if (l > TBUFSIZE) {
2437c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "tnchktc(): TERM=%s: Termcap entry "
2447c478bd9Sstevel@tonic-gate 		    "too long\n", termname);
2457c478bd9Sstevel@tonic-gate 		q[TBUFSIZE - (p - holdtbuf)] = 0;
2467c478bd9Sstevel@tonic-gate 	}
2477c478bd9Sstevel@tonic-gate 	(void) strcpy(p, q + 1);
2487c478bd9Sstevel@tonic-gate 	tbuf = holdtbuf;
2497c478bd9Sstevel@tonic-gate 	return (1);
2507c478bd9Sstevel@tonic-gate }
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate /*
2537c478bd9Sstevel@tonic-gate  * Tnamatch deals with name matching.  The first field of the termcap
2547c478bd9Sstevel@tonic-gate  * entry is a sequence of names separated by |'s, so we compare
2557c478bd9Sstevel@tonic-gate  * against each such name.  The normal : terminator after the last
2567c478bd9Sstevel@tonic-gate  * name (before the first field) stops us.
2577c478bd9Sstevel@tonic-gate  */
2587c478bd9Sstevel@tonic-gate static int
otnamatch(char * np)2597c478bd9Sstevel@tonic-gate otnamatch(char *np)
2607c478bd9Sstevel@tonic-gate {
2617c478bd9Sstevel@tonic-gate 	char *Np, *Bp;
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	Bp = tbuf;
2647c478bd9Sstevel@tonic-gate 	if (*Bp == '#')
2657c478bd9Sstevel@tonic-gate 		return (0);
2667c478bd9Sstevel@tonic-gate 	for (;;) {
2677c478bd9Sstevel@tonic-gate 		for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
2687c478bd9Sstevel@tonic-gate 			continue;
2697c478bd9Sstevel@tonic-gate 		if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
2707c478bd9Sstevel@tonic-gate 			return (1);
2717c478bd9Sstevel@tonic-gate 		while (*Bp && *Bp != ':' && *Bp != '|')
2727c478bd9Sstevel@tonic-gate 			Bp++;
2737c478bd9Sstevel@tonic-gate 		if (*Bp == 0 || *Bp == ':')
2747c478bd9Sstevel@tonic-gate 			return (0);
2757c478bd9Sstevel@tonic-gate 		Bp++;
2767c478bd9Sstevel@tonic-gate 	}
2777c478bd9Sstevel@tonic-gate }
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate /*
2807c478bd9Sstevel@tonic-gate  * Skip to the next field.  Notice that this is very dumb, not
2817c478bd9Sstevel@tonic-gate  * knowing about \: escapes or any such.  If necessary, :'s can be put
2827c478bd9Sstevel@tonic-gate  * into the termcap file in octal.
2837c478bd9Sstevel@tonic-gate  */
284*b5514887Smuffin char *
tskip(char * bp)2857c478bd9Sstevel@tonic-gate tskip(char *bp)
2867c478bd9Sstevel@tonic-gate {
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	while (*bp && *bp != ':')
2897c478bd9Sstevel@tonic-gate 		bp++;
2907c478bd9Sstevel@tonic-gate 	if (*bp == ':')
2917c478bd9Sstevel@tonic-gate 		bp++;
2927c478bd9Sstevel@tonic-gate 	return (bp);
2937c478bd9Sstevel@tonic-gate }
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate /*
2967c478bd9Sstevel@tonic-gate  * Return the (numeric) option id.
2977c478bd9Sstevel@tonic-gate  * Numeric options look like
2987c478bd9Sstevel@tonic-gate  *	li#80
2997c478bd9Sstevel@tonic-gate  * i.e. the option string is separated from the numeric value by
3007c478bd9Sstevel@tonic-gate  * a # character.  If the option is not found we return -1.
3017c478bd9Sstevel@tonic-gate  * Note that we handle octal numbers beginning with 0.
3027c478bd9Sstevel@tonic-gate  */
303*b5514887Smuffin int
otgetnum(char * id)3047c478bd9Sstevel@tonic-gate otgetnum(char *id)
3057c478bd9Sstevel@tonic-gate {
3067c478bd9Sstevel@tonic-gate 	int i, base;
3077c478bd9Sstevel@tonic-gate 	char *bp = tbuf;
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	for (;;) {
3107c478bd9Sstevel@tonic-gate 		bp = tskip(bp);
3117c478bd9Sstevel@tonic-gate 		if (*bp == 0)
3127c478bd9Sstevel@tonic-gate 			return (-1);
3137c478bd9Sstevel@tonic-gate 		if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
3147c478bd9Sstevel@tonic-gate 			continue;
3157c478bd9Sstevel@tonic-gate 		if (*bp == '@')
3167c478bd9Sstevel@tonic-gate 			return (-1);
3177c478bd9Sstevel@tonic-gate 		if (*bp != '#')
3187c478bd9Sstevel@tonic-gate 			continue;
3197c478bd9Sstevel@tonic-gate 		bp++;
3207c478bd9Sstevel@tonic-gate 		base = 10;
3217c478bd9Sstevel@tonic-gate 		if (*bp == '0')
3227c478bd9Sstevel@tonic-gate 			base = 8;
3237c478bd9Sstevel@tonic-gate 		i = 0;
3247c478bd9Sstevel@tonic-gate 		while (isdigit(*bp))
3257c478bd9Sstevel@tonic-gate 			i *= base, i += *bp++ - '0';
3267c478bd9Sstevel@tonic-gate 		return (i);
3277c478bd9Sstevel@tonic-gate 	}
3287c478bd9Sstevel@tonic-gate }
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate /*
3317c478bd9Sstevel@tonic-gate  * Handle a flag option.
3327c478bd9Sstevel@tonic-gate  * Flag options are given "naked", i.e. followed by a : or the end
3337c478bd9Sstevel@tonic-gate  * of the buffer.  Return 1 if we find the option, or 0 if it is
3347c478bd9Sstevel@tonic-gate  * not given.
3357c478bd9Sstevel@tonic-gate  */
336*b5514887Smuffin int
otgetflag(char * id)3377c478bd9Sstevel@tonic-gate otgetflag(char *id)
3387c478bd9Sstevel@tonic-gate {
3397c478bd9Sstevel@tonic-gate 	char *bp = tbuf;
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 	for (;;) {
3427c478bd9Sstevel@tonic-gate 		bp = tskip(bp);
3437c478bd9Sstevel@tonic-gate 		if (!*bp)
3447c478bd9Sstevel@tonic-gate 			return (0);
3457c478bd9Sstevel@tonic-gate 		if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
3467c478bd9Sstevel@tonic-gate 			if (!*bp || *bp == ':')
3477c478bd9Sstevel@tonic-gate 				return (1);
3487c478bd9Sstevel@tonic-gate 			else if (*bp == '@')
3497c478bd9Sstevel@tonic-gate 				return (0);
3507c478bd9Sstevel@tonic-gate 		}
3517c478bd9Sstevel@tonic-gate 	}
3527c478bd9Sstevel@tonic-gate }
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate /*
3557c478bd9Sstevel@tonic-gate  * Get a string valued option.
3567c478bd9Sstevel@tonic-gate  * These are given as
3577c478bd9Sstevel@tonic-gate  *	cl=^Z
3587c478bd9Sstevel@tonic-gate  * Much decoding is done on the strings, and the strings are
3597c478bd9Sstevel@tonic-gate  * placed in area, which is a ref parameter which is updated.
3607c478bd9Sstevel@tonic-gate  * No checking on area overflow.
3617c478bd9Sstevel@tonic-gate  */
3627c478bd9Sstevel@tonic-gate char *
otgetstr(char * id,char ** area)3637c478bd9Sstevel@tonic-gate otgetstr(char *id, char **area)
3647c478bd9Sstevel@tonic-gate {
3657c478bd9Sstevel@tonic-gate 	char *bp = tbuf;
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 	for (; ; ) {
3687c478bd9Sstevel@tonic-gate 		bp = tskip(bp);
3697c478bd9Sstevel@tonic-gate 		if (!*bp)
3707c478bd9Sstevel@tonic-gate 			return (0);
3717c478bd9Sstevel@tonic-gate 		if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
3727c478bd9Sstevel@tonic-gate 			continue;
3737c478bd9Sstevel@tonic-gate 		if (*bp == '@')
3747c478bd9Sstevel@tonic-gate 			return (0);
3757c478bd9Sstevel@tonic-gate 		if (*bp != '=')
3767c478bd9Sstevel@tonic-gate 			continue;
3777c478bd9Sstevel@tonic-gate 		bp++;
3787c478bd9Sstevel@tonic-gate 		return (tdecode(bp, area));
3797c478bd9Sstevel@tonic-gate 	}
3807c478bd9Sstevel@tonic-gate }
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate /*
3837c478bd9Sstevel@tonic-gate  * Tdecode does the grung work to decode the
3847c478bd9Sstevel@tonic-gate  * string capability escapes.
3857c478bd9Sstevel@tonic-gate  */
3867c478bd9Sstevel@tonic-gate static char *
tdecode(char * str,char ** area)3877c478bd9Sstevel@tonic-gate tdecode(char *str, char **area)
3887c478bd9Sstevel@tonic-gate {
3897c478bd9Sstevel@tonic-gate 	char *cp;
3907c478bd9Sstevel@tonic-gate 	int c;
3917c478bd9Sstevel@tonic-gate 	char *dp;
3927c478bd9Sstevel@tonic-gate 	int i;
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	cp = *area;
3957c478bd9Sstevel@tonic-gate 	while ((c = *str++) != '\0' && c != ':') {
3967c478bd9Sstevel@tonic-gate 		switch (c) {
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 		case '^':
3997c478bd9Sstevel@tonic-gate 			c = *str++ & 037;
4007c478bd9Sstevel@tonic-gate 			break;
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 		case '\\':
4037c478bd9Sstevel@tonic-gate 			dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
4047c478bd9Sstevel@tonic-gate 			c = *str++;
4057c478bd9Sstevel@tonic-gate nextc:
4067c478bd9Sstevel@tonic-gate 			if (*dp++ == c) {
4077c478bd9Sstevel@tonic-gate 				c = *dp++;
4087c478bd9Sstevel@tonic-gate 				break;
4097c478bd9Sstevel@tonic-gate 			}
4107c478bd9Sstevel@tonic-gate 			dp++;
4117c478bd9Sstevel@tonic-gate 			if (*dp)
4127c478bd9Sstevel@tonic-gate 				goto nextc;
4137c478bd9Sstevel@tonic-gate 			if (isdigit(c)) {
4147c478bd9Sstevel@tonic-gate 				c -= '0', i = 2;
4157c478bd9Sstevel@tonic-gate 				do
4167c478bd9Sstevel@tonic-gate 					c <<= 3, c |= *str++ - '0';
417*b5514887Smuffin 				while (--i && isdigit(*str))
418*b5514887Smuffin 					;
4197c478bd9Sstevel@tonic-gate 			}
4207c478bd9Sstevel@tonic-gate 			break;
4217c478bd9Sstevel@tonic-gate 		}
4227c478bd9Sstevel@tonic-gate 		*cp++ = c;
4237c478bd9Sstevel@tonic-gate 	}
4247c478bd9Sstevel@tonic-gate 	*cp++ = 0;
4257c478bd9Sstevel@tonic-gate 	str = *area;
4267c478bd9Sstevel@tonic-gate 	*area = cp;
4277c478bd9Sstevel@tonic-gate 	return (str);
4287c478bd9Sstevel@tonic-gate }
429