rohrpost

A commandline mail client to change the world as we see it.
git clone git://r-36.net/rohrpost
Log | Files | Refs | README | LICENSE

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