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 378