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