]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/nvi/common/util.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / nvi / common / util.c
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 #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 */
15
16 #include <sys/types.h>
17 #include <sys/queue.h>
18
19 #ifdef __APPLE__
20 #include <mach/clock.h>
21 #include <mach/mach.h>
22 #include <mach/mach_time.h>
23 #endif
24
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>
35
36 #include "common.h"
37
38 /*
39  * binc --
40  *      Increase the size of a buffer.
41  *
42  * PUBLIC: void *binc __P((SCR *, void *, size_t *, size_t));
43  */
44 void *
45 binc(
46         SCR *sp,                        /* sp MAY BE NULL!!! */
47         void *bp,
48         size_t *bsizep,
49         size_t min)
50 {
51         size_t csize;
52
53         /* If already larger than the minimum, just return. */
54         if (min && *bsizep >= min)
55                 return (bp);
56
57         csize = p2roundup(MAX(min, 256));
58         REALLOC(sp, bp, void *, csize);
59
60         if (bp == NULL) {
61                 *bsizep = 0;
62                 return (NULL);
63         }
64         /*
65          * Memory is guaranteed to be zero-filled, various parts of
66          * nvi depend on this.
67          */
68         memset((char *)bp + *bsizep, 0, csize - *bsizep);
69         *bsizep = csize;
70         return (bp);
71 }
72
73 /*
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.
78  *
79  * PUBLIC: int nonblank __P((SCR *, recno_t, size_t *));
80  */
81 int
82 nonblank(
83         SCR *sp,
84         recno_t lno,
85         size_t *cnop)
86 {
87         CHAR_T *p;
88         size_t cnt, len, off;
89         int isempty;
90
91         /* Default. */
92         off = *cnop;
93         *cnop = 0;
94
95         /* Get the line, succeeding in an empty file. */
96         if (db_eget(sp, lno, &p, &len, &isempty))
97                 return (!isempty);
98
99         /* Set the offset. */
100         if (len == 0 || off >= len)
101                 return (0);
102
103         for (cnt = off, p = &p[off],
104             len -= off; len && ISBLANK(*p); ++cnt, ++p, --len);
105
106         /* Set the return. */
107         *cnop = len ? cnt : cnt - 1;
108         return (0);
109 }
110
111 /*
112  * tail --
113  *      Return tail of a path.
114  *
115  * PUBLIC: char *tail __P((char *));
116  */
117 char *
118 tail(char *path)
119 {
120         char *p;
121
122         if ((p = strrchr(path, '/')) == NULL)
123                 return (path);
124         return (p + 1);
125 }
126
127 /*
128  * join --
129  *      Join two paths; need free.
130  *
131  * PUBLIC: char *join __P((char *, char *));
132  */
133 char *
134 join(
135     char *path1,
136     char *path2)
137 {
138         char *p;
139
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;
145 }
146
147 /*
148  * expanduser --
149  *      Return a "~" or "~user" expanded path; need free.
150  *
151  * PUBLIC: char *expanduser __P((char *));
152  */
153 char *
154 expanduser(char *str)
155 {
156         struct passwd *pwd;
157         char *p, *t, *u, *h;
158
159         /*
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.
163          */
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);
179                 }
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);
190         }
191
192         for (; *t == '/' && *t != '\0'; ++t)
193                 continue;
194         return (join(h, t));
195 }
196
197 /*
198  * quote --
199  *      Return a escaped string for /bin/sh; need free.
200  *
201  * PUBLIC: char *quote __P((char *));
202  */
203 char *
204 quote(char *str)
205 {
206         char *p, *t;
207         size_t i = 0, n = 0;
208         int unsafe = 0;
209
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;
222                         }
223                 }
224                 unsafe = 1;
225         }
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;
237                 }
238                 *p++ = '\'';
239                 *p = '\0';
240         }
241         return t;
242 }
243
244 /*
245  * v_strdup --
246  *      Strdup for 8-bit character strings with an associated length.
247  *
248  * PUBLIC: char *v_strdup __P((SCR *, const char *, size_t));
249  */
250 char *
251 v_strdup(
252         SCR *sp,
253         const char *str,
254         size_t len)
255 {
256         char *copy;
257
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);
264 }
265
266 /*
267  * v_wstrdup --
268  *      Strdup for wide character strings with an associated length.
269  *
270  * PUBLIC: CHAR_T *v_wstrdup __P((SCR *, const CHAR_T *, size_t));
271  */
272 CHAR_T *
273 v_wstrdup(SCR *sp,
274         const CHAR_T *str,
275         size_t len)
276 {
277         CHAR_T *copy;
278
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);
285 }
286
287 /*
288  * nget_uslong --
289  *      Get an unsigned long, checking for overflow.
290  *
291  * PUBLIC: enum nresult nget_uslong __P((u_long *, const CHAR_T *, CHAR_T **, int));
292  */
293 enum nresult
294 nget_uslong(
295         u_long *valp,
296         const CHAR_T *p,
297         CHAR_T **endp,
298         int base)
299 {
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);
307 }
308
309 /*
310  * nget_slong --
311  *      Convert a signed long, checking for overflow and underflow.
312  *
313  * PUBLIC: enum nresult nget_slong __P((long *, const CHAR_T *, CHAR_T **, int));
314  */
315 enum nresult
316 nget_slong(
317         long *valp,
318         const CHAR_T *p,
319         CHAR_T **endp,
320         int base)
321 {
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);
331         }
332         return (NUM_ERR);
333 }
334
335 /*
336  * timepoint_steady --
337  *      Get a timestamp from a monotonic clock.
338  *
339  * PUBLIC: void timepoint_steady __P((struct timespec *));
340  */
341 void
342 timepoint_steady(
343         struct timespec *ts)
344 {
345 #ifdef __APPLE__
346         static mach_timebase_info_data_t base = { 0 };
347         uint64_t val;
348         uint64_t ns;
349
350         if (base.denom == 0)
351                 (void)mach_timebase_info(&base);
352
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
364 }
365
366 /*
367  * timepoint_system --
368  *      Get the current calendar time.
369  *
370  * PUBLIC: void timepoint_system __P((struct timespec *));
371  */
372 void
373 timepoint_system(
374         struct timespec *ts)
375 {
376 #ifdef __APPLE__
377         clock_serv_t clk;
378         mach_timespec_t mts;
379         kern_return_t kr;
380
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
395 }
396
397 #ifdef DEBUG
398 #include <stdarg.h>
399
400 /*
401  * TRACE --
402  *      debugging trace routine.
403  *
404  * PUBLIC: void TRACE __P((SCR *, const char *, ...));
405  */
406 void
407 TRACE(
408         SCR *sp,
409         const char *fmt,
410         ...)
411 {
412         FILE *tfp;
413         va_list ap;
414
415         if ((tfp = sp->gp->tracefp) == NULL)
416                 return;
417         va_start(ap, fmt);
418         (void)vfprintf(tfp, fmt, ap);
419         va_end(ap);
420
421         (void)fflush(tfp);
422 }
423 #endif