1b8ba871bSPeter Wemm /*- 2b8ba871bSPeter Wemm * Copyright (c) 1991, 1993, 1994 3b8ba871bSPeter Wemm * The Regents of the University of California. All rights reserved. 4b8ba871bSPeter Wemm * Copyright (c) 1991, 1993, 1994, 1995, 1996 5b8ba871bSPeter Wemm * Keith Bostic. All rights reserved. 6b8ba871bSPeter Wemm * 7b8ba871bSPeter Wemm * See the LICENSE file for redistribution information. 8b8ba871bSPeter Wemm */ 9b8ba871bSPeter Wemm 10b8ba871bSPeter Wemm #include "config.h" 11b8ba871bSPeter Wemm 12b8ba871bSPeter Wemm #include <sys/types.h> 13b8ba871bSPeter Wemm #include <sys/queue.h> 14b8ba871bSPeter Wemm 15f0957ccaSPeter Wemm #ifdef __APPLE__ 16f0957ccaSPeter Wemm #include <mach/clock.h> 17f0957ccaSPeter Wemm #include <mach/mach.h> 18f0957ccaSPeter Wemm #include <mach/mach_time.h> 19f0957ccaSPeter Wemm #endif 20f0957ccaSPeter Wemm 21b8ba871bSPeter Wemm #include <bitstring.h> 22f0957ccaSPeter Wemm #include <ctype.h> 23b8ba871bSPeter Wemm #include <errno.h> 24b8ba871bSPeter Wemm #include <limits.h> 25f0957ccaSPeter Wemm #include <pwd.h> 26b8ba871bSPeter Wemm #include <stdio.h> 27b8ba871bSPeter Wemm #include <stdlib.h> 28b8ba871bSPeter Wemm #include <string.h> 29f0957ccaSPeter Wemm #include <time.h> 30b8ba871bSPeter Wemm #include <unistd.h> 31b8ba871bSPeter Wemm 32b8ba871bSPeter Wemm #include "common.h" 33b8ba871bSPeter Wemm 34b8ba871bSPeter Wemm /* 35b8ba871bSPeter Wemm * binc -- 36b8ba871bSPeter Wemm * Increase the size of a buffer. 37b8ba871bSPeter Wemm * 38c271fa92SBaptiste Daroussin * PUBLIC: void *binc(SCR *, void *, size_t *, size_t); 39b8ba871bSPeter Wemm */ 40b8ba871bSPeter Wemm void * 41*110d525eSBaptiste Daroussin binc(SCR *sp, /* sp MAY BE NULL!!! */ 42*110d525eSBaptiste Daroussin void *bp, size_t *bsizep, size_t min) 43b8ba871bSPeter Wemm { 44b8ba871bSPeter Wemm size_t csize; 45b8ba871bSPeter Wemm 46b8ba871bSPeter Wemm /* If already larger than the minimum, just return. */ 47b8ba871bSPeter Wemm if (min && *bsizep >= min) 48b8ba871bSPeter Wemm return (bp); 49b8ba871bSPeter Wemm 50f0957ccaSPeter Wemm csize = p2roundup(MAX(min, 256)); 51b8ba871bSPeter Wemm REALLOC(sp, bp, void *, csize); 52b8ba871bSPeter Wemm 53b8ba871bSPeter Wemm if (bp == NULL) { 54b8ba871bSPeter Wemm *bsizep = 0; 55b8ba871bSPeter Wemm return (NULL); 56b8ba871bSPeter Wemm } 57b8ba871bSPeter Wemm /* 58b8ba871bSPeter Wemm * Memory is guaranteed to be zero-filled, various parts of 59b8ba871bSPeter Wemm * nvi depend on this. 60b8ba871bSPeter Wemm */ 61b8ba871bSPeter Wemm memset((char *)bp + *bsizep, 0, csize - *bsizep); 62b8ba871bSPeter Wemm *bsizep = csize; 63b8ba871bSPeter Wemm return (bp); 64b8ba871bSPeter Wemm } 65b8ba871bSPeter Wemm 66b8ba871bSPeter Wemm /* 67b8ba871bSPeter Wemm * nonblank -- 68b8ba871bSPeter Wemm * Set the column number of the first non-blank character 69b8ba871bSPeter Wemm * including or after the starting column. On error, set 70b8ba871bSPeter Wemm * the column to 0, it's safest. 71b8ba871bSPeter Wemm * 72c271fa92SBaptiste Daroussin * PUBLIC: int nonblank(SCR *, recno_t, size_t *); 73b8ba871bSPeter Wemm */ 74b8ba871bSPeter Wemm int 75*110d525eSBaptiste Daroussin nonblank(SCR *sp, recno_t lno, size_t *cnop) 76b8ba871bSPeter Wemm { 77f0957ccaSPeter Wemm CHAR_T *p; 78b8ba871bSPeter Wemm size_t cnt, len, off; 79b8ba871bSPeter Wemm int isempty; 80b8ba871bSPeter Wemm 81b8ba871bSPeter Wemm /* Default. */ 82b8ba871bSPeter Wemm off = *cnop; 83b8ba871bSPeter Wemm *cnop = 0; 84b8ba871bSPeter Wemm 85b8ba871bSPeter Wemm /* Get the line, succeeding in an empty file. */ 86b8ba871bSPeter Wemm if (db_eget(sp, lno, &p, &len, &isempty)) 87b8ba871bSPeter Wemm return (!isempty); 88b8ba871bSPeter Wemm 89b8ba871bSPeter Wemm /* Set the offset. */ 90b8ba871bSPeter Wemm if (len == 0 || off >= len) 91b8ba871bSPeter Wemm return (0); 92b8ba871bSPeter Wemm 93b8ba871bSPeter Wemm for (cnt = off, p = &p[off], 94f0957ccaSPeter Wemm len -= off; len && ISBLANK(*p); ++cnt, ++p, --len); 95b8ba871bSPeter Wemm 96b8ba871bSPeter Wemm /* Set the return. */ 97b8ba871bSPeter Wemm *cnop = len ? cnt : cnt - 1; 98b8ba871bSPeter Wemm return (0); 99b8ba871bSPeter Wemm } 100b8ba871bSPeter Wemm 101b8ba871bSPeter Wemm /* 102f0957ccaSPeter Wemm * join -- 103f0957ccaSPeter Wemm * Join two paths; need free. 104f0957ccaSPeter Wemm * 105c271fa92SBaptiste Daroussin * PUBLIC: char *join(char *, char *); 106f0957ccaSPeter Wemm */ 107f0957ccaSPeter Wemm char * 108*110d525eSBaptiste Daroussin join(char *path1, char *path2) 109f0957ccaSPeter Wemm { 110f0957ccaSPeter Wemm char *p; 111f0957ccaSPeter Wemm 112f0957ccaSPeter Wemm if (path1[0] == '\0' || path2[0] == '/') 113f0957ccaSPeter Wemm return strdup(path2); 114f0957ccaSPeter Wemm (void)asprintf(&p, path1[strlen(path1)-1] == '/' ? 115f0957ccaSPeter Wemm "%s%s" : "%s/%s", path1, path2); 116f0957ccaSPeter Wemm return p; 117f0957ccaSPeter Wemm } 118f0957ccaSPeter Wemm 119f0957ccaSPeter Wemm /* 120f0957ccaSPeter Wemm * expanduser -- 121f0957ccaSPeter Wemm * Return a "~" or "~user" expanded path; need free. 122f0957ccaSPeter Wemm * 123c271fa92SBaptiste Daroussin * PUBLIC: char *expanduser(char *); 124f0957ccaSPeter Wemm */ 125f0957ccaSPeter Wemm char * 126f0957ccaSPeter Wemm expanduser(char *str) 127f0957ccaSPeter Wemm { 128f0957ccaSPeter Wemm struct passwd *pwd; 129f0957ccaSPeter Wemm char *p, *t, *u, *h; 130f0957ccaSPeter Wemm 131f0957ccaSPeter Wemm /* 132f0957ccaSPeter Wemm * This function always expands the content between the 133f0957ccaSPeter Wemm * leading '~' and the first '/' or '\0' from the input. 134f0957ccaSPeter Wemm * Return NULL whenever we fail to do so. 135f0957ccaSPeter Wemm */ 136f0957ccaSPeter Wemm if (*str != '~') 137f0957ccaSPeter Wemm return (NULL); 138f0957ccaSPeter Wemm p = str + 1; 139f0957ccaSPeter Wemm for (t = p; *t != '/' && *t != '\0'; ++t) 140f0957ccaSPeter Wemm continue; 141f0957ccaSPeter Wemm if (t == p) { 142f0957ccaSPeter Wemm /* ~ */ 143f0957ccaSPeter Wemm if (issetugid() != 0 || 144f0957ccaSPeter Wemm (h = getenv("HOME")) == NULL) { 145f0957ccaSPeter Wemm if (((h = getlogin()) != NULL && 146f0957ccaSPeter Wemm (pwd = getpwnam(h)) != NULL) || 147f0957ccaSPeter Wemm (pwd = getpwuid(getuid())) != NULL) 148f0957ccaSPeter Wemm h = pwd->pw_dir; 149f0957ccaSPeter Wemm else 150f0957ccaSPeter Wemm return (NULL); 151f0957ccaSPeter Wemm } 152f0957ccaSPeter Wemm } else { 153f0957ccaSPeter Wemm /* ~user */ 154f0957ccaSPeter Wemm if ((u = strndup(p, t - p)) == NULL) 155f0957ccaSPeter Wemm return (NULL); 156f0957ccaSPeter Wemm if ((pwd = getpwnam(u)) == NULL) { 157f0957ccaSPeter Wemm free(u); 158f0957ccaSPeter Wemm return (NULL); 159f0957ccaSPeter Wemm } else 160f0957ccaSPeter Wemm h = pwd->pw_dir; 161f0957ccaSPeter Wemm free(u); 162f0957ccaSPeter Wemm } 163f0957ccaSPeter Wemm 164f0957ccaSPeter Wemm for (; *t == '/' && *t != '\0'; ++t) 165f0957ccaSPeter Wemm continue; 166f0957ccaSPeter Wemm return (join(h, t)); 167f0957ccaSPeter Wemm } 168f0957ccaSPeter Wemm 169f0957ccaSPeter Wemm /* 170f0957ccaSPeter Wemm * quote -- 171f0957ccaSPeter Wemm * Return a escaped string for /bin/sh; need free. 172f0957ccaSPeter Wemm * 173c271fa92SBaptiste Daroussin * PUBLIC: char *quote(char *); 174f0957ccaSPeter Wemm */ 175f0957ccaSPeter Wemm char * 176f0957ccaSPeter Wemm quote(char *str) 177f0957ccaSPeter Wemm { 178f0957ccaSPeter Wemm char *p, *t; 179f0957ccaSPeter Wemm size_t i = 0, n = 0; 180f0957ccaSPeter Wemm int unsafe = 0; 181f0957ccaSPeter Wemm 182f0957ccaSPeter Wemm for (p = str; *p != '\0'; p++, i++) { 183f0957ccaSPeter Wemm if (*p == '\'') 184f0957ccaSPeter Wemm n++; 185f0957ccaSPeter Wemm if (unsafe) 186f0957ccaSPeter Wemm continue; 187*110d525eSBaptiste Daroussin if (isascii((u_char)*p)) { 188*110d525eSBaptiste Daroussin if (isalnum((u_char)*p)) 189f0957ccaSPeter Wemm continue; 190f0957ccaSPeter Wemm switch (*p) { 191f0957ccaSPeter Wemm case '%': case '+': case ',': case '-': case '.': 192f0957ccaSPeter Wemm case '/': case ':': case '=': case '@': case '_': 193f0957ccaSPeter Wemm continue; 194f0957ccaSPeter Wemm } 195f0957ccaSPeter Wemm } 196f0957ccaSPeter Wemm unsafe = 1; 197f0957ccaSPeter Wemm } 198f0957ccaSPeter Wemm if (!unsafe) 199f0957ccaSPeter Wemm t = strdup(str); 200f0957ccaSPeter Wemm #define SQT "'\\''" 201f0957ccaSPeter Wemm else if ((p = t = malloc(i + n * (sizeof(SQT) - 2) + 3)) != NULL) { 202f0957ccaSPeter Wemm *p++ = '\''; 203f0957ccaSPeter Wemm for (; *str != '\0'; str++) { 204f0957ccaSPeter Wemm if (*str == '\'') { 205f0957ccaSPeter Wemm (void)memcpy(p, SQT, sizeof(SQT) - 1); 206f0957ccaSPeter Wemm p += sizeof(SQT) - 1; 207f0957ccaSPeter Wemm } else 208f0957ccaSPeter Wemm *p++ = *str; 209f0957ccaSPeter Wemm } 210f0957ccaSPeter Wemm *p++ = '\''; 211f0957ccaSPeter Wemm *p = '\0'; 212f0957ccaSPeter Wemm } 213f0957ccaSPeter Wemm return t; 214f0957ccaSPeter Wemm } 215f0957ccaSPeter Wemm 216f0957ccaSPeter Wemm /* 217b8ba871bSPeter Wemm * v_strdup -- 218f0957ccaSPeter Wemm * Strdup for 8-bit character strings with an associated length. 219f0957ccaSPeter Wemm * 220c271fa92SBaptiste Daroussin * PUBLIC: char *v_strdup(SCR *, const char *, size_t); 221f0957ccaSPeter Wemm */ 222f0957ccaSPeter Wemm char * 223*110d525eSBaptiste Daroussin v_strdup(SCR *sp, const char *str, size_t len) 224f0957ccaSPeter Wemm { 225f0957ccaSPeter Wemm char *copy; 226f0957ccaSPeter Wemm 227*110d525eSBaptiste Daroussin MALLOC(sp, copy, len + 1); 228f0957ccaSPeter Wemm if (copy == NULL) 229f0957ccaSPeter Wemm return (NULL); 230f0957ccaSPeter Wemm memcpy(copy, str, len); 231f0957ccaSPeter Wemm copy[len] = '\0'; 232f0957ccaSPeter Wemm return (copy); 233f0957ccaSPeter Wemm } 234f0957ccaSPeter Wemm 235f0957ccaSPeter Wemm /* 236f0957ccaSPeter Wemm * v_wstrdup -- 237b8ba871bSPeter Wemm * Strdup for wide character strings with an associated length. 238b8ba871bSPeter Wemm * 239c271fa92SBaptiste Daroussin * PUBLIC: CHAR_T *v_wstrdup(SCR *, const CHAR_T *, size_t); 240b8ba871bSPeter Wemm */ 241b8ba871bSPeter Wemm CHAR_T * 242*110d525eSBaptiste Daroussin v_wstrdup(SCR *sp, const CHAR_T *str, size_t len) 243b8ba871bSPeter Wemm { 244b8ba871bSPeter Wemm CHAR_T *copy; 245b8ba871bSPeter Wemm 246*110d525eSBaptiste Daroussin MALLOC(sp, copy, (len + 1) * sizeof(CHAR_T)); 247b8ba871bSPeter Wemm if (copy == NULL) 248b8ba871bSPeter Wemm return (NULL); 249f0957ccaSPeter Wemm MEMCPY(copy, str, len); 250b8ba871bSPeter Wemm copy[len] = '\0'; 251b8ba871bSPeter Wemm return (copy); 252b8ba871bSPeter Wemm } 253b8ba871bSPeter Wemm 254b8ba871bSPeter Wemm /* 255b8ba871bSPeter Wemm * nget_uslong -- 256b8ba871bSPeter Wemm * Get an unsigned long, checking for overflow. 257b8ba871bSPeter Wemm * 258c271fa92SBaptiste Daroussin * PUBLIC: enum nresult nget_uslong(u_long *, const CHAR_T *, CHAR_T **, int); 259b8ba871bSPeter Wemm */ 260b8ba871bSPeter Wemm enum nresult 261*110d525eSBaptiste Daroussin nget_uslong(u_long *valp, const CHAR_T *p, CHAR_T **endp, int base) 262b8ba871bSPeter Wemm { 263b8ba871bSPeter Wemm errno = 0; 264f0957ccaSPeter Wemm *valp = STRTOUL(p, endp, base); 265b8ba871bSPeter Wemm if (errno == 0) 266b8ba871bSPeter Wemm return (NUM_OK); 267b8ba871bSPeter Wemm if (errno == ERANGE && *valp == ULONG_MAX) 268b8ba871bSPeter Wemm return (NUM_OVER); 269b8ba871bSPeter Wemm return (NUM_ERR); 270b8ba871bSPeter Wemm } 271b8ba871bSPeter Wemm 272b8ba871bSPeter Wemm /* 273b8ba871bSPeter Wemm * nget_slong -- 274b8ba871bSPeter Wemm * Convert a signed long, checking for overflow and underflow. 275b8ba871bSPeter Wemm * 276c271fa92SBaptiste Daroussin * PUBLIC: enum nresult nget_slong(long *, const CHAR_T *, CHAR_T **, int); 277b8ba871bSPeter Wemm */ 278b8ba871bSPeter Wemm enum nresult 279*110d525eSBaptiste Daroussin nget_slong(long *valp, const CHAR_T *p, CHAR_T **endp, int base) 280b8ba871bSPeter Wemm { 281b8ba871bSPeter Wemm errno = 0; 282f0957ccaSPeter Wemm *valp = STRTOL(p, endp, base); 283b8ba871bSPeter Wemm if (errno == 0) 284b8ba871bSPeter Wemm return (NUM_OK); 285b8ba871bSPeter Wemm if (errno == ERANGE) { 286b8ba871bSPeter Wemm if (*valp == LONG_MAX) 287b8ba871bSPeter Wemm return (NUM_OVER); 288b8ba871bSPeter Wemm if (*valp == LONG_MIN) 289b8ba871bSPeter Wemm return (NUM_UNDER); 290b8ba871bSPeter Wemm } 291b8ba871bSPeter Wemm return (NUM_ERR); 292b8ba871bSPeter Wemm } 293b8ba871bSPeter Wemm 294f0957ccaSPeter Wemm /* 295f0957ccaSPeter Wemm * timepoint_steady -- 296f0957ccaSPeter Wemm * Get a timestamp from a monotonic clock. 297f0957ccaSPeter Wemm * 298c271fa92SBaptiste Daroussin * PUBLIC: void timepoint_steady(struct timespec *); 299f0957ccaSPeter Wemm */ 300f0957ccaSPeter Wemm void 301*110d525eSBaptiste Daroussin timepoint_steady(struct timespec *ts) 302f0957ccaSPeter Wemm { 303f0957ccaSPeter Wemm #ifdef __APPLE__ 304f0957ccaSPeter Wemm static mach_timebase_info_data_t base = { 0 }; 305f0957ccaSPeter Wemm uint64_t val; 306f0957ccaSPeter Wemm uint64_t ns; 307f0957ccaSPeter Wemm 308f0957ccaSPeter Wemm if (base.denom == 0) 309f0957ccaSPeter Wemm (void)mach_timebase_info(&base); 310f0957ccaSPeter Wemm 311f0957ccaSPeter Wemm val = mach_absolute_time(); 312f0957ccaSPeter Wemm ns = val * base.numer / base.denom; 313f0957ccaSPeter Wemm ts->tv_sec = ns / 1000000000; 314f0957ccaSPeter Wemm ts->tv_nsec = ns % 1000000000; 315b8ba871bSPeter Wemm #else 316f0957ccaSPeter Wemm #ifdef CLOCK_MONOTONIC_FAST 317f0957ccaSPeter Wemm (void)clock_gettime(CLOCK_MONOTONIC_FAST, ts); 318f0957ccaSPeter Wemm #else 319f0957ccaSPeter Wemm (void)clock_gettime(CLOCK_MONOTONIC, ts); 320b8ba871bSPeter Wemm #endif 321f0957ccaSPeter Wemm #endif 322f0957ccaSPeter Wemm } 323f0957ccaSPeter Wemm 324f0957ccaSPeter Wemm /* 325f0957ccaSPeter Wemm * timepoint_system -- 326f0957ccaSPeter Wemm * Get the current calendar time. 327f0957ccaSPeter Wemm * 328c271fa92SBaptiste Daroussin * PUBLIC: void timepoint_system(struct timespec *); 329f0957ccaSPeter Wemm */ 330f0957ccaSPeter Wemm void 331*110d525eSBaptiste Daroussin timepoint_system(struct timespec *ts) 332f0957ccaSPeter Wemm { 333f0957ccaSPeter Wemm #ifdef __APPLE__ 334f0957ccaSPeter Wemm clock_serv_t clk; 335f0957ccaSPeter Wemm mach_timespec_t mts; 336f0957ccaSPeter Wemm kern_return_t kr; 337f0957ccaSPeter Wemm 338f0957ccaSPeter Wemm kr = host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &clk); 339f0957ccaSPeter Wemm if (kr != KERN_SUCCESS) 340f0957ccaSPeter Wemm return; 341f0957ccaSPeter Wemm (void)clock_get_time(clk, &mts); 342f0957ccaSPeter Wemm (void)mach_port_deallocate(mach_task_self(), clk); 343f0957ccaSPeter Wemm ts->tv_sec = mts.tv_sec; 344f0957ccaSPeter Wemm ts->tv_nsec = mts.tv_nsec; 345f0957ccaSPeter Wemm #else 346f0957ccaSPeter Wemm #ifdef CLOCK_REALTIME_FAST 347f0957ccaSPeter Wemm (void)clock_gettime(CLOCK_REALTIME_FAST, ts); 348f0957ccaSPeter Wemm #else 349f0957ccaSPeter Wemm (void)clock_gettime(CLOCK_REALTIME, ts); 350f0957ccaSPeter Wemm #endif 351f0957ccaSPeter Wemm #endif 352f0957ccaSPeter Wemm } 353f0957ccaSPeter Wemm 354f0957ccaSPeter Wemm #ifdef DEBUG 355f0957ccaSPeter Wemm #include <stdarg.h> 356b8ba871bSPeter Wemm 357b8ba871bSPeter Wemm /* 358b8ba871bSPeter Wemm * TRACE -- 359b8ba871bSPeter Wemm * debugging trace routine. 360b8ba871bSPeter Wemm * 361c271fa92SBaptiste Daroussin * PUBLIC: void TRACE(SCR *, const char *, ...); 362b8ba871bSPeter Wemm */ 363b8ba871bSPeter Wemm void 364*110d525eSBaptiste Daroussin TRACE(SCR *sp, const char *fmt, ...) 365b8ba871bSPeter Wemm { 366b8ba871bSPeter Wemm FILE *tfp; 367b8ba871bSPeter Wemm va_list ap; 368b8ba871bSPeter Wemm 369b8ba871bSPeter Wemm if ((tfp = sp->gp->tracefp) == NULL) 370b8ba871bSPeter Wemm return; 371b8ba871bSPeter Wemm va_start(ap, fmt); 372b8ba871bSPeter Wemm (void)vfprintf(tfp, fmt, ap); 373b8ba871bSPeter Wemm va_end(ap); 374b8ba871bSPeter Wemm 375b8ba871bSPeter Wemm (void)fflush(tfp); 376b8ba871bSPeter Wemm } 377b8ba871bSPeter Wemm #endif 378