]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - common/util.c
Import nvi 2.2.0
[FreeBSD/FreeBSD.git] / 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 #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  */
40 void *
41 binc(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  */
74 int
75 nonblank(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  */
107 char *
108 join(char *path1, char *path2)
109 {
110         char *p;
111
112         if (path1[0] == '\0' || path2[0] == '/')
113                 return strdup(path2);
114         (void)asprintf(&p, path1[strlen(path1)-1] == '/' ?
115             "%s%s" : "%s/%s", path1, path2);
116         return p;
117 }
118
119 /*
120  * expanduser --
121  *      Return a "~" or "~user" expanded path; need free.
122  *
123  * PUBLIC: char *expanduser(char *);
124  */
125 char *
126 expanduser(char *str)
127 {
128         struct passwd *pwd;
129         char *p, *t, *u, *h;
130
131         /*
132          * This function always expands the content between the
133          * leading '~' and the first '/' or '\0' from the input.
134          * Return NULL whenever we fail to do so.
135          */
136         if (*str != '~')
137                 return (NULL);
138         p = str + 1;
139         for (t = p; *t != '/' && *t != '\0'; ++t)
140                 continue;
141         if (t == p) {
142                 /* ~ */
143                 if (issetugid() != 0 ||
144                     (h = getenv("HOME")) == NULL) {
145                         if (((h = getlogin()) != NULL &&
146                              (pwd = getpwnam(h)) != NULL) ||
147                             (pwd = getpwuid(getuid())) != NULL)
148                                 h = pwd->pw_dir;
149                         else
150                                 return (NULL);
151                 }
152         } else {
153                 /* ~user */
154                 if ((u = strndup(p, t - p)) == NULL)
155                         return (NULL);
156                 if ((pwd = getpwnam(u)) == NULL) {
157                         free(u);
158                         return (NULL);
159                 } else
160                         h = pwd->pw_dir;
161                 free(u);
162         }
163
164         for (; *t == '/' && *t != '\0'; ++t)
165                 continue;
166         return (join(h, t));
167 }
168
169 /*
170  * quote --
171  *      Return a escaped string for /bin/sh; need free.
172  *
173  * PUBLIC: char *quote(char *);
174  */
175 char *
176 quote(char *str)
177 {
178         char *p, *t;
179         size_t i = 0, n = 0;
180         int unsafe = 0;
181
182         for (p = str; *p != '\0'; p++, i++) {
183                 if (*p == '\'')
184                         n++;
185                 if (unsafe)
186                         continue;
187                 if (isascii((u_char)*p)) {
188                         if (isalnum((u_char)*p))
189                                 continue;
190                         switch (*p) {
191                         case '%': case '+': case ',': case '-': case '.':
192                         case '/': case ':': case '=': case '@': case '_':
193                                 continue;
194                         }
195                 }
196                 unsafe = 1;
197         }
198         if (!unsafe)
199                 t = strdup(str);
200 #define SQT "'\\''"
201         else if ((p = t = malloc(i + n * (sizeof(SQT) - 2) + 3)) != NULL) {
202                 *p++ = '\'';
203                 for (; *str != '\0'; str++) {
204                         if (*str == '\'') {
205                                 (void)memcpy(p, SQT, sizeof(SQT) - 1);
206                                 p += sizeof(SQT) - 1;
207                         } else
208                                 *p++ = *str;
209                 }
210                 *p++ = '\'';
211                 *p = '\0';
212         }
213         return t;
214 }
215
216 /*
217  * v_strdup --
218  *      Strdup for 8-bit character strings with an associated length.
219  *
220  * PUBLIC: char *v_strdup(SCR *, const char *, size_t);
221  */
222 char *
223 v_strdup(SCR *sp, const char *str, size_t len)
224 {
225         char *copy;
226
227         MALLOC(sp, copy, len + 1);
228         if (copy == NULL)
229                 return (NULL);
230         memcpy(copy, str, len);
231         copy[len] = '\0';
232         return (copy);
233 }
234
235 /*
236  * v_wstrdup --
237  *      Strdup for wide character strings with an associated length.
238  *
239  * PUBLIC: CHAR_T *v_wstrdup(SCR *, const CHAR_T *, size_t);
240  */
241 CHAR_T *
242 v_wstrdup(SCR *sp, const CHAR_T *str, size_t len)
243 {
244         CHAR_T *copy;
245
246         MALLOC(sp, copy, (len + 1) * sizeof(CHAR_T));
247         if (copy == NULL)
248                 return (NULL);
249         MEMCPY(copy, str, len);
250         copy[len] = '\0';
251         return (copy);
252 }
253
254 /*
255  * nget_uslong --
256  *      Get an unsigned long, checking for overflow.
257  *
258  * PUBLIC: enum nresult nget_uslong(u_long *, const CHAR_T *, CHAR_T **, int);
259  */
260 enum nresult
261 nget_uslong(u_long *valp, const CHAR_T *p, CHAR_T **endp, int base)
262 {
263         errno = 0;
264         *valp = STRTOUL(p, endp, base);
265         if (errno == 0)
266                 return (NUM_OK);
267         if (errno == ERANGE && *valp == ULONG_MAX)
268                 return (NUM_OVER);
269         return (NUM_ERR);
270 }
271
272 /*
273  * nget_slong --
274  *      Convert a signed long, checking for overflow and underflow.
275  *
276  * PUBLIC: enum nresult nget_slong(long *, const CHAR_T *, CHAR_T **, int);
277  */
278 enum nresult
279 nget_slong(long *valp, const CHAR_T *p, CHAR_T **endp, int base)
280 {
281         errno = 0;
282         *valp = STRTOL(p, endp, base);
283         if (errno == 0)
284                 return (NUM_OK);
285         if (errno == ERANGE) {
286                 if (*valp == LONG_MAX)
287                         return (NUM_OVER);
288                 if (*valp == LONG_MIN)
289                         return (NUM_UNDER);
290         }
291         return (NUM_ERR);
292 }
293
294 /*
295  * timepoint_steady --
296  *      Get a timestamp from a monotonic clock.
297  *
298  * PUBLIC: void timepoint_steady(struct timespec *);
299  */
300 void
301 timepoint_steady(struct timespec *ts)
302 {
303 #ifdef __APPLE__
304         static mach_timebase_info_data_t base = { 0 };
305         uint64_t val;
306         uint64_t ns;
307
308         if (base.denom == 0)
309                 (void)mach_timebase_info(&base);
310
311         val = mach_absolute_time();
312         ns = val * base.numer / base.denom;
313         ts->tv_sec = ns / 1000000000;
314         ts->tv_nsec = ns % 1000000000;
315 #else
316 #ifdef CLOCK_MONOTONIC_FAST
317         (void)clock_gettime(CLOCK_MONOTONIC_FAST, ts);
318 #else
319         (void)clock_gettime(CLOCK_MONOTONIC, ts);
320 #endif
321 #endif
322 }
323
324 /*
325  * timepoint_system --
326  *      Get the current calendar time.
327  *
328  * PUBLIC: void timepoint_system(struct timespec *);
329  */
330 void
331 timepoint_system(struct timespec *ts)
332 {
333 #ifdef __APPLE__
334         clock_serv_t clk;
335         mach_timespec_t mts;
336         kern_return_t kr;
337
338         kr = host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &clk);
339         if (kr != KERN_SUCCESS)
340                 return;
341         (void)clock_get_time(clk, &mts);
342         (void)mach_port_deallocate(mach_task_self(), clk);
343         ts->tv_sec = mts.tv_sec;
344         ts->tv_nsec = mts.tv_nsec;
345 #else
346 #ifdef CLOCK_REALTIME_FAST
347         (void)clock_gettime(CLOCK_REALTIME_FAST, ts);
348 #else
349         (void)clock_gettime(CLOCK_REALTIME, ts);
350 #endif
351 #endif
352 }
353
354 #ifdef DEBUG
355 #include <stdarg.h>
356
357 /*
358  * TRACE --
359  *      debugging trace routine.
360  *
361  * PUBLIC: void TRACE(SCR *, const char *, ...);
362  */
363 void
364 TRACE(SCR *sp, const char *fmt, ...)
365 {
366         FILE *tfp;
367         va_list ap;
368
369         if ((tfp = sp->gp->tracefp) == NULL)
370                 return;
371         va_start(ap, fmt);
372         (void)vfprintf(tfp, fmt, ap);
373         va_end(ap);
374
375         (void)fflush(tfp);
376 }
377 #endif