initial
This commit is contained in:
commit
2992b0e0f9
|
@ -0,0 +1,5 @@
|
|||
CC = clang
|
||||
CFLAGS = -Wall -Wextra -std=c99 -pedantic
|
||||
|
||||
makros: makros.c
|
||||
$(CC) $(CFLAGS) $< -o $@
|
|
@ -0,0 +1,173 @@
|
|||
#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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#makro TEXT=random text
|
||||
makros is a simple macro tool, in a similar vein to the C preprocessor. However,
|
||||
in addition to storing TEXT in macros, it supports storing shell command output
|
||||
in them as well to allow for more flexibility. This readme file is an example of
|
||||
a raw file you can feed into makros. Try compiling the program by running
|
||||
`make' and run the command `./makros readme' to see how it works.
|
||||
|
||||
#makro DATE@date +%s
|
||||
This readme was compiled at DATE.
|
||||
We have some *special* macros available, which give us some file reflection:
|
||||
File last changed FILE_LAST_CHANGED.
|
||||
This file is named FILE_NAME.
|
Loading…
Reference in New Issue