2017-10-25 18:36:17 +02:00
|
|
|
#include <string.h>
|
|
|
|
#include "fs.h"
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include "hashtable.h"
|
|
|
|
|
|
|
|
#define _(x) x
|
|
|
|
|
2017-10-25 20:42:33 +02:00
|
|
|
struct macro {
|
|
|
|
char * name;
|
|
|
|
};
|
|
|
|
|
|
|
|
void *copy_macro(void * macro) {
|
|
|
|
struct macro * temp = (struct macro*)(macro),
|
|
|
|
* new = malloc(sizeof(struct macro));
|
|
|
|
|
|
|
|
new->name = strdup(temp->name);
|
|
|
|
return (void*)(new);
|
|
|
|
}
|
|
|
|
|
|
|
|
void free_macro(void * macro) {
|
|
|
|
struct macro * temp = (struct macro*)(macro);
|
|
|
|
|
|
|
|
free(temp->name);
|
|
|
|
free(temp);
|
|
|
|
}
|
|
|
|
|
2017-10-25 18:36:17 +02:00
|
|
|
|
2017-10-25 20:42:33 +02:00
|
|
|
typedef struct hashtable macrotable_t;
|
|
|
|
|
|
|
|
// init default macros empty
|
|
|
|
macrotable_t default_macros = {};
|
|
|
|
|
|
|
|
void build_default_macros() {
|
|
|
|
// default macros currently implemented:
|
|
|
|
// if
|
|
|
|
// lstinputlisting
|
|
|
|
// include
|
|
|
|
// input
|
|
|
|
// includegraphics
|
|
|
|
// graphicspath
|
|
|
|
hashtable_clear(&default_macros);
|
|
|
|
}
|
|
|
|
|
|
|
|
void macrotable_init(macrotable_t * table) {
|
|
|
|
hashtable_init(table);
|
|
|
|
table->dealloc_data = free_macro;
|
|
|
|
}
|
|
|
|
|
|
|
|
void macrotable_copy(macrotable_t * to, macrotable_t * from) {
|
|
|
|
if (!to || !from) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
hashtable_iterator_t it = hashtable_next(from, NULL);
|
|
|
|
struct entry newEntry;
|
|
|
|
|
|
|
|
for(; it != hashtable_end(from); it = hashtable_next(from, it)) {
|
|
|
|
// insert it into to
|
|
|
|
newEntry = *it;
|
|
|
|
newEntry.data = copy_macro(newEntry.data);
|
|
|
|
|
|
|
|
hashtable_add(to, newEntry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct filelist {
|
|
|
|
struct filelist * next;
|
|
|
|
char * path;
|
|
|
|
struct hashtable * macros;
|
|
|
|
};
|
2017-10-25 18:36:17 +02:00
|
|
|
|
|
|
|
void free_filelist(struct filelist * list) {
|
|
|
|
if (list == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct filelist * next = list->next;
|
|
|
|
|
|
|
|
while(list->next) {
|
|
|
|
next = list->next;
|
|
|
|
free(next->path);
|
|
|
|
free(next);
|
|
|
|
|
|
|
|
list->next = list->next->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(list->path);
|
|
|
|
free(list);
|
|
|
|
}
|
|
|
|
|
|
|
|
int filelist_push(struct filelist * pos, const char * path) {
|
|
|
|
struct filelist * new = malloc(sizeof(struct filelist));
|
|
|
|
if (!new) {
|
|
|
|
errno = ENOMEM;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
new->next = pos->next;
|
|
|
|
new->path = strdup(path);
|
|
|
|
|
|
|
|
pos->next = new;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int good(FILE * file) {
|
|
|
|
return !feof(file);
|
|
|
|
}
|
|
|
|
|
2017-10-25 20:42:33 +02:00
|
|
|
volatile int line = 0, pos = 0;
|
|
|
|
FILE * fopen_count(const char * path, const char * flags) {
|
|
|
|
line = pos = 0;
|
|
|
|
return fopen(path, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
char fgetc_count(FILE *file) {
|
2017-10-25 18:36:17 +02:00
|
|
|
char temp = fgetc(file);
|
|
|
|
if (temp == '\n') {
|
2017-10-25 20:42:33 +02:00
|
|
|
line++;
|
|
|
|
pos = 0;
|
2017-10-25 18:36:17 +02:00
|
|
|
} else {
|
2017-10-25 20:42:33 +02:00
|
|
|
pos++;
|
2017-10-25 18:36:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return temp;
|
|
|
|
}
|
|
|
|
|
|
|
|
int add_char(char ** str, char c) {
|
|
|
|
if (str == NULL || *str == NULL) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int len = strlen(*str);
|
|
|
|
|
|
|
|
char *temp = realloc(*str, len + 1);
|
|
|
|
if (temp == NULL) {
|
|
|
|
errno = ENOMEM;
|
|
|
|
return -1;
|
|
|
|
}
|
2017-10-25 20:42:33 +02:00
|
|
|
|
2017-10-25 18:36:17 +02:00
|
|
|
*str = temp;
|
|
|
|
|
|
|
|
(*str)[len-1] = c;
|
|
|
|
(*str)[len] = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-10-25 20:42:33 +02:00
|
|
|
|
|
|
|
|
2017-10-25 18:36:17 +02:00
|
|
|
void eval_macro(struct filelist * last, FILE * file) {
|
|
|
|
char * name = NULL;
|
|
|
|
strhash_t hash = 0;
|
2017-10-25 20:42:33 +02:00
|
|
|
hashtable_iterator_t macro;
|
2017-10-25 18:36:17 +02:00
|
|
|
|
|
|
|
char current = 0;
|
|
|
|
|
|
|
|
// read macro name
|
2017-10-25 20:42:33 +02:00
|
|
|
while(good(file) && current != '\\' && macro == hashtable_end(last->macros)) {
|
|
|
|
hash = strhash_add(hash, current);
|
|
|
|
// try to find macro in table
|
|
|
|
macro = hashtable_get_hash(last->macros, hash);
|
2017-10-25 18:36:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!good(file)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void eval_file(struct filelist * last) {
|
|
|
|
// open file
|
2017-10-25 20:42:33 +02:00
|
|
|
FILE * file = fopen_count(last->path, "r");
|
2017-10-25 18:36:17 +02:00
|
|
|
|
|
|
|
if (file == NULL) {
|
|
|
|
fprintf(stderr, _("could not open file \"%s\":%s\n"), last->path, strerror(errno));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("processing file: %s\n", last->path);
|
|
|
|
|
|
|
|
char current = 1;
|
|
|
|
while(good(file)) {
|
2017-10-25 20:42:33 +02:00
|
|
|
current = fgetc_count(file);
|
2017-10-25 18:36:17 +02:00
|
|
|
|
|
|
|
switch(current) {
|
|
|
|
case '%':
|
|
|
|
// comment, skip line
|
|
|
|
do {
|
2017-10-25 20:42:33 +02:00
|
|
|
current = fgetc_count(file);
|
2017-10-25 18:36:17 +02:00
|
|
|
} while(good(file) && current != '\n');
|
|
|
|
|
|
|
|
break;
|
|
|
|
case '\\':
|
|
|
|
// macro
|
|
|
|
eval_macro(last, file);
|
|
|
|
break;
|
|
|
|
default:
|
2017-10-25 20:42:33 +02:00
|
|
|
printf(_("%d:%d:unrecognized char! %c\n"), line, pos, current);
|
2017-10-25 18:36:17 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fclose(file);
|
|
|
|
}
|
|
|
|
|
|
|
|
#include <getopt.h>
|
|
|
|
|
|
|
|
struct option long_opts[] = {
|
|
|
|
{"output", required_argument, NULL, 'o'},
|
|
|
|
{"target", required_argument, NULL, 't'},
|
|
|
|
{}, // terminator
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
void help(int argc, char ** args) {
|
|
|
|
printf("%s [OPTIONS] file1 file2...\n"
|
|
|
|
"--output\n"
|
|
|
|
"-o\tby default the program will create a depfile for every input\n"
|
|
|
|
"\tnaming it like the tex file with a .d extension. By giving the -o Option\n"
|
|
|
|
"\tthe output will instead be put in this file exculsivly\n"
|
|
|
|
"--target\n"
|
|
|
|
"-t\tOverride the target name\n", args[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char ** args) {
|
|
|
|
int long_index = 0;
|
|
|
|
int opt = 0;
|
|
|
|
|
|
|
|
const char *outfile, *target;
|
|
|
|
|
|
|
|
while((opt = getopt_long(argc, args, "o:t:", long_opts, &long_index)) != -1) {
|
|
|
|
switch(opt) {
|
|
|
|
case 'o':
|
|
|
|
outfile = optarg;
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
target = optarg;
|
|
|
|
break;
|
|
|
|
case '?':
|
|
|
|
help(argc, args);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
char * current_file = NULL;
|
|
|
|
|
|
|
|
// process all files
|
|
|
|
for(;optind < argc; ++optind) {
|
|
|
|
current_file = args[optind];
|
|
|
|
|
|
|
|
struct filelist list;
|
|
|
|
list.next = NULL;
|
|
|
|
list.path = current_file;
|
2017-10-25 20:42:33 +02:00
|
|
|
list.macros = malloc(sizeof(macrotable_t));
|
|
|
|
|
|
|
|
macrotable_init(list.macros);
|
|
|
|
macrotable_copy(list.macros, &default_macros);
|
2017-10-25 18:36:17 +02:00
|
|
|
|
|
|
|
eval_file(&list);
|
|
|
|
free_filelist(list.next);
|
|
|
|
}
|
|
|
|
}
|