119304Speter/*-
219304Speter * Copyright (c) 1991, 1993, 1994
319304Speter *	The Regents of the University of California.  All rights reserved.
419304Speter * Copyright (c) 1991, 1993, 1994, 1995, 1996
519304Speter *	Keith Bostic.  All rights reserved.
619304Speter *
719304Speter * See the LICENSE file for redistribution information.
819304Speter */
919304Speter
1019304Speter#include "config.h"
1119304Speter
1219304Speter#ifndef lint
13254225Speterstatic const char sccsid[] = "$Id: util.c,v 10.30 2013/03/19 10:00:27 yamt Exp $";
1419304Speter#endif /* not lint */
1519304Speter
1619304Speter#include <sys/types.h>
1719304Speter#include <sys/queue.h>
1819304Speter
19254225Speter#ifdef __APPLE__
20254225Speter#include <mach/clock.h>
21254225Speter#include <mach/mach.h>
22254225Speter#include <mach/mach_time.h>
23254225Speter#endif
24254225Speter
2519304Speter#include <bitstring.h>
26254225Speter#include <ctype.h>
2719304Speter#include <errno.h>
2819304Speter#include <limits.h>
29254225Speter#include <pwd.h>
3019304Speter#include <stdio.h>
3119304Speter#include <stdlib.h>
3219304Speter#include <string.h>
33254225Speter#include <time.h>
3419304Speter#include <unistd.h>
3519304Speter
3619304Speter#include "common.h"
3719304Speter
3819304Speter/*
3919304Speter * binc --
4019304Speter *	Increase the size of a buffer.
4119304Speter *
42281373Sbapt * PUBLIC: void *binc(SCR *, void *, size_t *, size_t);
4319304Speter */
4419304Spetervoid *
45254225Speterbinc(
46254225Speter	SCR *sp,			/* sp MAY BE NULL!!! */
47254225Speter	void *bp,
48254225Speter	size_t *bsizep,
49254225Speter	size_t min)
5019304Speter{
5119304Speter	size_t csize;
5219304Speter
5319304Speter	/* If already larger than the minimum, just return. */
5419304Speter	if (min && *bsizep >= min)
5519304Speter		return (bp);
5619304Speter
57254225Speter	csize = p2roundup(MAX(min, 256));
5819304Speter	REALLOC(sp, bp, void *, csize);
5919304Speter
6019304Speter	if (bp == NULL) {
6119304Speter		*bsizep = 0;
6219304Speter		return (NULL);
6319304Speter	}
6419304Speter	/*
6519304Speter	 * Memory is guaranteed to be zero-filled, various parts of
6619304Speter	 * nvi depend on this.
6719304Speter	 */
6819304Speter	memset((char *)bp + *bsizep, 0, csize - *bsizep);
6919304Speter	*bsizep = csize;
7019304Speter	return (bp);
7119304Speter}
7219304Speter
7319304Speter/*
7419304Speter * nonblank --
7519304Speter *	Set the column number of the first non-blank character
7619304Speter *	including or after the starting column.  On error, set
7719304Speter *	the column to 0, it's safest.
7819304Speter *
79281373Sbapt * PUBLIC: int nonblank(SCR *, recno_t, size_t *);
8019304Speter */
8119304Speterint
82254225Speternonblank(
83254225Speter	SCR *sp,
84254225Speter	recno_t lno,
85254225Speter	size_t *cnop)
8619304Speter{
87254225Speter	CHAR_T *p;
8819304Speter	size_t cnt, len, off;
8919304Speter	int isempty;
9019304Speter
9119304Speter	/* Default. */
9219304Speter	off = *cnop;
9319304Speter	*cnop = 0;
9419304Speter
9519304Speter	/* Get the line, succeeding in an empty file. */
9619304Speter	if (db_eget(sp, lno, &p, &len, &isempty))
9719304Speter		return (!isempty);
9819304Speter
9919304Speter	/* Set the offset. */
10019304Speter	if (len == 0 || off >= len)
10119304Speter		return (0);
10219304Speter
10319304Speter	for (cnt = off, p = &p[off],
104254225Speter	    len -= off; len && ISBLANK(*p); ++cnt, ++p, --len);
10519304Speter
10619304Speter	/* Set the return. */
10719304Speter	*cnop = len ? cnt : cnt - 1;
10819304Speter	return (0);
10919304Speter}
11019304Speter
11119304Speter/*
11219304Speter * tail --
11319304Speter *	Return tail of a path.
11419304Speter *
115281373Sbapt * PUBLIC: char *tail(char *);
11619304Speter */
11719304Speterchar *
118254225Spetertail(char *path)
11919304Speter{
12019304Speter	char *p;
12119304Speter
12219304Speter	if ((p = strrchr(path, '/')) == NULL)
12319304Speter		return (path);
12419304Speter	return (p + 1);
12519304Speter}
12619304Speter
12719304Speter/*
128254225Speter * join --
129254225Speter *	Join two paths; need free.
130254225Speter *
131281373Sbapt * PUBLIC: char *join(char *, char *);
132254225Speter */
133254225Speterchar *
134254225Speterjoin(
135281373Sbapt	char *path1,
136281373Sbapt	char *path2)
137254225Speter{
138254225Speter	char *p;
139254225Speter
140254225Speter	if (path1[0] == '\0' || path2[0] == '/')
141254225Speter		return strdup(path2);
142254225Speter	(void)asprintf(&p, path1[strlen(path1)-1] == '/' ?
143254225Speter	    "%s%s" : "%s/%s", path1, path2);
144254225Speter	return p;
145254225Speter}
146254225Speter
147254225Speter/*
148254225Speter * expanduser --
149254225Speter *	Return a "~" or "~user" expanded path; need free.
150254225Speter *
151281373Sbapt * PUBLIC: char *expanduser(char *);
152254225Speter */
153254225Speterchar *
154254225Speterexpanduser(char *str)
155254225Speter{
156254225Speter	struct passwd *pwd;
157254225Speter	char *p, *t, *u, *h;
158254225Speter
159254225Speter	/*
160254225Speter	 * This function always expands the content between the
161254225Speter	 * leading '~' and the first '/' or '\0' from the input.
162254225Speter	 * Return NULL whenever we fail to do so.
163254225Speter	 */
164254225Speter	if (*str != '~')
165254225Speter		return (NULL);
166254225Speter	p = str + 1;
167254225Speter	for (t = p; *t != '/' && *t != '\0'; ++t)
168254225Speter		continue;
169254225Speter	if (t == p) {
170254225Speter		/* ~ */
171254225Speter		if (issetugid() != 0 ||
172254225Speter		    (h = getenv("HOME")) == NULL) {
173254225Speter			if (((h = getlogin()) != NULL &&
174254225Speter			     (pwd = getpwnam(h)) != NULL) ||
175254225Speter			    (pwd = getpwuid(getuid())) != NULL)
176254225Speter				h = pwd->pw_dir;
177254225Speter			else
178254225Speter				return (NULL);
179254225Speter		}
180254225Speter	} else {
181254225Speter		/* ~user */
182254225Speter		if ((u = strndup(p, t - p)) == NULL)
183254225Speter			return (NULL);
184254225Speter		if ((pwd = getpwnam(u)) == NULL) {
185254225Speter			free(u);
186254225Speter			return (NULL);
187254225Speter		} else
188254225Speter			h = pwd->pw_dir;
189254225Speter		free(u);
190254225Speter	}
191254225Speter
192254225Speter	for (; *t == '/' && *t != '\0'; ++t)
193254225Speter		continue;
194254225Speter	return (join(h, t));
195254225Speter}
196254225Speter
197254225Speter/*
198254225Speter * quote --
199254225Speter *	Return a escaped string for /bin/sh; need free.
200254225Speter *
201281373Sbapt * PUBLIC: char *quote(char *);
202254225Speter */
203254225Speterchar *
204254225Speterquote(char *str)
205254225Speter{
206254225Speter	char *p, *t;
207254225Speter	size_t i = 0, n = 0;
208254225Speter	int unsafe = 0;
209254225Speter
210254225Speter	for (p = str; *p != '\0'; p++, i++) {
211254225Speter		if (*p == '\'')
212254225Speter			n++;
213254225Speter		if (unsafe)
214254225Speter			continue;
215254225Speter		if (isascii(*p)) {
216254225Speter			if (isalnum(*p))
217254225Speter				continue;
218254225Speter			switch (*p) {
219254225Speter			case '%': case '+': case ',': case '-': case '.':
220254225Speter			case '/': case ':': case '=': case '@': case '_':
221254225Speter				continue;
222254225Speter			}
223254225Speter		}
224254225Speter		unsafe = 1;
225254225Speter	}
226254225Speter	if (!unsafe)
227254225Speter		t = strdup(str);
228254225Speter#define SQT "'\\''"
229254225Speter	else if ((p = t = malloc(i + n * (sizeof(SQT) - 2) + 3)) != NULL) {
230254225Speter		*p++ = '\'';
231254225Speter		for (; *str != '\0'; str++) {
232254225Speter			if (*str == '\'') {
233254225Speter				(void)memcpy(p, SQT, sizeof(SQT) - 1);
234254225Speter				p += sizeof(SQT) - 1;
235254225Speter			} else
236254225Speter				*p++ = *str;
237254225Speter		}
238254225Speter		*p++ = '\'';
239254225Speter		*p = '\0';
240254225Speter	}
241254225Speter	return t;
242254225Speter}
243254225Speter
244254225Speter/*
24519304Speter * v_strdup --
246254225Speter *	Strdup for 8-bit character strings with an associated length.
247254225Speter *
248281373Sbapt * PUBLIC: char *v_strdup(SCR *, const char *, size_t);
249254225Speter */
250254225Speterchar *
251254225Speterv_strdup(
252254225Speter	SCR *sp,
253254225Speter	const char *str,
254254225Speter	size_t len)
255254225Speter{
256254225Speter	char *copy;
257254225Speter
258254225Speter	MALLOC(sp, copy, char *, len + 1);
259254225Speter	if (copy == NULL)
260254225Speter		return (NULL);
261254225Speter	memcpy(copy, str, len);
262254225Speter	copy[len] = '\0';
263254225Speter	return (copy);
264254225Speter}
265254225Speter
266254225Speter/*
267254225Speter * v_wstrdup --
26819304Speter *	Strdup for wide character strings with an associated length.
26919304Speter *
270281373Sbapt * PUBLIC: CHAR_T *v_wstrdup(SCR *, const CHAR_T *, size_t);
27119304Speter */
27219304SpeterCHAR_T *
273254225Speterv_wstrdup(SCR *sp,
274254225Speter	const CHAR_T *str,
275254225Speter	size_t len)
27619304Speter{
27719304Speter	CHAR_T *copy;
27819304Speter
279254225Speter	MALLOC(sp, copy, CHAR_T *, (len + 1) * sizeof(CHAR_T));
28019304Speter	if (copy == NULL)
28119304Speter		return (NULL);
282254225Speter	MEMCPY(copy, str, len);
28319304Speter	copy[len] = '\0';
28419304Speter	return (copy);
28519304Speter}
28619304Speter
28719304Speter/*
28819304Speter * nget_uslong --
28919304Speter *      Get an unsigned long, checking for overflow.
29019304Speter *
291281373Sbapt * PUBLIC: enum nresult nget_uslong(u_long *, const CHAR_T *, CHAR_T **, int);
29219304Speter */
29319304Speterenum nresult
294254225Speternget_uslong(
295254225Speter	u_long *valp,
296254225Speter	const CHAR_T *p,
297254225Speter	CHAR_T **endp,
298254225Speter	int base)
29919304Speter{
30019304Speter	errno = 0;
301254225Speter	*valp = STRTOUL(p, endp, base);
30219304Speter	if (errno == 0)
30319304Speter		return (NUM_OK);
30419304Speter	if (errno == ERANGE && *valp == ULONG_MAX)
30519304Speter		return (NUM_OVER);
30619304Speter	return (NUM_ERR);
30719304Speter}
30819304Speter
30919304Speter/*
31019304Speter * nget_slong --
31119304Speter *      Convert a signed long, checking for overflow and underflow.
31219304Speter *
313281373Sbapt * PUBLIC: enum nresult nget_slong(long *, const CHAR_T *, CHAR_T **, int);
31419304Speter */
31519304Speterenum nresult
316254225Speternget_slong(
317254225Speter	long *valp,
318254225Speter	const CHAR_T *p,
319254225Speter	CHAR_T **endp,
320254225Speter	int base)
32119304Speter{
32219304Speter	errno = 0;
323254225Speter	*valp = STRTOL(p, endp, base);
32419304Speter	if (errno == 0)
32519304Speter		return (NUM_OK);
32619304Speter	if (errno == ERANGE) {
32719304Speter		if (*valp == LONG_MAX)
32819304Speter			return (NUM_OVER);
32919304Speter		if (*valp == LONG_MIN)
33019304Speter			return (NUM_UNDER);
33119304Speter	}
33219304Speter	return (NUM_ERR);
33319304Speter}
33419304Speter
335254225Speter/*
336254225Speter * timepoint_steady --
337254225Speter *      Get a timestamp from a monotonic clock.
338254225Speter *
339281373Sbapt * PUBLIC: void timepoint_steady(struct timespec *);
340254225Speter */
341254225Spetervoid
342254225Spetertimepoint_steady(
343254225Speter	struct timespec *ts)
344254225Speter{
345254225Speter#ifdef __APPLE__
346254225Speter	static mach_timebase_info_data_t base = { 0 };
347254225Speter	uint64_t val;
348254225Speter	uint64_t ns;
349254225Speter
350254225Speter	if (base.denom == 0)
351254225Speter		(void)mach_timebase_info(&base);
352254225Speter
353254225Speter	val = mach_absolute_time();
354254225Speter	ns = val * base.numer / base.denom;
355254225Speter	ts->tv_sec = ns / 1000000000;
356254225Speter	ts->tv_nsec = ns % 1000000000;
35719304Speter#else
358254225Speter#ifdef CLOCK_MONOTONIC_FAST
359254225Speter	(void)clock_gettime(CLOCK_MONOTONIC_FAST, ts);
360254225Speter#else
361254225Speter	(void)clock_gettime(CLOCK_MONOTONIC, ts);
36219304Speter#endif
363254225Speter#endif
364254225Speter}
36519304Speter
36619304Speter/*
367254225Speter * timepoint_system --
368254225Speter *      Get the current calendar time.
369254225Speter *
370281373Sbapt * PUBLIC: void timepoint_system(struct timespec *);
371254225Speter */
372254225Spetervoid
373254225Spetertimepoint_system(
374254225Speter	struct timespec *ts)
375254225Speter{
376254225Speter#ifdef __APPLE__
377254225Speter	clock_serv_t clk;
378254225Speter	mach_timespec_t mts;
379254225Speter	kern_return_t kr;
380254225Speter
381254225Speter	kr = host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &clk);
382254225Speter	if (kr != KERN_SUCCESS)
383254225Speter		return;
384254225Speter	(void)clock_get_time(clk, &mts);
385254225Speter	(void)mach_port_deallocate(mach_task_self(), clk);
386254225Speter	ts->tv_sec = mts.tv_sec;
387254225Speter	ts->tv_nsec = mts.tv_nsec;
388254225Speter#else
389254225Speter#ifdef CLOCK_REALTIME_FAST
390254225Speter	(void)clock_gettime(CLOCK_REALTIME_FAST, ts);
391254225Speter#else
392254225Speter	(void)clock_gettime(CLOCK_REALTIME, ts);
393254225Speter#endif
394254225Speter#endif
395254225Speter}
396254225Speter
397254225Speter#ifdef DEBUG
398254225Speter#include <stdarg.h>
399254225Speter
400254225Speter/*
40119304Speter * TRACE --
40219304Speter *	debugging trace routine.
40319304Speter *
404281373Sbapt * PUBLIC: void TRACE(SCR *, const char *, ...);
40519304Speter */
40619304Spetervoid
407254225SpeterTRACE(
408254225Speter	SCR *sp,
409254225Speter	const char *fmt,
410254225Speter	...)
41119304Speter{
41219304Speter	FILE *tfp;
41319304Speter	va_list ap;
41419304Speter
41519304Speter	if ((tfp = sp->gp->tracefp) == NULL)
41619304Speter		return;
41719304Speter	va_start(ap, fmt);
41819304Speter	(void)vfprintf(tfp, fmt, ap);
41919304Speter	va_end(ap);
42019304Speter
42119304Speter	(void)fflush(tfp);
42219304Speter}
42319304Speter#endif
424