initial
This commit is contained in:
		
						commit
						512744013e
					
				
							
								
								
									
										17
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
			
		||||
OBJ:=main.o
 | 
			
		||||
OUTPUT:= preparse
 | 
			
		||||
 | 
			
		||||
.PHONY: test debug clean
 | 
			
		||||
 | 
			
		||||
test: debug
 | 
			
		||||
	./$(OUTPUT) test.tex
 | 
			
		||||
 | 
			
		||||
debug: CFLAGS:= -g
 | 
			
		||||
debug: $(OUTPUT)
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
	$(RM) $(OBJ) $(OUTPUT)
 | 
			
		||||
 | 
			
		||||
$(OUTPUT): $(OBJ)
 | 
			
		||||
	$(CC) $(OBJ) -o preparse
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										248
									
								
								main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										248
									
								
								main.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,248 @@
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
typedef struct { char *start, *end; } substr_t;
 | 
			
		||||
 | 
			
		||||
inline static int substr_len(substr_t * str) {
 | 
			
		||||
	return (int)(str->end - str->start);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void substr_conv(char * src, substr_t * target) {
 | 
			
		||||
	target->start	= src;
 | 
			
		||||
	target->end 	= src + strlen(src);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// make new substr on heap using calloc
 | 
			
		||||
// does not copy take ownership of from
 | 
			
		||||
substr_t * substr_new(char * from) {
 | 
			
		||||
	substr_t * ptr = calloc(1, sizeof(substr_t));
 | 
			
		||||
	if (ptr == NULL) { return ptr; }
 | 
			
		||||
 | 
			
		||||
	ptr->start	= from;
 | 
			
		||||
	ptr->end	= ptr->start + strlen(ptr->start);
 | 
			
		||||
 | 
			
		||||
	return ptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define testEnd(current) if (*current->start == '\0' || current->start == current->end) return 0
 | 
			
		||||
#define next(current) current->start++; testEnd(current)
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
	substr_t name;
 | 
			
		||||
} macro_t;
 | 
			
		||||
 | 
			
		||||
macro_t * macro_table = NULL;
 | 
			
		||||
size_t macro_table_size = 0;
 | 
			
		||||
 | 
			
		||||
void macro_add(macro_t *m) {
 | 
			
		||||
	macro_table = realloc(macro_table, sizeof(macro_t)*(macro_table_size+1));
 | 
			
		||||
	if (macro_table== NULL) {
 | 
			
		||||
		printf("out of MEM!!\n");
 | 
			
		||||
		exit(1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// copy macro
 | 
			
		||||
	macro_table[macro_table_size] = *m;
 | 
			
		||||
	macro_table_size++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void macro_table_drop() {
 | 
			
		||||
	free(macro_table);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void macro_table_init() {
 | 
			
		||||
	// add default macros
 | 
			
		||||
	// /newCommand
 | 
			
		||||
	// /def
 | 
			
		||||
	// /begin
 | 
			
		||||
	// /end
 | 
			
		||||
	macro_t temp;
 | 
			
		||||
	substr_conv("newCommand", &temp.name);
 | 
			
		||||
	macro_add(&temp);
 | 
			
		||||
 | 
			
		||||
	substr_conv(&temp.name, "renewCommand", &temp.name);
 | 
			
		||||
	macro_add(&temp);
 | 
			
		||||
 | 
			
		||||
	substr_conv(&temp.name, "def");
 | 
			
		||||
	macro_add(&temp);
 | 
			
		||||
 | 
			
		||||
	substr_conv(&temp.name, "begin");
 | 
			
		||||
	macro_add(&temp);
 | 
			
		||||
 | 
			
		||||
	substr_conv(&temp.name, "end");
 | 
			
		||||
	macro_add(&temp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int macro_name_cmp(macro_t * one, macro_t * two) {
 | 
			
		||||
	// length mismatch results in failure 
 | 
			
		||||
	if (substr_len(&one->name) != substr_len(&two->name)) return 0;
 | 
			
		||||
 | 
			
		||||
	substr_t A = one->name, B = two->name;
 | 
			
		||||
 | 
			
		||||
	for(; A.start != A.end && *A.start == *B.start; A.start++, B.start++) {}
 | 
			
		||||
 | 
			
		||||
	if (A.start != A.end) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int macro_lookup(macro_t *m) {
 | 
			
		||||
	if (substr_len(&m->name) == 0) {
 | 
			
		||||
		return 0; // len == 0 is not allowed
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	size_t i = 0;
 | 
			
		||||
	for (; i < macro_table_size; i++) {
 | 
			
		||||
		if (macro_name_cmp(macro_table + i, m)) {
 | 
			
		||||
			break; // found it
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return i;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// tex macro calls always start with backslash
 | 
			
		||||
int parseMacro(macro_t *target, substr_t * current) {
 | 
			
		||||
	if (*current->start != '\\') {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	target->name.end = target->name.start = current->start;
 | 
			
		||||
 | 
			
		||||
	while((*current->start != '\0') && 
 | 
			
		||||
			substr_len(current) > 0 && 
 | 
			
		||||
			!isspace(*current->start) &&
 | 
			
		||||
			*current->start != '[' &&
 | 
			
		||||
			*current->start != '{' ) {
 | 
			
		||||
		target->name.end = ++current->start;
 | 
			
		||||
		// check for known
 | 
			
		||||
		if (macro_lookup(target)) {
 | 
			
		||||
			break;
 | 
			
		||||
			// this macros name is known, break for now
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	target->name.end = current->start;
 | 
			
		||||
 | 
			
		||||
	// read name		
 | 
			
		||||
	next(current);
 | 
			
		||||
 | 
			
		||||
	int depth = 1;
 | 
			
		||||
 | 
			
		||||
	// optional arguments
 | 
			
		||||
	if (*current->start == '[') {
 | 
			
		||||
		depth = 1;
 | 
			
		||||
		while(*current->start != '\0' && substr_len(current) > 0 && depth) {
 | 
			
		||||
			current->start++;
 | 
			
		||||
			if (*current->start == '[') depth++;
 | 
			
		||||
			if (*current->start == ']') depth--;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		next(current);	
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// required arguments
 | 
			
		||||
	if (*current->start == '{') {
 | 
			
		||||
		depth = 1;
 | 
			
		||||
		while(*current->start != '\0' && substr_len(current) > 0 && depth) {
 | 
			
		||||
			current->start++;
 | 
			
		||||
			if (*current->start == '{') depth++;
 | 
			
		||||
			if (*current->start == '}') depth--;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// all done
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void printMacro(macro_t * macro) {
 | 
			
		||||
	printf("macro: ");
 | 
			
		||||
	char * current = macro->name.start;
 | 
			
		||||
	while(current != macro->name.end) {
 | 
			
		||||
		fputc(*current, stdout);
 | 
			
		||||
		++current;
 | 
			
		||||
	}
 | 
			
		||||
	fputc('\n', stdout);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int parseText(substr_t * str) {
 | 
			
		||||
	while(substr_len(str) > 0) {
 | 
			
		||||
		// a text can contain macro calls too
 | 
			
		||||
		while(substr_len(str) > 0 && *str->start != '\\') {
 | 
			
		||||
			++str->start;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// here starts a macro
 | 
			
		||||
		macro_t macro;
 | 
			
		||||
		if (!parseMacro(¯o, str)) {
 | 
			
		||||
			return 0; // strange
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		printMacro(¯o);
 | 
			
		||||
	}
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <sys/mman.h> 	// for mmap()
 | 
			
		||||
#include <sys/stat.h>	// for fstat()
 | 
			
		||||
#include <fcntl.h>		// for open()
 | 
			
		||||
#include <unistd.h>		// for close()
 | 
			
		||||
#include <errno.h>	// for perror()
 | 
			
		||||
 | 
			
		||||
int main(int argc, char ** args) {
 | 
			
		||||
	// find all the files the given tex files depend on
 | 
			
		||||
 | 
			
		||||
	int fd = 0;
 | 
			
		||||
	struct stat filestat;
 | 
			
		||||
 | 
			
		||||
	for(;argc > 1; --argc) {
 | 
			
		||||
		char * filename = args[argc-1];
 | 
			
		||||
		printf("looking at %s\n", filename);
 | 
			
		||||
 | 
			
		||||
		// try to open file
 | 
			
		||||
		fd = open(filename, O_RDONLY);
 | 
			
		||||
		if (fd == -1) {
 | 
			
		||||
			perror("could not open input file");
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		fstat(fd, &filestat);
 | 
			
		||||
		printf("file size: %d\n", filestat.st_size);	
 | 
			
		||||
		
 | 
			
		||||
		// try to mmap file
 | 
			
		||||
		char * memory_area = mmap(NULL, filestat.st_size, PROT_READ, MAP_SHARED, fd, 0);
 | 
			
		||||
		if (memory_area == NULL) {
 | 
			
		||||
			perror("could not mmap the input");
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		printf("mmap success, parse file\n");
 | 
			
		||||
		
 | 
			
		||||
		substr_t file = {
 | 
			
		||||
			.start = memory_area,
 | 
			
		||||
			.end = memory_area + filestat.st_size,
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		macro_table_init();
 | 
			
		||||
 | 
			
		||||
		if (!parseText(&file)) {
 | 
			
		||||
			printf("error parsing!");
 | 
			
		||||
		} else {
 | 
			
		||||
			printf("parsed %s\n", filename);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// cleanup
 | 
			
		||||
		munmap(memory_area, filestat.st_size);
 | 
			
		||||
		close(fd);
 | 
			
		||||
		macro_table_drop();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	printf("done\n");
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user