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 424