Bring in an errno.9 manual page (based on NetBSD's).
[dragonfly.git] / contrib / nvi2 / common / util.c
blob44c8e29482e676b596f72fbb1f73738bf3ded90e
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.
7 * See the LICENSE file for redistribution information.
8 */
10 #include "config.h"
12 #ifndef lint
13 static const char sccsid[] = "$Id: util.c,v 10.30 2013/03/19 10:00:27 yamt Exp $";
14 #endif /* not lint */
16 #include <sys/types.h>
17 #include <sys/queue.h>
19 #ifdef __APPLE__
20 #include <mach/clock.h>
21 #include <mach/mach.h>
22 #include <mach/mach_time.h>
23 #endif
25 #include <bitstring.h>
26 #include <ctype.h>
27 #include <errno.h>
28 #include <limits.h>
29 #include <pwd.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <time.h>
34 #include <unistd.h>
36 #include "common.h"
39 * binc --
40 * Increase the size of a buffer.
42 * PUBLIC: void *binc(SCR *, void *, size_t *, size_t);
44 void *
45 binc(
46 SCR *sp, /* sp MAY BE NULL!!! */
47 void *bp,
48 size_t *bsizep,
49 size_t min)
51 size_t csize;
53 /* If already larger than the minimum, just return. */
54 if (min && *bsizep >= min)
55 return (bp);
57 csize = p2roundup(MAX(min, 256));
58 REALLOC(sp, bp, void *, csize);
60 if (bp == NULL) {
61 *bsizep = 0;
62 return (NULL);
65 * Memory is guaranteed to be zero-filled, various parts of
66 * nvi depend on this.
68 memset((char *)bp + *bsizep, 0, csize - *bsizep);
69 *bsizep = csize;
70 return (bp);
74 * nonblank --
75 * Set the column number of the first non-blank character
76 * including or after the starting column. On error, set
77 * the column to 0, it's safest.
79 * PUBLIC: int nonblank(SCR *, recno_t, size_t *);
81 int
82 nonblank(
83 SCR *sp,
84 recno_t lno,
85 size_t *cnop)
87 CHAR_T *p;
88 size_t cnt, len, off;
89 int isempty;
91 /* Default. */
92 off = *cnop;
93 *cnop = 0;
95 /* Get the line, succeeding in an empty file. */
96 if (db_eget(sp, lno, &p, &len, &isempty))
97 return (!isempty);
99 /* Set the offset. */
100 if (len == 0 || off >= len)
101 return (0);
103 for (cnt = off, p = &p[off],
104 len -= off; len && ISBLANK(*p); ++cnt, ++p, --len);
106 /* Set the return. */
107 *cnop = len ? cnt : cnt - 1;
108 return (0);
112 * tail --
113 * Return tail of a path.
115 * PUBLIC: char *tail(char *);
117 char *
118 tail(char *path)
120 char *p;
122 if ((p = strrchr(path, '/')) == NULL)
123 return (path);
124 return (p + 1);
128 * join --
129 * Join two paths; need free.
131 * PUBLIC: char *join(char *, char *);
133 char *
134 join(
135 char *path1,
136 char *path2)
138 char *p;
140 if (path1[0] == '\0' || path2[0] == '/')
141 return strdup(path2);
142 (void)asprintf(&p, path1[strlen(path1)-1] == '/' ?
143 "%s%s" : "%s/%s", path1, path2);
144 return p;
148 * expanduser --
149 * Return a "~" or "~user" expanded path; need free.
151 * PUBLIC: char *expanduser(char *);
153 char *
154 expanduser(char *str)
156 struct passwd *pwd;
157 char *p, *t, *u, *h;
160 * This function always expands the content between the
161 * leading '~' and the first '/' or '\0' from the input.
162 * Return NULL whenever we fail to do so.
164 if (*str != '~')
165 return (NULL);
166 p = str + 1;
167 for (t = p; *t != '/' && *t != '\0'; ++t)
168 continue;
169 if (t == p) {
170 /* ~ */
171 if (issetugid() != 0 ||
172 (h = getenv("HOME")) == NULL) {
173 if (((h = getlogin()) != NULL &&
174 (pwd = getpwnam(h)) != NULL) ||
175 (pwd = getpwuid(getuid())) != NULL)
176 h = pwd->pw_dir;
177 else
178 return (NULL);
180 } else {
181 /* ~user */
182 if ((u = strndup(p, t - p)) == NULL)
183 return (NULL);
184 if ((pwd = getpwnam(u)) == NULL) {
185 free(u);
186 return (NULL);
187 } else
188 h = pwd->pw_dir;
189 free(u);
192 for (; *t == '/' && *t != '\0'; ++t)
193 continue;
194 return (join(h, t));
198 * quote --
199 * Return a escaped string for /bin/sh; need free.
201 * PUBLIC: char *quote(char *);
203 char *
204 quote(char *str)
206 char *p, *t;
207 size_t i = 0, n = 0;
208 int unsafe = 0;
210 for (p = str; *p != '\0'; p++, i++) {
211 if (*p == '\'')
212 n++;
213 if (unsafe)
214 continue;
215 if (isascii(*p)) {
216 if (isalnum(*p))
217 continue;
218 switch (*p) {
219 case '%': case '+': case ',': case '-': case '.':
220 case '/': case ':': case '=': case '@': case '_':
221 continue;
224 unsafe = 1;
226 if (!unsafe)
227 t = strdup(str);
228 #define SQT "'\\''"
229 else if ((p = t = malloc(i + n * (sizeof(SQT) - 2) + 3)) != NULL) {
230 *p++ = '\'';
231 for (; *str != '\0'; str++) {
232 if (*str == '\'') {
233 (void)memcpy(p, SQT, sizeof(SQT) - 1);
234 p += sizeof(SQT) - 1;
235 } else
236 *p++ = *str;
238 *p++ = '\'';
239 *p = '\0';
241 return t;
245 * v_strdup --
246 * Strdup for 8-bit character strings with an associated length.
248 * PUBLIC: char *v_strdup(SCR *, const char *, size_t);
250 char *
251 v_strdup(
252 SCR *sp,
253 const char *str,
254 size_t len)
256 char *copy;
258 MALLOC(sp, copy, char *, len + 1);
259 if (copy == NULL)
260 return (NULL);
261 memcpy(copy, str, len);
262 copy[len] = '\0';
263 return (copy);
267 * v_wstrdup --
268 * Strdup for wide character strings with an associated length.
270 * PUBLIC: CHAR_T *v_wstrdup(SCR *, const CHAR_T *, size_t);
272 CHAR_T *
273 v_wstrdup(SCR *sp,
274 const CHAR_T *str,
275 size_t len)
277 CHAR_T *copy;
279 MALLOC(sp, copy, CHAR_T *, (len + 1) * sizeof(CHAR_T));
280 if (copy == NULL)
281 return (NULL);
282 MEMCPY(copy, str, len);
283 copy[len] = '\0';
284 return (copy);
288 * nget_uslong --
289 * Get an unsigned long, checking for overflow.
291 * PUBLIC: enum nresult nget_uslong(u_long *, const CHAR_T *, CHAR_T **, int);
293 enum nresult
294 nget_uslong(
295 u_long *valp,
296 const CHAR_T *p,
297 CHAR_T **endp,
298 int base)
300 errno = 0;
301 *valp = STRTOUL(p, endp, base);
302 if (errno == 0)
303 return (NUM_OK);
304 if (errno == ERANGE && *valp == ULONG_MAX)
305 return (NUM_OVER);
306 return (NUM_ERR);
310 * nget_slong --
311 * Convert a signed long, checking for overflow and underflow.
313 * PUBLIC: enum nresult nget_slong(long *, const CHAR_T *, CHAR_T **, int);
315 enum nresult
316 nget_slong(
317 long *valp,
318 const CHAR_T *p,
319 CHAR_T **endp,
320 int base)
322 errno = 0;
323 *valp = STRTOL(p, endp, base);
324 if (errno == 0)
325 return (NUM_OK);
326 if (errno == ERANGE) {
327 if (*valp == LONG_MAX)
328 return (NUM_OVER);
329 if (*valp == LONG_MIN)
330 return (NUM_UNDER);
332 return (NUM_ERR);
336 * timepoint_steady --
337 * Get a timestamp from a monotonic clock.
339 * PUBLIC: void timepoint_steady(struct timespec *);
341 void
342 timepoint_steady(
343 struct timespec *ts)
345 #ifdef __APPLE__
346 static mach_timebase_info_data_t base = { 0 };
347 uint64_t val;
348 uint64_t ns;
350 if (base.denom == 0)
351 (void)mach_timebase_info(&base);
353 val = mach_absolute_time();
354 ns = val * base.numer / base.denom;
355 ts->tv_sec = ns / 1000000000;
356 ts->tv_nsec = ns % 1000000000;
357 #else
358 #ifdef CLOCK_MONOTONIC_FAST
359 (void)clock_gettime(CLOCK_MONOTONIC_FAST, ts);
360 #else
361 (void)clock_gettime(CLOCK_MONOTONIC, ts);
362 #endif
363 #endif
367 * timepoint_system --
368 * Get the current calendar time.
370 * PUBLIC: void timepoint_system(struct timespec *);
372 void
373 timepoint_system(
374 struct timespec *ts)
376 #ifdef __APPLE__
377 clock_serv_t clk;
378 mach_timespec_t mts;
379 kern_return_t kr;
381 kr = host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &clk);
382 if (kr != KERN_SUCCESS)
383 return;
384 (void)clock_get_time(clk, &mts);
385 (void)mach_port_deallocate(mach_task_self(), clk);
386 ts->tv_sec = mts.tv_sec;
387 ts->tv_nsec = mts.tv_nsec;
388 #else
389 #ifdef CLOCK_REALTIME_FAST
390 (void)clock_gettime(CLOCK_REALTIME_FAST, ts);
391 #else
392 (void)clock_gettime(CLOCK_REALTIME, ts);
393 #endif
394 #endif
397 #ifdef DEBUG
398 #include <stdarg.h>
401 * TRACE --
402 * debugging trace routine.
404 * PUBLIC: void TRACE(SCR *, const char *, ...);
406 void
407 TRACE(
408 SCR *sp,
409 const char *fmt,
410 ...)
412 FILE *tfp;
413 va_list ap;
415 if ((tfp = sp->gp->tracefp) == NULL)
416 return;
417 va_start(ap, fmt);
418 (void)vfprintf(tfp, fmt, ap);
419 va_end(ap);
421 (void)fflush(tfp);
423 #endif