texdepends/main.c
2020-12-02 15:35:20 +01:00

297 lines
5.2 KiB
C

#include <string.h>
#include "fs.h"
#include <errno.h>
#include <stdlib.h>
#include "hashtable.h"
#define _(x) x
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);
}
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;
};
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);
}
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) {
char temp = fgetc(file);
if (temp == '\n') {
line++;
pos = 0;
} else {
pos++;
}
return temp;
}
int add_char(char ** str, char c) {
if (str == NULL) {
return 0;
}
if (*str != NULL) {
int len = strlen(*str);
char *temp = realloc(*str, len + 2);
if (temp == NULL) {
errno = ENOMEM;
return -1;
}
*str = temp;
(*str)[len] = c;
(*str)[len+1] = 0;
return 0;
}
*str = malloc(2);
if (*str == NULL) {
errno = ENOMEM;
return -1;
}
(*str)[0] = c;
(*str)[1] = '\0';
return 0;
}
int macro_limiter(char c) {
switch(c) {
case '\\':
// next macro
return 1;
case '{':
// arguments
return 2;
case '[':
// optional arguments
return 3;
}
return 0;
}
void eval_macro(struct filelist * last, FILE * file) {
char * name = NULL;
strhash_t hash = 0;
hashtable_iterator_t macro = hashtable_end(last->macros);
char current = 0;
// read macro name
while(good(file) && !macro_limiter(current) && macro == hashtable_end(last->macros)) {
current = fgetc_count(file);
hash = strhash_add(hash, current);
add_char(&name, current);
// try to find macro in table
macro = hashtable_get_hash(last->macros, hash);
}
if (macro == hashtable_end(last->macros)) {
// no macro with that name found
printf("%d:%d:macro not found: %s\n", line, pos, name);
}
if (!good(file)) {
return;
}
}
void eval_file(struct filelist * last) {
// open file
FILE * file = fopen_count(last->path, "r");
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)) {
current = fgetc_count(file);
switch(current) {
case '%':
// comment, skip line
do {
current = fgetc_count(file);
} while(good(file) && current != '\n');
break;
case '\\':
// macro
eval_macro(last, file);
break;
default:
printf(_("%d:%d:unrecognized char! %c\n"), line, pos, current);
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;
list.macros = malloc(sizeof(macrotable_t));
macrotable_init(list.macros);
macrotable_copy(list.macros, &default_macros);
eval_file(&list);
free_filelist(list.next);
}
}