ind.c (8246B)
1 /* 2 * Copy me if you can. 3 * by 20h 4 */ 5 6 #include <unistd.h> 7 #include <stdio.h> 8 #include <stdlib.h> 9 #include <stdarg.h> 10 #include <fcntl.h> 11 #include <string.h> 12 #include <strings.h> 13 #include <errno.h> 14 #include <ctype.h> 15 #include <sys/types.h> 16 #include <sys/stat.h> 17 #include <time.h> 18 #include <limits.h> 19 20 #include "ind.h" 21 22 void 23 edie(char *fmt, ...) 24 { 25 va_list fmtargs; 26 27 va_start(fmtargs, fmt); 28 vfprintf(stderr, fmt, fmtargs); 29 va_end(fmtargs); 30 fprintf(stderr, ": "); 31 32 perror(NULL); 33 34 exit(1); 35 } 36 37 void 38 die(char *fmt, ...) 39 { 40 va_list fmtargs; 41 42 va_start(fmtargs, fmt); 43 vfprintf(stderr, fmt, fmtargs); 44 va_end(fmtargs); 45 46 exit(1); 47 } 48 49 void * 50 reallocz(void *p, int l, int z) 51 { 52 p = realloc(p, l); 53 if(p == NULL) 54 edie("realloc"); 55 if(z) 56 memset(p, 0, l); 57 58 return p; 59 } 60 61 void * 62 mallocz(int l, int z) 63 { 64 return reallocz(NULL, l, z); 65 } 66 67 void * 68 memdup(void *p, int l) 69 { 70 char *ret; 71 72 ret = reallocz(NULL, l, 2); 73 memmove(ret, p, l); 74 75 return (void *)ret; 76 } 77 78 void * 79 memdupz(void *p, int l) 80 { 81 char *ret; 82 83 ret = reallocz(NULL, l+1, 2); 84 memmove(ret, p, l); 85 86 return (void *)ret; 87 } 88 89 void * 90 memdups(void *p) 91 { 92 char *ret; 93 int l; 94 95 l = strlen(p) + 1; 96 97 ret = reallocz(NULL, l, 2); 98 memmove(ret, p, l); 99 100 return (void *)ret; 101 } 102 103 /* 104 * Append the data at c with the length of lc to 105 * p, at position lp of p. 106 */ 107 void * 108 memdupcat(void *p, int lp, void *c, int lc) 109 { 110 p = reallocz(p, lp+lc, 0); 111 memset(&((char *)p)[lp], 0, lc); 112 113 memmove(&((char *)p)[lp], c, lc); 114 115 return p; 116 } 117 118 char * 119 vsmprintf(char *fmt, va_list fmtargs, int size) 120 { 121 char *ret; 122 123 ret = reallocz(NULL, ++size, 2); 124 vsnprintf(ret, size, fmt, fmtargs); 125 126 return ret; 127 } 128 129 char * 130 smprintf(char *fmt, ...) 131 { 132 va_list fmtargs; 133 char *ret; 134 int len; 135 136 va_start(fmtargs, fmt); 137 len = vsnprintf(NULL, 0, fmt, fmtargs); 138 va_end(fmtargs); 139 140 if (len == INT_MAX) 141 return NULL; 142 143 va_start(fmtargs, fmt); 144 ret = vsmprintf(fmt, fmtargs, len); 145 va_end(fmtargs); 146 147 return ret; 148 } 149 150 void 151 setnonblocking(int fd) 152 { 153 int opts; 154 155 opts = fcntl(fd, F_GETFL); 156 if(opts < 0) 157 edie("setnonblocking"); 158 159 if(fcntl(fd, F_SETFL, opts | O_NONBLOCK) < 0) 160 edie("setnonblocking"); 161 } 162 163 void 164 setblocking(int fd) 165 { 166 int opts; 167 168 opts = fcntl(fd, F_GETFL); 169 if(opts < 0) 170 edie("setblocking"); 171 172 if(fcntl(fd, F_SETFL, opts & ~O_NONBLOCK) < 0) 173 edie("setblocking"); 174 } 175 176 int 177 runcmd(char *cmd, int *infd, int *outfd, int *errfd, int keepold) 178 { 179 int pid, nullfd, status; 180 int pstdin[2], pstdout[2], pstderr[2]; 181 182 enum { 183 DOSTDOUT = 0x01, 184 DOSTDIN = 0x02, 185 DOSTDERR = 0x04, 186 HAVENULLFD = 0x08 187 }; 188 189 status = 0; 190 191 if (infd) { 192 if (pipe(pstdin)) 193 goto runcmderror; 194 status |= DOSTDOUT; 195 } 196 if (outfd) { 197 if (pipe(pstdout)) 198 goto runcmderror; 199 status |= DOSTDIN; 200 } 201 if (errfd) { 202 if (pipe(pstderr)) 203 goto runcmderror; 204 status |= DOSTDERR; 205 } 206 if (!keepold && ((status & DOSTDIN) || (status & DOSTDOUT) 207 || (status & DOSTDERR))) { 208 nullfd = open("/dev/null", O_RDWR); 209 if (nullfd < 0) 210 goto runcmderror; 211 status |= HAVENULLFD; 212 } 213 214 pid = fork(); 215 switch(pid) { 216 case -1: 217 return pid; 218 case 0: 219 if (status & DOSTDIN) { 220 close(pstdin[1]); 221 dup2(pstdin[0], 0); 222 } else { 223 if (!keepold) 224 dup2(nullfd, 0); 225 } 226 if (status & DOSTDOUT) { 227 close(pstdout[0]); 228 dup2(pstdout[1], 1); 229 } else { 230 if (!keepold) 231 dup2(nullfd, 1); 232 } 233 if (status & DOSTDERR) { 234 close(pstderr[1]); 235 dup2(pstderr[0], 2); 236 } else { 237 if (!keepold) 238 dup2(nullfd, 2); 239 } 240 241 execl("/bin/sh", "sh", "-c", cmd, NULL); 242 exit(1); 243 default: 244 break; 245 } 246 247 if (status & DOSTDIN) { 248 close(pstdin[0]); 249 *infd = pstdin[1]; 250 } 251 if (status & DOSTDOUT) { 252 close(pstdout[1]); 253 *outfd = pstdout[0]; 254 } 255 if (status & DOSTDERR) { 256 close(pstderr[1]); 257 *errfd = pstderr[1]; 258 } 259 260 return pid; 261 runcmderror: 262 if (status & DOSTDIN) { 263 close(pstdin[0]); 264 close(pstdin[1]); 265 } 266 if (status & DOSTDOUT) { 267 close(pstdout[0]); 268 close(pstdout[1]); 269 } 270 if (status & DOSTDERR) { 271 close(pstderr[0]); 272 close(pstderr[1]); 273 } 274 if (status & HAVENULLFD) 275 close(nullfd); 276 277 return -1; 278 } 279 280 char * 281 expandhome(char *path) 282 { 283 char *home, *retpath; 284 285 retpath = NULL; 286 287 if (path[0] == '~') { 288 home = getenv("HOME"); 289 if (home != NULL) 290 retpath = smprintf("%s%s", home, path+1); 291 } 292 if (retpath == NULL) 293 retpath = memdups(path); 294 295 return retpath; 296 } 297 298 int 299 writeall(FILE *fd, void *data, int len) 300 { 301 int written; 302 303 for (written = 0; len > 0; ) { 304 written = fwrite(data, 1, len, fd); 305 len -= written; 306 } 307 308 return 0; 309 } 310 311 int 312 writeallfd(int fd, void *data, int len) 313 { 314 int written; 315 316 for (written = 0; len > 0; ) { 317 written = write(fd, &((char *)data)[written], len); 318 len -= written; 319 } 320 321 return 0; 322 } 323 324 int 325 writefile(char *file, void *data, int len, char *mode) 326 { 327 FILE *fd; 328 329 fd = fopen(file, mode); 330 if (fd == NULL) 331 return 1; 332 if (writeall(fd, data, len)) 333 return 1; 334 fclose(fd); 335 336 return 0; 337 } 338 339 int 340 getfilesize(char *file) 341 { 342 struct stat fs; 343 344 if (stat(file, &fs) < 0) 345 return -1; 346 347 return fs.st_size; 348 } 349 350 char * 351 readtoeof(FILE *fd, int *len) 352 { 353 char *ret, buf[4096]; 354 int olen, nlen, rl; 355 356 for (nlen = 0, olen = 0, ret = NULL; !feof(fd); olen = nlen) { 357 rl = fread(buf, 1, sizeof(buf), fd); 358 if (rl > 0) { 359 nlen += rl; 360 ret = reallocz(ret, nlen+1, 0); 361 ret[nlen] = '\0'; 362 363 memmove(&ret[olen], buf, rl); 364 } 365 } 366 367 *len = nlen; 368 return ret; 369 } 370 371 char * 372 readtoeoffd(int fd, int *len) 373 { 374 char *ret, buf[4096]; 375 int olen, nlen, rl; 376 377 for (nlen = 0, olen = 0, ret = NULL; 378 (rl = read(fd, buf, sizeof(buf))); olen = nlen) { 379 if (rl > 0) { 380 nlen += rl; 381 ret = reallocz(ret, nlen+1, 0); 382 ret[nlen] = '\0'; 383 384 memmove(&ret[olen], buf, rl); 385 } 386 } 387 388 *len = nlen; 389 return ret; 390 } 391 392 char * 393 readfile(char *file, int *len) 394 { 395 FILE *fd; 396 char *data; 397 398 fd = fopen(file, "r"); 399 if (fd == NULL) 400 return NULL; 401 402 data = readtoeof(fd, len); 403 fclose(fd); 404 405 return data; 406 } 407 408 char * 409 readstdin(int *len) 410 { 411 return readtoeof(stdin, len); 412 } 413 414 /* 415 * Get line from string buffer. 416 */ 417 char * 418 sgets(char *s, int size, char **p) 419 { 420 char *np; 421 int cl; 422 423 if (*p == NULL) 424 return NULL; 425 426 np = strchr(*p, '\n'); 427 if (np == NULL) { 428 cl = strlen(*p); 429 if (cl < 1) { 430 *p = NULL; 431 return NULL; 432 } 433 } else { 434 cl = np - *p; 435 } 436 437 if (cl >= size) 438 cl = size - 1; 439 memmove(s, *p, cl); 440 s[cl] = '\0'; 441 442 if (np == NULL) { 443 *p = NULL; 444 } else { 445 *p = np+1; 446 } 447 448 return s; 449 } 450 451 char * 452 sgetuntil(char *str, char **p, char *max, int *len) 453 { 454 char *ret, *op; 455 int si; 456 457 ret = NULL; 458 459 si = 0; 460 for (op = *p; op < max; op++) { 461 if (str[si] == '\0') 462 break; 463 if (op[0] == str[si]) { 464 si++; 465 } else { 466 si = 0; 467 } 468 } 469 if (str[si] == '\0') { 470 *len = op - *p - strlen(str); 471 ret = memdupz(*p, *len); 472 *p = op; 473 } 474 475 return ret; 476 } 477 478 char * 479 strrlnspn(char *p, char *chars, int limit) 480 { 481 char *np; 482 483 np = &p[limit-1]; 484 for(; !strchr(chars, np[0] && p != np); np--); 485 486 return np; 487 } 488 489 int 490 strisascii(char *str) 491 { 492 int len, i; 493 494 len = strlen(str); 495 for (i = 0; i < len; i++) { 496 if (!isascii(str[i])) 497 return 0; 498 } 499 500 return 1; 501 } 502 503 void 504 strnormalizespace(char *str) 505 { 506 int len, i; 507 508 len = strlen(str); 509 for (i = 0; i < len; i++) { 510 if (isspace(str[i])) 511 str[i] = ' '; 512 } 513 } 514 515 /* 516 * Find a whitespace character in a certain limit. This is used for formatting 517 * mail to a certain width. 518 */ 519 char * 520 findlimitws(char *str, int limit) 521 { 522 int len; 523 char *ptr; 524 525 len = strlen(str); 526 if (len < limit) 527 return NULL; 528 529 ptr = strrlnspn(str, "\t\r\v\f ", limit); 530 if (ptr == str) 531 return &str[limit-1]; 532 return ptr; 533 } 534 535 char * 536 mktmpfile(char *prefix, char *suffix, int *fd) 537 { 538 char *name; 539 time_t tm; 540 int tfd; 541 542 tm = time(NULL); 543 srand(tm); 544 545 for (tfd = -1; tfd < 0;) { 546 name = smprintf("/tmp/%s.%d.%d.%s", prefix, getpid(), rand(), 547 suffix); 548 tfd = open(name, O_EXCL|O_CREAT|O_RDWR|O_TRUNC, 549 S_IRUSR|S_IWUSR); 550 if (tfd >= 0) 551 break; 552 if (tfd < 0 && errno != EEXIST) 553 edie("mktmpfile"); 554 free(name); 555 } 556 557 *fd = tfd; 558 559 return name; 560 } 561 562 int 563 intcmp(const void *p1, const void *p2) 564 { 565 return *((int *)p1) - *((int *)p2); 566 } 567 568 char * 569 smftime(char *fmt, const struct tm *tm) 570 { 571 int len, rlen; 572 char *ret; 573 574 len = strlen(fmt); 575 ret = NULL; 576 for (; len < 1024;) { 577 len *= 2; 578 ret = reallocz(ret, len, 0); 579 rlen = strftime(ret, len, fmt, tm); 580 if (rlen == 0) 581 continue; 582 } 583 584 return ret; 585 } 586