xref: /netbsd/bin/ps/keyword.c (revision f7f9a06b)
1*f7f9a06bSchristos /*	$NetBSD: keyword.c,v 1.60 2021/09/15 13:16:57 christos Exp $	*/
249f0ad86Scgd 
361f28255Scgd /*-
44d1457ceScgd  * Copyright (c) 1990, 1993, 1994
54d1457ceScgd  *	The Regents of the University of California.  All rights reserved.
661f28255Scgd  *
761f28255Scgd  * Redistribution and use in source and binary forms, with or without
861f28255Scgd  * modification, are permitted provided that the following conditions
961f28255Scgd  * are met:
1061f28255Scgd  * 1. Redistributions of source code must retain the above copyright
1161f28255Scgd  *    notice, this list of conditions and the following disclaimer.
1261f28255Scgd  * 2. Redistributions in binary form must reproduce the above copyright
1361f28255Scgd  *    notice, this list of conditions and the following disclaimer in the
1461f28255Scgd  *    documentation and/or other materials provided with the distribution.
15b5b29542Sagc  * 3. Neither the name of the University nor the names of its contributors
1661f28255Scgd  *    may be used to endorse or promote products derived from this software
1761f28255Scgd  *    without specific prior written permission.
1861f28255Scgd  *
1961f28255Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2061f28255Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2161f28255Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2261f28255Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2361f28255Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2461f28255Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2561f28255Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2661f28255Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2761f28255Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2861f28255Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2961f28255Scgd  * SUCH DAMAGE.
3061f28255Scgd  */
3161f28255Scgd 
3278295c8bSchristos #include <sys/cdefs.h>
3361f28255Scgd #ifndef lint
3449f0ad86Scgd #if 0
354d1457ceScgd static char sccsid[] = "@(#)keyword.c	8.5 (Berkeley) 4/2/94";
3649f0ad86Scgd #else
37*f7f9a06bSchristos __RCSID("$NetBSD: keyword.c,v 1.60 2021/09/15 13:16:57 christos Exp $");
3849f0ad86Scgd #endif
3961f28255Scgd #endif /* not lint */
4061f28255Scgd 
4161f28255Scgd #include <sys/param.h>
4261f28255Scgd #include <sys/time.h>
433fdac2b8Sthorpej #include <sys/lwp.h>
4461f28255Scgd #include <sys/proc.h>
4579ddb78aSmrg #include <sys/resource.h>
4679ddb78aSmrg #include <sys/sysctl.h>
4779ddb78aSmrg #include <sys/ucred.h>
484d1457ceScgd 
494d1457ceScgd #include <err.h>
5061f28255Scgd #include <errno.h>
51e7f8f72dSsimonb #include <kvm.h>
52973821efSchristos #include <ctype.h>
534d1457ceScgd #include <stddef.h>
5461f28255Scgd #include <stdio.h>
5561f28255Scgd #include <stdlib.h>
5661f28255Scgd #include <string.h>
57f3d0eddcSchristos #include <signal.h>
58d92ffdbeSchristos #include <util.h>
594d1457ceScgd 
6061f28255Scgd #include "ps.h"
6161f28255Scgd 
62f24cb256Sdsl static VAR *findvar(const char *);
63f24cb256Sdsl static int  vcmp(const void *, const void *);
6461f28255Scgd 
6561f28255Scgd /* Compute offset in common structures. */
66fd521aefSsimonb #define	POFF(x)	offsetof(struct kinfo_proc2, x)
673fdac2b8Sthorpej #define	LOFF(x)	offsetof(struct kinfo_lwp, x)
6861f28255Scgd 
6961f28255Scgd #define	UIDFMT	"u"
703fccf7e0Schristos #define	UID(n1, n2, of) \
713fccf7e0Schristos 	{ .name = n1, .header = n2, .flag = 0, .oproc = pvar, \
723fccf7e0Schristos 	  .off = POFF(of), .type = UINT32, .fmt = UIDFMT }
73f24cb256Sdsl #define	GID(n1, n2, off)	UID(n1, n2, off)
74db6548cdScgd 
7561f28255Scgd #define	PIDFMT	"d"
763fccf7e0Schristos #define	PID(n1, n2, of) \
773fccf7e0Schristos 	{ .name = n1, .header = n2, .flag = 0, .oproc = pvar, \
783fccf7e0Schristos 	  .off = POFF(of), .type = INT32, .fmt = PIDFMT }
7961f28255Scgd 
803fccf7e0Schristos #define	LVAR(n1, n2, fl, of, ty, fm) \
813fccf7e0Schristos 	{ .name = n1, .header = n2, .flag = (fl) | LWP, .oproc = pvar, \
823fccf7e0Schristos 	  .off = LOFF(of), .type = ty, .fmt = fm }
833fccf7e0Schristos #define	PVAR(n1, n2, fl, of, ty, fm) \
843fccf7e0Schristos 	{ .name = n1, .header = n2, .flag = (fl) | 0, .oproc = pvar, \
853fccf7e0Schristos 	  .off = POFF(of), .type = ty, .fmt = fm }
863fccf7e0Schristos #define	PUVAR(n1, n2, fl, of, ty, fm) \
873fccf7e0Schristos 	{ .name = n1, .header = n2, .flag = (fl) | UAREA, .oproc = pvar, \
883fccf7e0Schristos 	  .off = POFF(of), .type = ty, .fmt = fm }
893fccf7e0Schristos #define VAR3(n1, n2, fl) \
903fccf7e0Schristos 	{ .name = n1, .header = n2, .flag = fl }
913fccf7e0Schristos #define VAR4(n1, n2, fl, op) \
923fccf7e0Schristos 	{ .name = n1, .header = n2, .flag = fl, .oproc = op, }
933fccf7e0Schristos #define VAR6(n1, n2, fl, op, of, ty) \
943fccf7e0Schristos 	{ .name = n1, .header = n2, .flag = fl, .oproc = op, \
953fccf7e0Schristos 	  .off = of, .type = ty }
96f24cb256Sdsl 
97f24cb256Sdsl /* NB: table must be sorted, in vi use:
98f24cb256Sdsl  *	:/^VAR/,/end_sort/! sort -t\" +1
99f24cb256Sdsl  * breaking long lines just makes the sort harder
100d9463bc1Sapb  *
101d9463bc1Sapb  * We support all the fields required by P1003.1-2004 (SUSv3), with
102d9463bc1Sapb  * the correct default headers, except for the "tty" field, where the
103d9463bc1Sapb  * standard says the header should be "TT", but we have "TTY".
104f24cb256Sdsl  */
10561f28255Scgd VAR var[] = {
1063fccf7e0Schristos 	VAR6("%cpu", "%CPU", 0, pcpu, 0, PCPU),
1073fccf7e0Schristos 	VAR6("%mem", "%MEM", 0, pmem, POFF(p_vm_rssize), INT32),
108973821efSchristos 	PVAR("acflag", "ACFLG", 0, p_acflag, PROCACFLAG, "x"),
1093fccf7e0Schristos 	VAR3("acflg", "acflag", ALIAS),
1103fccf7e0Schristos 	VAR3("args", "command", ALIAS),
1113fccf7e0Schristos 	VAR3("blocked", "sigmask", ALIAS),
1123fccf7e0Schristos 	VAR3("caught", "sigcatch", ALIAS),
1133fccf7e0Schristos 	VAR4("comm", "COMMAND", COMM|ARGV0|LJUST, command),
1143fccf7e0Schristos 	VAR4("command", "COMMAND", COMM|LJUST, command),
115f24cb256Sdsl 	PVAR("cpu", "CPU", 0, p_estcpu, UINT, "u"),
116da86f0e5Schristos 	VAR4("cpuid", "CPUID", LWP, cpuid),
1173fccf7e0Schristos 	VAR3("cputime", "time", ALIAS),
1183fccf7e0Schristos 	VAR6("ctime", "CTIME", 0, putimeval, POFF(p_uctime_sec), TIMEVAL),
119f24cb256Sdsl 	GID("egid", "EGID", p_gid),
1203fccf7e0Schristos 	VAR4("egroup", "EGROUP", LJUST, gname),
121d0a868f4Schristos 	VAR4("emul", "EMUL", LJUST, emul),
1223fccf7e0Schristos 	VAR6("etime", "ELAPSED", 0, elapsed, POFF(p_ustart_sec), TIMEVAL),
123f24cb256Sdsl 	UID("euid", "EUID", p_uid),
124675d8f39Skamil 	VAR4("euser", "EUSER", LJUST, usrname),
125973821efSchristos 	PVAR("f", "F", 0, p_flag, PROCFLAG, "x"),
1263fccf7e0Schristos 	VAR3("flags", "f", ALIAS),
127f24cb256Sdsl 	GID("gid", "GID", p_gid),
1283fccf7e0Schristos 	VAR4("group", "GROUP", LJUST, gname),
1293fccf7e0Schristos 	VAR4("groupnames", "GROUPNAMES", LJUST, groupnames),
1303fccf7e0Schristos 	VAR4("groups", "GROUPS", LJUST, groups),
13140cf6f36Srmind 	/* holdcnt: unused, left for compat. */
132f24cb256Sdsl 	LVAR("holdcnt", "HOLDCNT", 0, l_holdcnt, INT, "d"),
1339c147c5dSkamil 	PUVAR("idrss", "IDRSS", 0, p_uru_idrss, UINT64, PRIu64),
1343fccf7e0Schristos 	VAR3("ignored", "sigignore", ALIAS),
135f24cb256Sdsl 	PUVAR("inblk", "INBLK", 0, p_uru_inblock, UINT64, PRIu64),
1363fccf7e0Schristos 	VAR3("inblock", "inblk", ALIAS),
1379c147c5dSkamil 	PUVAR("isrss", "ISRSS", 0, p_uru_isrss, UINT64, PRId64),
1389c147c5dSkamil 	PUVAR("ixrss", "IXRSS", 0, p_uru_ixrss, UINT64, PRId64),
139f24cb256Sdsl 	PVAR("jobc", "JOBC", 0, p_jobc, SHORT, "d"),
140d92ffdbeSchristos 	PVAR("ktrace", "KTRACE", 0, p_traceflag, KTRACEFLAG, "x"),
141f24cb256Sdsl /*XXX*/	PVAR("ktracep", "KTRACEP", 0, p_tracep, KPTR, PRIx64),
1423d720e58Snathanw 	LVAR("laddr", "LADDR", 0, l_laddr, KPTR, PRIx64),
14373cc67cbSsimonb 	LVAR("lid", "LID", 0, l_lid, INT32, "d"),
1443fccf7e0Schristos 	VAR4("lim", "LIM", 0, maxrss),
14537ac06beSyamt 	VAR4("lname", "LNAME", LJUST|LWP, lname),
1463fccf7e0Schristos 	VAR4("login", "LOGIN", LJUST, logname),
1473fccf7e0Schristos 	VAR3("logname", "login", ALIAS),
1483fccf7e0Schristos 	VAR6("lstart", "STARTED", LJUST, lstarted, POFF(p_ustart_sec), UINT32),
1493fccf7e0Schristos 	VAR4("lstate", "STAT", LJUST|LWP, lstate),
1501878b5eeSmlelstv 	VAR6("ltime", "LTIME", LWP, lcputime, 0, CPUTIME),
151f24cb256Sdsl 	PUVAR("majflt", "MAJFLT", 0, p_uru_majflt, UINT64, PRIu64),
1529c147c5dSkamil 	PUVAR("maxrss", "MAXRSS", 0, p_uru_maxrss, UINT64, PRIu64),
153f24cb256Sdsl 	PUVAR("minflt", "MINFLT", 0, p_uru_minflt, UINT64, PRIu64),
154f24cb256Sdsl 	PUVAR("msgrcv", "MSGRCV", 0, p_uru_msgrcv, UINT64, PRIu64),
155f24cb256Sdsl 	PUVAR("msgsnd", "MSGSND", 0, p_uru_msgsnd, UINT64, PRIu64),
1563fccf7e0Schristos 	VAR3("ni", "nice", ALIAS),
1573fccf7e0Schristos 	VAR6("nice", "NI", 0, pnice, POFF(p_nice), UCHAR),
158f24cb256Sdsl 	PUVAR("nivcsw", "NIVCSW", 0, p_uru_nivcsw, UINT64, PRIu64),
159f24cb256Sdsl 	PVAR("nlwp", "NLWP", 0, p_nlwps, UINT64, PRId64),
1603fccf7e0Schristos 	VAR3("nsignals", "nsigs", ALIAS),
161f24cb256Sdsl 	PUVAR("nsigs", "NSIGS", 0, p_uru_nsignals, UINT64, PRIu64),
16240cf6f36Srmind 	/* nswap: unused, left for compat. */
163f24cb256Sdsl 	PUVAR("nswap", "NSWAP", 0, p_uru_nswap, UINT64, PRIu64),
164f24cb256Sdsl 	PUVAR("nvcsw", "NVCSW", 0, p_uru_nvcsw, UINT64, PRIu64),
165f24cb256Sdsl /*XXX*/	LVAR("nwchan", "WCHAN", 0, l_wchan, KPTR, PRIx64),
166f24cb256Sdsl 	PUVAR("oublk", "OUBLK", 0, p_uru_oublock, UINT64, PRIu64),
1673fccf7e0Schristos 	VAR3("oublock", "oublk", ALIAS),
168f24cb256Sdsl /*XXX*/	PVAR("p_ru", "P_RU", 0, p_ru, KPTR, PRIx64),
169f24cb256Sdsl /*XXX*/	PVAR("paddr", "PADDR", 0, p_paddr, KPTR, PRIx64),
170f24cb256Sdsl 	PUVAR("pagein", "PAGEIN", 0, p_uru_majflt, UINT64, PRIu64),
1713fccf7e0Schristos 	VAR3("pcpu", "%cpu", ALIAS),
1723fccf7e0Schristos 	VAR3("pending", "sig", ALIAS),
173f24cb256Sdsl 	PID("pgid", "PGID", p__pgid),
174f24cb256Sdsl 	PID("pid", "PID", p_pid),
1753fccf7e0Schristos 	VAR3("pmem", "%mem", ALIAS),
176f24cb256Sdsl 	PID("ppid", "PPID", p_ppid),
1773fccf7e0Schristos 	VAR4("pri", "PRI", LWP, pri),
178f24cb256Sdsl 	LVAR("re", "RE", INF127, l_swtime, UINT, "u"),
179f24cb256Sdsl 	GID("rgid", "RGID", p_rgid),
1803fccf7e0Schristos 	VAR4("rgroup", "RGROUP", LJUST, rgname),
181f24cb256Sdsl /*XXX*/	LVAR("rlink", "RLINK", 0, l_back, KPTR, PRIx64),
182f24cb256Sdsl 	PVAR("rlwp", "RLWP", 0, p_nrlwps, UINT64, PRId64),
1833fccf7e0Schristos 	VAR6("rss", "RSS", 0, p_rssize, POFF(p_vm_rssize), INT32),
1843fccf7e0Schristos 	VAR3("rssize", "rsz", ALIAS),
1853fccf7e0Schristos 	VAR6("rsz", "RSZ", 0, rssize, POFF(p_vm_rssize), INT32),
186f24cb256Sdsl 	UID("ruid", "RUID", p_ruid),
1873fccf7e0Schristos 	VAR4("ruser", "RUSER", LJUST, runame),
188f24cb256Sdsl 	PVAR("sess", "SESS", 0, p_sess, KPTR24, PRIx64),
189f24cb256Sdsl 	PID("sid", "SID", p_sid),
190f24cb256Sdsl 	PVAR("sig", "PENDING", 0, p_siglist, SIGLIST, "s"),
191f24cb256Sdsl 	PVAR("sigcatch", "CAUGHT", 0, p_sigcatch, SIGLIST, "s"),
192f24cb256Sdsl 	PVAR("sigignore", "IGNORED", 0, p_sigignore, SIGLIST, "s"),
193f24cb256Sdsl 	PVAR("sigmask", "BLOCKED", 0, p_sigmask, SIGLIST, "s"),
194f24cb256Sdsl 	LVAR("sl", "SL", INF127, l_slptime, UINT, "u"),
1953fccf7e0Schristos 	VAR6("start", "STARTED", 0, started, POFF(p_ustart_sec), UINT32),
1963fccf7e0Schristos 	VAR3("stat", "state", ALIAS),
1973fccf7e0Schristos 	VAR4("state", "STAT", LJUST, state),
1983fccf7e0Schristos 	VAR6("stime", "STIME", 0, putimeval, POFF(p_ustime_sec), TIMEVAL),
199f24cb256Sdsl 	GID("svgid", "SVGID", p_svgid),
2003fccf7e0Schristos 	VAR4("svgroup", "SVGROUP", LJUST, svgname),
201f24cb256Sdsl 	UID("svuid", "SVUID", p_svuid),
2023fccf7e0Schristos 	VAR4("svuser", "SVUSER", LJUST, svuname),
203b44ef110Sdsl 	/* "tdev" is UINT32, but we do this for sorting purposes */
2043fccf7e0Schristos 	VAR6("tdev", "TDEV", 0, tdev, POFF(p_tdev), INT32),
2053fccf7e0Schristos 	VAR6("time", "TIME", 0, cputime, 0, CPUTIME),
206550c4966Smjl 	PID("tpgid", "TPGID", p_tpgid),
207f24cb256Sdsl 	PVAR("tsess", "TSESS", 0, p_tsess, KPTR, PRIx64),
2083fccf7e0Schristos 	VAR6("tsiz", "TSIZ", 0, tsize, POFF(p_vm_tsize), INT32),
2093fccf7e0Schristos 	VAR6("tt", "TTY", LJUST, tname, POFF(p_tdev), INT32),
2103fccf7e0Schristos 	VAR6("tty", "TTY", LJUST, longtname, POFF(p_tdev), INT32),
21158c15fb5Schs 	LVAR("uaddr", "UADDR", 0, l_addr, KPTR, PRIx64),
2123fccf7e0Schristos 	VAR4("ucomm", "UCOMM", LJUST, ucomm),
213f24cb256Sdsl 	UID("uid", "UID", p_uid),
214f24cb256Sdsl 	LVAR("upr", "UPR", 0, l_usrpri, UCHAR, "u"),
215675d8f39Skamil 	VAR4("user", "USER", LJUST, usrname),
2163fccf7e0Schristos 	VAR3("usrpri", "upr", ALIAS),
2173fccf7e0Schristos 	VAR6("utime", "UTIME", 0, putimeval, POFF(p_uutime_sec), TIMEVAL),
2183fccf7e0Schristos 	VAR3("vsize", "vsz", ALIAS),
2193fccf7e0Schristos 	VAR6("vsz", "VSZ", 0, vsize, 0, VSIZE),
2203fccf7e0Schristos 	VAR4("wchan", "WCHAN", LJUST|LWP, wchan),
221f24cb256Sdsl 	PVAR("xstat", "XSTAT", 0, p_xstat, USHORT, "x"),
222f24cb256Sdsl /* "zzzz" end_sort */
2233fccf7e0Schristos 	{ .name = "" },
22461f28255Scgd };
22561f28255Scgd 
2264d1457ceScgd void
showkey(void)227f24cb256Sdsl showkey(void)
22861f28255Scgd {
2294d1457ceScgd 	VAR *v;
2304d1457ceScgd 	int i;
2316310b596Schristos 	const char *p;
2326310b596Schristos 	const char *sep;
23361f28255Scgd 
23461f28255Scgd 	i = 0;
23561f28255Scgd 	sep = "";
23661f28255Scgd 	for (v = var; *(p = v->name); ++v) {
2374d1457ceScgd 		int len = strlen(p);
23861f28255Scgd 		if (termwidth && (i += len + 1) > termwidth) {
23961f28255Scgd 			i = len;
24061f28255Scgd 			sep = "\n";
24161f28255Scgd 		}
24261f28255Scgd 		(void)printf("%s%s", sep, p);
24361f28255Scgd 		sep = " ";
24461f28255Scgd 	}
24561f28255Scgd 	(void)printf("\n");
24661f28255Scgd }
24761f28255Scgd 
248d9463bc1Sapb /*
249d9463bc1Sapb  * Parse the string pp, and insert or append entries to the list
250d9463bc1Sapb  * referenced by listptr.  If pos in non-null and *pos is non-null, then
251d9463bc1Sapb  * *pos specifies where to insert (instead of appending).  If pos is
252d9463bc1Sapb  * non-null, then a new value is returned through *pos referring to the
253d9463bc1Sapb  * last item inserted.
254d9463bc1Sapb  */
255f24cb256Sdsl static void
parsevarlist(const char * pp,struct varlist * listptr,struct varent ** pos)256d9463bc1Sapb parsevarlist(const char *pp, struct varlist *listptr, struct varent **pos)
25761f28255Scgd {
258d9463bc1Sapb 	char *p, *sp, *equalsp;
259f24cb256Sdsl 
260d9463bc1Sapb 	/* dup to avoid zapping arguments.  We will free sp later. */
261d92ffdbeSchristos 	p = sp = estrdup(pp);
262d9463bc1Sapb 
263d9463bc1Sapb 	/*
264d9463bc1Sapb 	 * Everything after the first '=' is part of a custom header.
265d9463bc1Sapb 	 * Temporarily replace it with '\0' to simplify other code.
266d9463bc1Sapb 	 */
267d9463bc1Sapb 	equalsp = strchr(p, '=');
268d9463bc1Sapb 	if (equalsp)
269d9463bc1Sapb 	    *equalsp = '\0';
27061f28255Scgd 
27161f28255Scgd #define	FMTSEP	" \t,\n"
27261f28255Scgd 	while (p && *p) {
2734d1457ceScgd 		char *cp;
2744d1457ceScgd 		VAR *v;
2754d1457ceScgd 		struct varent *vent;
2764d1457ceScgd 
277d9463bc1Sapb 		/*
278d9463bc1Sapb 		 * skip separators before the first keyword, and
279d9463bc1Sapb 		 * look for the separator after the keyword.
280d9463bc1Sapb 		 */
281d9463bc1Sapb 		for (cp = p; *cp != '\0'; cp++) {
282d9463bc1Sapb 		    p = strpbrk(cp, FMTSEP);
283d9463bc1Sapb 		    if (p != cp)
284d9463bc1Sapb 			break;
285d9463bc1Sapb 		}
286d9463bc1Sapb 		if (*cp == '\0')
287d9463bc1Sapb 		    break;
288d9463bc1Sapb 		/*
289d9463bc1Sapb 		 * Now cp points to the start of a keyword,
290d9463bc1Sapb 		 * and p is NULL or points past the end of the keyword.
291d9463bc1Sapb 		 *
292d9463bc1Sapb 		 * Terminate the keyword with '\0', or reinstate the
293d9463bc1Sapb 		 * '=' that was removed earlier, if appropriate.
294d9463bc1Sapb 		 */
295d9463bc1Sapb 		if (p) {
296d9463bc1Sapb 			*p = '\0';
297d9463bc1Sapb 			p++;
298d9463bc1Sapb 		} else if (equalsp) {
299d9463bc1Sapb 			*equalsp = '=';
300d9463bc1Sapb 		}
301d9463bc1Sapb 
302d9463bc1Sapb 		/*
303d9463bc1Sapb 		 * If findvar() likes the keyword or keyword=header,
304d9463bc1Sapb 		 * add it to our list.  If findvar() doesn't like it,
305d9463bc1Sapb 		 * it will print a warning, so we ignore it.
306d9463bc1Sapb 		 */
307d9463bc1Sapb 		if ((v = findvar(cp)) == NULL)
30861f28255Scgd 			continue;
309d92ffdbeSchristos 		vent = emalloc(sizeof(*vent));
31061f28255Scgd 		vent->var = v;
311d9463bc1Sapb 		if (pos && *pos)
312d9463bc1Sapb 		    SIMPLEQ_INSERT_AFTER(listptr, *pos, vent, next);
313d9463bc1Sapb 		else {
314d9463bc1Sapb 		    SIMPLEQ_INSERT_TAIL(listptr, vent, next);
315d9463bc1Sapb 		}
316d9463bc1Sapb 		if (pos)
317d9463bc1Sapb 		    *pos = vent;
31861f28255Scgd 	}
319eb903308Schristos  	free(sp);
320d9463bc1Sapb 	if (SIMPLEQ_EMPTY(listptr))
32171097a5aSchristos 		errx(EXIT_FAILURE, "no valid keywords");
32261f28255Scgd }
32361f28255Scgd 
324f24cb256Sdsl void
parsefmt(const char * p)325f24cb256Sdsl parsefmt(const char *p)
32661f28255Scgd {
32761f28255Scgd 
328d9463bc1Sapb 	parsevarlist(p, &displaylist, NULL);
329d9463bc1Sapb }
330d9463bc1Sapb 
331d9463bc1Sapb void
parsefmt_insert(const char * p,struct varent ** pos)332d9463bc1Sapb parsefmt_insert(const char *p, struct varent **pos)
333d9463bc1Sapb {
334d9463bc1Sapb 
335d9463bc1Sapb 	parsevarlist(p, &displaylist, pos);
336f24cb256Sdsl }
337f24cb256Sdsl 
338f24cb256Sdsl void
parsesort(const char * p)339f24cb256Sdsl parsesort(const char *p)
340f24cb256Sdsl {
341f24cb256Sdsl 
342d9463bc1Sapb 	parsevarlist(p, &sortlist, NULL);
343d9463bc1Sapb }
344d9463bc1Sapb 
345d9463bc1Sapb /* Search through a list for an entry with a specified name. */
346d9463bc1Sapb struct varent *
varlist_find(struct varlist * list,const char * name)347d9463bc1Sapb varlist_find(struct varlist *list, const char *name)
348d9463bc1Sapb {
349d9463bc1Sapb 	struct varent *vent;
350d9463bc1Sapb 
351d9463bc1Sapb 	SIMPLEQ_FOREACH(vent, list, next) {
352d9463bc1Sapb 		if (strcmp(vent->var->name, name) == 0)
353d9463bc1Sapb 			break;
354d9463bc1Sapb 	}
355d9463bc1Sapb 	return vent;
356f24cb256Sdsl }
357f24cb256Sdsl 
358f24cb256Sdsl static VAR *
findvar(const char * p)359f24cb256Sdsl findvar(const char *p)
360f24cb256Sdsl {
361f24cb256Sdsl 	VAR *v;
362f24cb256Sdsl 	char *hp;
363973821efSchristos 	char pp[1024];
364973821efSchristos 	strlcpy(pp, p, sizeof(pp));
36561f28255Scgd 
366973821efSchristos 	hp = strchr(pp, '=');
36761f28255Scgd 	if (hp)
36861f28255Scgd 		*hp++ = '\0';
369973821efSchristos 	for (char *dp = pp; *dp; dp++)
370973821efSchristos 		*dp = tolower((unsigned char)*dp);
37161f28255Scgd 
372d92ffdbeSchristos 	v = bsearch(pp, var, __arraycount(var) - 1, sizeof(*var), vcmp);
373f24cb256Sdsl 	if (v && v->flag & ALIAS)
374f24cb256Sdsl 		v = findvar(v->header);
37561f28255Scgd 	if (!v) {
3764d1457ceScgd 		warnx("%s: keyword not found", p);
37761f28255Scgd 		eval = 1;
378f24cb256Sdsl 		return NULL;
37961f28255Scgd 	}
380f24cb256Sdsl 
381973821efSchristos 	if (!hp && *p == *pp)
382973821efSchristos 		return v;
383973821efSchristos 
384d92ffdbeSchristos 	struct var *newvar = emalloc(sizeof(*newvar));
385d92ffdbeSchristos 	*newvar = *v;
386973821efSchristos 
387973821efSchristos 	if (hp) {
388d9463bc1Sapb 		/*
389d9463bc1Sapb 		 * Override the header.
390d9463bc1Sapb 		 *
391d9463bc1Sapb 		 * We need to copy the entry first, and override the
392d9463bc1Sapb 		 * header in the copy, because the same field might be
393d9463bc1Sapb 		 * used multiple times with different headers.  We also
394d9463bc1Sapb 		 * need to strdup the header.
395d9463bc1Sapb 		 */
396d92ffdbeSchristos 		newvar->header = estrdup(hp);
397d9463bc1Sapb 		/*
398d9463bc1Sapb 		 * According to P1003.1-2004, if the header text is null,
399d9463bc1Sapb 		 * such as -o user=, the field width will be at least as
400d9463bc1Sapb 		 * wide as the default header text.
401d9463bc1Sapb 		 */
402d9463bc1Sapb 		if (*hp == '\0')
4037c5fcf62Sapb 			newvar->width = strlen(v->header);
404d9463bc1Sapb 	}
405973821efSchristos 
406973821efSchristos 	if (*p != *pp)
407973821efSchristos 		newvar->flag |= ALTPR|LJUST;
408973821efSchristos 
409*f7f9a06bSchristos 	return newvar;
41061f28255Scgd }
41161f28255Scgd 
4124d1457ceScgd static int
vcmp(const void * a,const void * b)413f24cb256Sdsl vcmp(const void *a, const void *b)
41461f28255Scgd {
4156310b596Schristos         return strcmp(a, ((const VAR *)b)->name);
41661f28255Scgd }
417