examples

Toy examples in single C files.
git clone git://henryandlizzy.uk/examples
Log | Files | Refs

enviro.c (2353B)


      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <unistd.h>
      4 #include <string.h>
      5 #include <regex.h>
      6 #include <fcntl.h>
      7 #include <sys/stat.h>
      8 
      9 #define ARRAY_SIZE(a)	(sizeof(a) / sizeof(*(a)))
     10 
     11 __attribute__((noreturn))
     12 void die(char const* msg)
     13 {
     14 	fprintf(stderr, "enviro: %s\n", msg);
     15 	exit(1);
     16 }
     17 
     18 __attribute__((noreturn))
     19 void errorno_die(char const* msg)
     20 {
     21 	perror(msg);
     22 	exit(1);
     23 }
     24 
     25 __attribute__((noreturn))
     26 void regex_die(int e, regex_t const* r, char const* msg)
     27 {
     28 	size_t size = regerror(e, r, NULL, 0);
     29 	char* buf = malloc(size);
     30 
     31 	regerror(e, r, buf, size);
     32 	fprintf(stderr, "%s: %s\n", msg, buf);
     33 	exit(1);
     34 }
     35 
     36 int regexec_or_die(const regex_t *restrict preg, const char *restrict string, size_t nmatch, regmatch_t pmatch[restrict], int eflags)
     37 {
     38 	int e = regexec(preg, string, nmatch, pmatch, eflags);
     39 	switch (e)
     40 	{
     41 	case REG_NOMATCH:
     42 	case 0:
     43 		return e;
     44 
     45 	default:
     46 		regex_die(e, preg, "regexec");
     47 	}
     48 }
     49 
     50 char const usage[] =
     51 	"USAGE:\n"
     52 	"\tenviro (file | -) command [args...]\n"
     53 	"\nSUMMARY:\n"
     54 	"\tRun command with the environment from a file or stdin\n";
     55 
     56 char const* regexes[] =
     57 {
     58 	"^[[:blank:]]*(#.*)?\n$",
     59 	"^[[:blank:]]*([[:alnum:]_.,]+=.*)\n$",
     60 };
     61 
     62 regex_t r[ARRAY_SIZE(regexes)];
     63 
     64 int main(int argc, char* argv[])
     65 {
     66 	FILE* f = stdin;
     67 
     68 	for (unsigned i = 0; i < ARRAY_SIZE(r); ++i)
     69 	{
     70 		int e = regcomp(r + i, regexes[i], REG_EXTENDED | REG_NEWLINE);
     71 		if (e)
     72 			regex_die(e, r + i, "regcomp");
     73 	}
     74 
     75 	if (argc < 3)
     76 	{
     77 		fputs(usage, stderr);
     78 		return 1;
     79 	}
     80 
     81 	if (strcmp("-", argv[1]))
     82 	{
     83 		struct stat s;
     84 		int fd = open(argv[1], O_RDONLY);
     85 		
     86 		if (fd < 0)
     87 			errorno_die("open");
     88 
     89 		if (fstat(fd, &s))
     90 			errorno_die("fstat");
     91 
     92 		if ((s.st_mode & S_IFMT) == S_IFDIR)
     93 		{
     94 			fprintf(stderr, "enviro: '%s' is a directory\n", argv[1]);
     95 			exit(1);
     96 		}
     97 
     98 		f = fdopen(fd, "r");
     99 		if (!f)
    100 			errorno_die("fdopen");
    101 	}
    102 
    103 	clearenv();
    104 
    105 	for (;;)
    106 	{
    107 		char* line = NULL;
    108 		size_t size = 0;
    109 		regmatch_t m[2];
    110 
    111 		if (getline(&line, &size, f) == -1)
    112 			break;
    113 
    114 		if (!regexec_or_die(&r[0], line, 0, NULL, 0))
    115 			continue;
    116 
    117 		if (regexec_or_die(r+1, line, ARRAY_SIZE(m), m, 0))
    118 		{
    119 			fprintf(stderr, "enviro: bad format: %s\n", line);
    120 			return 1;
    121 		}
    122 
    123 		if (m[1].rm_so == -1)
    124 			die("bad match");
    125 
    126 		line[m[1].rm_eo] = '\0';
    127 
    128 		if (putenv(line + m[1].rm_so))
    129 			errorno_die("putenv");
    130 	}
    131 
    132 	execvp(argv[2], argv + 2);
    133 	errorno_die("execvp");
    134 }