1b8ba871bSPeter Wemm /*-
2b8ba871bSPeter Wemm * Copyright (c) 1991, 1993, 1994
3b8ba871bSPeter Wemm * The Regents of the University of California. All rights reserved.
4b8ba871bSPeter Wemm * Copyright (c) 1991, 1993, 1994, 1995, 1996
5b8ba871bSPeter Wemm * Keith Bostic. All rights reserved.
6b8ba871bSPeter Wemm *
7b8ba871bSPeter Wemm * See the LICENSE file for redistribution information.
8b8ba871bSPeter Wemm */
9b8ba871bSPeter Wemm
10b8ba871bSPeter Wemm #include "config.h"
11b8ba871bSPeter Wemm
12b8ba871bSPeter Wemm #include <sys/types.h>
13b8ba871bSPeter Wemm #include <sys/queue.h>
14b8ba871bSPeter Wemm
15b8ba871bSPeter Wemm #ifdef __APPLE__
16b8ba871bSPeter Wemm #include <mach/clock.h>
17b8ba871bSPeter Wemm #include <mach/mach.h>
18b8ba871bSPeter Wemm #include <mach/mach_time.h>
19b8ba871bSPeter Wemm #endif
20b8ba871bSPeter Wemm
21b8ba871bSPeter Wemm #include <bitstring.h>
22b8ba871bSPeter Wemm #include <ctype.h>
23b8ba871bSPeter Wemm #include <errno.h>
24b8ba871bSPeter Wemm #include <limits.h>
25b8ba871bSPeter Wemm #include <pwd.h>
26b8ba871bSPeter Wemm #include <stdio.h>
27b8ba871bSPeter Wemm #include <stdlib.h>
28b8ba871bSPeter Wemm #include <string.h>
29b8ba871bSPeter Wemm #include <time.h>
30b8ba871bSPeter Wemm #include <unistd.h>
31b8ba871bSPeter Wemm
32b8ba871bSPeter Wemm #include "common.h"
33b8ba871bSPeter Wemm
34b8ba871bSPeter Wemm /*
35b8ba871bSPeter Wemm * binc --
36b8ba871bSPeter Wemm * Increase the size of a buffer.
37b8ba871bSPeter Wemm *
38b8ba871bSPeter Wemm * PUBLIC: void *binc(SCR *, void *, size_t *, size_t);
39b8ba871bSPeter Wemm */
40b8ba871bSPeter Wemm void *
binc(SCR * sp,void * bp,size_t * bsizep,size_t min)41b8ba871bSPeter Wemm binc(SCR *sp, /* sp MAY BE NULL!!! */
42b8ba871bSPeter Wemm void *bp, size_t *bsizep, size_t min)
43b8ba871bSPeter Wemm {
44b8ba871bSPeter Wemm size_t csize;
45b8ba871bSPeter Wemm
46b8ba871bSPeter Wemm /* If already larger than the minimum, just return. */
47b8ba871bSPeter Wemm if (min && *bsizep >= min)
48b8ba871bSPeter Wemm return (bp);
49b8ba871bSPeter Wemm
50b8ba871bSPeter Wemm csize = p2roundup(MAX(min, 256));
51b8ba871bSPeter Wemm REALLOC(sp, bp, void *, csize);
52b8ba871bSPeter Wemm
53b8ba871bSPeter Wemm if (bp == NULL) {
54b8ba871bSPeter Wemm *bsizep = 0;
55b8ba871bSPeter Wemm return (NULL);
56b8ba871bSPeter Wemm }
57b8ba871bSPeter Wemm /*
58b8ba871bSPeter Wemm * Memory is guaranteed to be zero-filled, various parts of
59b8ba871bSPeter Wemm * nvi depend on this.
60b8ba871bSPeter Wemm */
61b8ba871bSPeter Wemm memset((char *)bp + *bsizep, 0, csize - *bsizep);
62b8ba871bSPeter Wemm *bsizep = csize;
63b8ba871bSPeter Wemm return (bp);
64b8ba871bSPeter Wemm }
65b8ba871bSPeter Wemm
66b8ba871bSPeter Wemm /*
67b8ba871bSPeter Wemm * nonblank --
68b8ba871bSPeter Wemm * Set the column number of the first non-blank character
69b8ba871bSPeter Wemm * including or after the starting column. On error, set
70b8ba871bSPeter Wemm * the column to 0, it's safest.
71b8ba871bSPeter Wemm *
72b8ba871bSPeter Wemm * PUBLIC: int nonblank(SCR *, recno_t, size_t *);
73b8ba871bSPeter Wemm */
74b8ba871bSPeter Wemm int
nonblank(SCR * sp,recno_t lno,size_t * cnop)75b8ba871bSPeter Wemm nonblank(SCR *sp, recno_t lno, size_t *cnop)
76b8ba871bSPeter Wemm {
77b8ba871bSPeter Wemm CHAR_T *p;
78b8ba871bSPeter Wemm size_t cnt, len, off;
79b8ba871bSPeter Wemm int isempty;
80b8ba871bSPeter Wemm
81b8ba871bSPeter Wemm /* Default. */
82b8ba871bSPeter Wemm off = *cnop;
83b8ba871bSPeter Wemm *cnop = 0;
84b8ba871bSPeter Wemm
85b8ba871bSPeter Wemm /* Get the line, succeeding in an empty file. */
86b8ba871bSPeter Wemm if (db_eget(sp, lno, &p, &len, &isempty))
87b8ba871bSPeter Wemm return (!isempty);
88b8ba871bSPeter Wemm
89b8ba871bSPeter Wemm /* Set the offset. */
90b8ba871bSPeter Wemm if (len == 0 || off >= len)
91b8ba871bSPeter Wemm return (0);
92b8ba871bSPeter Wemm
93b8ba871bSPeter Wemm for (cnt = off, p = &p[off],
94b8ba871bSPeter Wemm len -= off; len && ISBLANK(*p); ++cnt, ++p, --len);
95b8ba871bSPeter Wemm
96b8ba871bSPeter Wemm /* Set the return. */
97b8ba871bSPeter Wemm *cnop = len ? cnt : cnt - 1;
98b8ba871bSPeter Wemm return (0);
99b8ba871bSPeter Wemm }
100b8ba871bSPeter Wemm
101b8ba871bSPeter Wemm /*
102b8ba871bSPeter Wemm * join --
103b8ba871bSPeter Wemm * Join two paths; need free.
104b8ba871bSPeter Wemm *
105b8ba871bSPeter Wemm * PUBLIC: char *join(char *, char *);
106b8ba871bSPeter Wemm */
107b8ba871bSPeter Wemm char *
join(char * path1,char * path2)108b8ba871bSPeter Wemm join(char *path1, char *path2)
109b8ba871bSPeter Wemm {
110b8ba871bSPeter Wemm char *p;
111b8ba871bSPeter Wemm
112b8ba871bSPeter Wemm if (path1[0] == '\0' || path2[0] == '/')
113b8ba871bSPeter Wemm return strdup(path2);
114b8ba871bSPeter Wemm if (asprintf(&p, path1[strlen(path1)-1] == '/' ?
115b8ba871bSPeter Wemm "%s%s" : "%s/%s", path1, path2) == -1)
116b8ba871bSPeter Wemm return NULL;
117b8ba871bSPeter Wemm return p;
118b8ba871bSPeter Wemm }
119b8ba871bSPeter Wemm
120b8ba871bSPeter Wemm /*
121b8ba871bSPeter Wemm * expanduser --
122b8ba871bSPeter Wemm * Return a "~" or "~user" expanded path; need free.
123b8ba871bSPeter Wemm *
124b8ba871bSPeter Wemm * PUBLIC: char *expanduser(char *);
125b8ba871bSPeter Wemm */
126b8ba871bSPeter Wemm char *
expanduser(char * str)127b8ba871bSPeter Wemm expanduser(char *str)
128b8ba871bSPeter Wemm {
129b8ba871bSPeter Wemm struct passwd *pwd;
130b8ba871bSPeter Wemm char *p, *t, *u, *h;
131b8ba871bSPeter Wemm
132b8ba871bSPeter Wemm /*
133b8ba871bSPeter Wemm * This function always expands the content between the
134b8ba871bSPeter Wemm * leading '~' and the first '/' or '\0' from the input.
135b8ba871bSPeter Wemm * Return NULL whenever we fail to do so.
136b8ba871bSPeter Wemm */
137b8ba871bSPeter Wemm if (*str != '~')
138b8ba871bSPeter Wemm return (NULL);
139b8ba871bSPeter Wemm p = str + 1;
140b8ba871bSPeter Wemm for (t = p; *t != '/' && *t != '\0'; ++t)
141b8ba871bSPeter Wemm continue;
142b8ba871bSPeter Wemm if (t == p) {
143b8ba871bSPeter Wemm /* ~ */
144b8ba871bSPeter Wemm #ifdef __GLIBC__
145b8ba871bSPeter Wemm extern char *secure_getenv(const char *);
146b8ba871bSPeter Wemm if ((h = secure_getenv("HOME")) == NULL) {
147b8ba871bSPeter Wemm #else
148b8ba871bSPeter Wemm if (issetugid() != 0 ||
149b8ba871bSPeter Wemm (h = getenv("HOME")) == NULL) {
150b8ba871bSPeter Wemm #endif
151b8ba871bSPeter Wemm if (((h = getlogin()) != NULL &&
152b8ba871bSPeter Wemm (pwd = getpwnam(h)) != NULL) ||
153b8ba871bSPeter Wemm (pwd = getpwuid(getuid())) != NULL)
154b8ba871bSPeter Wemm h = pwd->pw_dir;
155b8ba871bSPeter Wemm else
156b8ba871bSPeter Wemm return (NULL);
157b8ba871bSPeter Wemm }
158b8ba871bSPeter Wemm } else {
159b8ba871bSPeter Wemm /* ~user */
160b8ba871bSPeter Wemm if ((u = strndup(p, t - p)) == NULL)
161b8ba871bSPeter Wemm return (NULL);
162b8ba871bSPeter Wemm if ((pwd = getpwnam(u)) == NULL) {
163b8ba871bSPeter Wemm free(u);
164b8ba871bSPeter Wemm return (NULL);
165b8ba871bSPeter Wemm } else
166b8ba871bSPeter Wemm h = pwd->pw_dir;
167b8ba871bSPeter Wemm free(u);
168b8ba871bSPeter Wemm }
169b8ba871bSPeter Wemm
170b8ba871bSPeter Wemm for (; *t == '/' && *t != '\0'; ++t)
171b8ba871bSPeter Wemm continue;
172b8ba871bSPeter Wemm return (join(h, t));
173b8ba871bSPeter Wemm }
174b8ba871bSPeter Wemm
175b8ba871bSPeter Wemm /*
176b8ba871bSPeter Wemm * quote --
177b8ba871bSPeter Wemm * Return a escaped string for /bin/sh; need free.
178b8ba871bSPeter Wemm *
179b8ba871bSPeter Wemm * PUBLIC: char *quote(char *);
180b8ba871bSPeter Wemm */
181b8ba871bSPeter Wemm char *
182b8ba871bSPeter Wemm quote(char *str)
183b8ba871bSPeter Wemm {
184b8ba871bSPeter Wemm char *p, *t;
185b8ba871bSPeter Wemm size_t i = 0, n = 0;
186b8ba871bSPeter Wemm int unsafe = 0;
187b8ba871bSPeter Wemm
188b8ba871bSPeter Wemm for (p = str; *p != '\0'; p++, i++) {
189b8ba871bSPeter Wemm if (*p == '\'')
190b8ba871bSPeter Wemm n++;
191b8ba871bSPeter Wemm if (unsafe)
192b8ba871bSPeter Wemm continue;
193b8ba871bSPeter Wemm if (isascii((u_char)*p)) {
194b8ba871bSPeter Wemm if (isalnum((u_char)*p))
195b8ba871bSPeter Wemm continue;
196b8ba871bSPeter Wemm switch (*p) {
197b8ba871bSPeter Wemm case '%': case '+': case ',': case '-': case '.':
198b8ba871bSPeter Wemm case '/': case ':': case '=': case '@': case '_':
199b8ba871bSPeter Wemm continue;
200b8ba871bSPeter Wemm }
201b8ba871bSPeter Wemm }
202b8ba871bSPeter Wemm unsafe = 1;
203b8ba871bSPeter Wemm }
204b8ba871bSPeter Wemm if (!unsafe)
205b8ba871bSPeter Wemm t = strdup(str);
206b8ba871bSPeter Wemm #define SQT "'\\''"
207b8ba871bSPeter Wemm else if ((p = t = malloc(i + n * (sizeof(SQT) - 2) + 3)) != NULL) {
208b8ba871bSPeter Wemm *p++ = '\'';
209b8ba871bSPeter Wemm for (; *str != '\0'; str++) {
210b8ba871bSPeter Wemm if (*str == '\'') {
211b8ba871bSPeter Wemm (void)memcpy(p, SQT, sizeof(SQT) - 1);
212b8ba871bSPeter Wemm p += sizeof(SQT) - 1;
213b8ba871bSPeter Wemm } else
214b8ba871bSPeter Wemm *p++ = *str;
215b8ba871bSPeter Wemm }
216b8ba871bSPeter Wemm *p++ = '\'';
217b8ba871bSPeter Wemm *p = '\0';
218b8ba871bSPeter Wemm }
219b8ba871bSPeter Wemm return t;
220b8ba871bSPeter Wemm }
221b8ba871bSPeter Wemm
222b8ba871bSPeter Wemm /*
223b8ba871bSPeter Wemm * v_strdup --
224b8ba871bSPeter Wemm * Strdup for 8-bit character strings with an associated length.
225b8ba871bSPeter Wemm *
226b8ba871bSPeter Wemm * PUBLIC: char *v_strdup(SCR *, const char *, size_t);
227b8ba871bSPeter Wemm */
228b8ba871bSPeter Wemm char *
229b8ba871bSPeter Wemm v_strdup(SCR *sp, const char *str, size_t len)
230b8ba871bSPeter Wemm {
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 */
247 CHAR_T *
248 v_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 */
266 enum nresult
267 nget_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 */
284 enum nresult
285 nget_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 */
306 void
307 timepoint_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 */
336 void
337 timepoint_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 */
369 void
370 TRACE(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