174 lines
3.8 KiB
C
174 lines
3.8 KiB
C
#define _POSIX_C_SOURCE 2 /* popen */
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <libgen.h>
|
|
#include <sys/stat.h>
|
|
#include <time.h>
|
|
|
|
typedef struct {
|
|
char ident[80];
|
|
char value[256]; // TODO: variable size values
|
|
} makro;
|
|
|
|
FILE *IN;
|
|
FILE *OUT;
|
|
size_t makro_num = 0;
|
|
makro makros[10] = {0}; // TODO: remove limitation of max 10 makros per file
|
|
|
|
void
|
|
readn(size_t n, char *buf)
|
|
{
|
|
for (size_t i = 0; i < n; i++)
|
|
buf[i] = fgetc(IN);
|
|
}
|
|
|
|
void
|
|
die(const char *s, ...)
|
|
{
|
|
va_list argp;
|
|
va_start(argp, s);
|
|
vfprintf(stderr, s, argp);
|
|
fputc('\n', stderr);
|
|
va_end(argp);
|
|
exit(1);
|
|
}
|
|
|
|
void
|
|
shell_output(const char *cmd, char *out)
|
|
{
|
|
FILE *shell_out = popen(cmd, "r");
|
|
if (shell_out == NULL)
|
|
die("couldn't execute command: %s", cmd);
|
|
|
|
char lastc = fgetc(shell_out), c;
|
|
size_t i = 0;
|
|
if (lastc != EOF) {
|
|
while ((c = fgetc(shell_out)) != EOF) {
|
|
out[i++] = lastc;
|
|
lastc = c;
|
|
}
|
|
}
|
|
|
|
pclose(shell_out);
|
|
}
|
|
|
|
void
|
|
add_special_makros(const char *filename)
|
|
{
|
|
makro_num = 2;
|
|
|
|
memcpy(makros[0].ident, "FILE_NAME", strlen("FILE_NAME"));
|
|
memcpy(makros[0].value, filename, strlen(filename));
|
|
|
|
memcpy(makros[1].ident, "FILE_LAST_CHANGED", strlen("FILE_LAST_CHANGED"));
|
|
struct stat attrib;
|
|
stat(filename, &attrib);
|
|
char date[20];
|
|
strftime(date, 20, "%Y-%m-%d", localtime(&(attrib.st_ctime)));
|
|
memcpy(makros[1].value, date, strlen(date));
|
|
}
|
|
|
|
void
|
|
define_makro(makro *m, char *lastc)
|
|
{
|
|
char buf[7];
|
|
readn(6, buf);
|
|
buf[6] = '\0';
|
|
if (strcmp(buf, "makro ")) {
|
|
fputc('#', OUT);
|
|
fseek(IN, -6L, SEEK_CUR);
|
|
*lastc = '#';
|
|
return;
|
|
}
|
|
|
|
*lastc = '\n';
|
|
|
|
char *assops = "=@";
|
|
size_t i = 0;
|
|
char c;
|
|
while ((c = fgetc(IN)) && strchr(assops, c) == NULL) {
|
|
m->ident[i++] = c;
|
|
if (c == EOF || c == '\n')
|
|
die("makro definition missing assignment operator");
|
|
}
|
|
i = 0;
|
|
|
|
switch (c) {
|
|
case '=':
|
|
while ((c = fgetc(IN)) != '\n') {
|
|
m->value[i++] = c;
|
|
if (c == EOF)
|
|
die("makro definition missing assignment operator");
|
|
}
|
|
break;
|
|
case '@': {
|
|
char buf[256] = {0};
|
|
while ((c = fgetc(IN)) != '\n') {
|
|
buf[i++] = c;
|
|
if (c == EOF)
|
|
die("makro definition missing assignment operator");
|
|
}
|
|
shell_output(buf, m->value);
|
|
break;
|
|
}
|
|
default:
|
|
die("invalid operator: %c", c);
|
|
}
|
|
}
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
switch (argc) {
|
|
case 1:
|
|
IN = stdin;
|
|
OUT = stdout;
|
|
break;
|
|
case 2:
|
|
IN = fopen(argv[1], "r");
|
|
OUT = stdout;
|
|
break;
|
|
case 3:
|
|
IN = fopen(argv[1], "r");
|
|
OUT = fopen(argv[2], "w");
|
|
break;
|
|
default:
|
|
die("usage: makros [input-file] [output-file]");
|
|
}
|
|
|
|
/* special makros */
|
|
add_special_makros(argv[1] ? argv[1] : "unknown");
|
|
|
|
char lastc = '\n', c;
|
|
while ((c = fgetc(IN)) != EOF) {
|
|
if (c == '#' && lastc == '\n') {
|
|
define_makro(&makros[makro_num++], &lastc);
|
|
if (lastc == '\n')
|
|
continue;
|
|
}
|
|
|
|
int found_makro = 0;
|
|
for (size_t i = 0; i < makro_num; i++) {
|
|
if (c == makros[i].ident[0]) {
|
|
char buf[80] = {0};
|
|
long len = strlen(makros[i].ident)-1;
|
|
readn(len, buf);
|
|
if (!strcmp(buf, makros[i].ident+1)) {
|
|
fprintf(OUT, "%s", makros[i].value);
|
|
found_makro = 1;
|
|
break;
|
|
}
|
|
else {
|
|
fseek(IN, -len, SEEK_CUR);
|
|
}
|
|
}
|
|
}
|
|
if (!found_makro) {
|
|
fputc(c, OUT);
|
|
lastc = c;
|
|
}
|
|
}
|
|
}
|