1/*-
2 * Copyright (c) 1991, 1993, 1994
3 *	The Regents of the University of California.  All rights reserved.
4 * Copyright (c) 1991, 1993, 1994, 1995, 1996
5 *	Keith Bostic.  All rights reserved.
6 *
7 * See the LICENSE file for redistribution information.
8 */
9
10#include "config.h"
11
12#include <sys/types.h>
13#include <sys/queue.h>
14
15#ifdef __APPLE__
16#include <mach/clock.h>
17#include <mach/mach.h>
18#include <mach/mach_time.h>
19#endif
20
21#include <bitstring.h>
22#include <ctype.h>
23#include <errno.h>
24#include <limits.h>
25#include <pwd.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <time.h>
30#include <unistd.h>
31
32#include "common.h"
33
34/*
35 * binc --
36 *	Increase the size of a buffer.
37 *
38 * PUBLIC: void *binc(SCR *, void *, size_t *, size_t);
39 */
40void *
41binc(SCR *sp,			/* sp MAY BE NULL!!! */
42    void *bp, size_t *bsizep, size_t min)
43{
44	size_t csize;
45
46	/* If already larger than the minimum, just return. */
47	if (min && *bsizep >= min)
48		return (bp);
49
50	csize = p2roundup(MAX(min, 256));
51	REALLOC(sp, bp, void *, csize);
52
53	if (bp == NULL) {
54		*bsizep = 0;
55		return (NULL);
56	}
57	/*
58	 * Memory is guaranteed to be zero-filled, various parts of
59	 * nvi depend on this.
60	 */
61	memset((char *)bp + *bsizep, 0, csize - *bsizep);
62	*bsizep = csize;
63	return (bp);
64}
65
66/*
67 * nonblank --
68 *	Set the column number of the first non-blank character
69 *	including or after the starting column.  On error, set
70 *	the column to 0, it's safest.
71 *
72 * PUBLIC: int nonblank(SCR *, recno_t, size_t *);
73 */
74int
75nonblank(SCR *sp, recno_t lno, size_t *cnop)
76{
77	CHAR_T *p;
78	size_t cnt, len, off;
79	int isempty;
80
81	/* Default. */
82	off = *cnop;
83	*cnop = 0;
84
85	/* Get the line, succeeding in an empty file. */
86	if (db_eget(sp, lno, &p, &len, &isempty))
87		return (!isempty);
88
89	/* Set the offset. */
90	if (len == 0 || off >= len)
91		return (0);
92
93	for (cnt = off, p = &p[off],
94	    len -= off; len && ISBLANK(*p); ++cnt, ++p, --len);
95
96	/* Set the return. */
97	*cnop = len ? cnt : cnt - 1;
98	return (0);
99}
100
101/*
102 * join --
103 *	Join two paths; need free.
104 *
105 * PUBLIC: char *join(char *, char *);
106 */
107char *
108join(char *path1, char *path2)
109{
110	char *p;
111
112	if (path1[0] == '\0' || path2[0] == '/')
113		return strdup(path2);
114	if (asprintf(&p, path1[strlen(path1)-1] == '/' ?
115	    "%s%s" : "%s/%s", path1, path2) == -1)
116		return NULL;
117	return p;
118}
119
120/*
121 * expanduser --
122 *	Return a "~" or "~user" expanded path; need free.
123 *
124 * PUBLIC: char *expanduser(char *);
125 */
126char *
127expanduser(char *str)
128{
129	struct passwd *pwd;
130	char *p, *t, *u, *h;
131
132	/*
133	 * This function always expands the content between the
134	 * leading '~' and the first '/' or '\0' from the input.
135	 * Return NULL whenever we fail to do so.
136	 */
137	if (*str != '~')
138		return (NULL);
139	p = str + 1;
140	for (t = p; *t != '/' && *t != '\0'; ++t)
141		continue;
142	if (t == p) {
143		/* ~ */
144#ifdef __GLIBC__
145		extern char *secure_getenv(const char *);
146		if ((h = secure_getenv("HOME")) == NULL) {
147#else
148		if (issetugid() != 0 ||
149		    (h = getenv("HOME")) == NULL) {
150#endif
151			if (((h = getlogin()) != NULL &&
152			     (pwd = getpwnam(h)) != NULL) ||
153			    (pwd = getpwuid(getuid())) != NULL)
154				h = pwd->pw_dir;
155			else
156				return (NULL);
157		}
158	} else {
159		/* ~user */
160		if ((u = strndup(p, t - p)) == NULL)
161			return (NULL);
162		if ((pwd = getpwnam(u)) == NULL) {
163			free(u);
164			return (NULL);
165		} else
166			h = pwd->pw_dir;
167		free(u);
168	}
169
170	for (; *t == '/' && *t != '\0'; ++t)
171		continue;
172	return (join(h, t));
173}
174
175/*
176 * quote --
177 *	Return a escaped string for /bin/sh; need free.
178 *
179 * PUBLIC: char *quote(char *);
180 */
181char *
182quote(char *str)
183{
184	char *p, *t;
185	size_t i = 0, n = 0;
186	int unsafe = 0;
187
188	for (p = str; *p != '\0'; p++, i++) {
189		if (*p == '\'')
190			n++;
191		if (unsafe)
192			continue;
193		if (isascii((u_char)*p)) {
194			if (isalnum((u_char)*p))
195				continue;
196			switch (*p) {
197			case '%': case '+': case ',': case '-': case '.':
198			case '/': case ':': case '=': case '@': case '_':
199				continue;
200			}
201		}
202		unsafe = 1;
203	}
204	if (!unsafe)
205		t = strdup(str);
206#define SQT "'\\''"
207	else if ((p = t = malloc(i + n * (sizeof(SQT) - 2) + 3)) != NULL) {
208		*p++ = '\'';
209		for (; *str != '\0'; str++) {
210			if (*str == '\'') {
211				(void)memcpy(p, SQT, sizeof(SQT) - 1);
212				p += sizeof(SQT) - 1;
213			} else
214				*p++ = *str;
215		}
216		*p++ = '\'';
217		*p = '\0';
218	}
219	return t;
220}
221
222/*
223 * v_strdup --
224 *	Strdup for 8-bit character strings with an associated length.
225 *
226 * PUBLIC: char *v_strdup(SCR *, const char *, size_t);
227 */
228char *
229v_strdup(SCR *sp, const char *str, size_t len)
230{
231	char *copy;
232
233	MALLOC(sp, copy, len + 1);
234	if (copy == NULL)
235		return (NULL);
236	memcpy(copy, str, len);
237	copy[len] = '\0';
238	return (copy);
239}
240
241/*
242 * v_wstrdup --
243 *	Strdup for wide character strings with an associated length.
244 *
245 * PUBLIC: CHAR_T *v_wstrdup(SCR *, const CHAR_T *, size_t);
246 */
247CHAR_T *
248v_wstrdup(SCR *sp, const CHAR_T *str, size_t len)
249{
250	CHAR_T *copy;
251
252	MALLOC(sp, copy, (len + 1) * sizeof(CHAR_T));
253	if (copy == NULL)
254		return (NULL);
255	MEMCPY(copy, str, len);
256	copy[len] = '\0';
257	return (copy);
258}
259
260/*
261 * nget_uslong --
262 *      Get an unsigned long, checking for overflow.
263 *
264 * PUBLIC: enum nresult nget_uslong(u_long *, const CHAR_T *, CHAR_T **, int);
265 */
266enum nresult
267nget_uslong(u_long *valp, const CHAR_T *p, CHAR_T **endp, int base)
268{
269	errno = 0;
270	*valp = STRTOUL(p, endp, base);
271	if (errno == 0)
272		return (NUM_OK);
273	if (errno == ERANGE && *valp == ULONG_MAX)
274		return (NUM_OVER);
275	return (NUM_ERR);
276}
277
278/*
279 * nget_slong --
280 *      Convert a signed long, checking for overflow and underflow.
281 *
282 * PUBLIC: enum nresult nget_slong(long *, const CHAR_T *, CHAR_T **, int);
283 */
284enum nresult
285nget_slong(long *valp, const CHAR_T *p, CHAR_T **endp, int base)
286{
287	errno = 0;
288	*valp = STRTOL(p, endp, base);
289	if (errno == 0)
290		return (NUM_OK);
291	if (errno == ERANGE) {
292		if (*valp == LONG_MAX)
293			return (NUM_OVER);
294		if (*valp == LONG_MIN)
295			return (NUM_UNDER);
296	}
297	return (NUM_ERR);
298}
299
300/*
301 * timepoint_steady --
302 *      Get a timestamp from a monotonic clock.
303 *
304 * PUBLIC: void timepoint_steady(struct timespec *);
305 */
306void
307timepoint_steady(struct timespec *ts)
308{
309#ifdef __APPLE__
310	static mach_timebase_info_data_t base = { 0 };
311	uint64_t val;
312	uint64_t ns;
313
314	if (base.denom == 0)
315		(void)mach_timebase_info(&base);
316
317	val = mach_absolute_time();
318	ns = val * base.numer / base.denom;
319	ts->tv_sec = ns / 1000000000;
320	ts->tv_nsec = ns % 1000000000;
321#else
322#ifdef CLOCK_MONOTONIC_FAST
323	(void)clock_gettime(CLOCK_MONOTONIC_FAST, ts);
324#else
325	(void)clock_gettime(CLOCK_MONOTONIC, ts);
326#endif
327#endif
328}
329
330/*
331 * timepoint_system --
332 *      Get the current calendar time.
333 *
334 * PUBLIC: void timepoint_system(struct timespec *);
335 */
336void
337timepoint_system(struct timespec *ts)
338{
339#ifdef __APPLE__
340	clock_serv_t clk;
341	mach_timespec_t mts;
342	kern_return_t kr;
343
344	kr = host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &clk);
345	if (kr != KERN_SUCCESS)
346		return;
347	(void)clock_get_time(clk, &mts);
348	(void)mach_port_deallocate(mach_task_self(), clk);
349	ts->tv_sec = mts.tv_sec;
350	ts->tv_nsec = mts.tv_nsec;
351#else
352#ifdef CLOCK_REALTIME_FAST
353	(void)clock_gettime(CLOCK_REALTIME_FAST, ts);
354#else
355	(void)clock_gettime(CLOCK_REALTIME, ts);
356#endif
357#endif
358}
359
360#ifdef DEBUG
361#include <stdarg.h>
362
363/*
364 * TRACE --
365 *	debugging trace routine.
366 *
367 * PUBLIC: void TRACE(SCR *, const char *, ...);
368 */
369void
370TRACE(SCR *sp, const char *fmt, ...)
371{
372	FILE *tfp;
373	va_list ap;
374
375	if ((tfp = sp->gp->tracefp) == NULL)
376		return;
377	va_start(ap, fmt);
378	(void)vfprintf(tfp, fmt, ap);
379	va_end(ap);
380
381	(void)fflush(tfp);
382}
383#endif
384