Compare commits
	
		
			10 Commits
		
	
	
		
			master
			...
			reimplemen
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| e42a53786a | |||
| ab099339b2 | |||
| 6b020756af | |||
| d5e58616a2 | |||
| ee37ac4da9 | |||
| 5970eae220 | |||
| 30f97cf955 | |||
| 2fcc59270b | |||
| ecb5e1bcf3 | |||
| 2bd12a392a | 
							
								
								
									
										28
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								Makefile
									
									
									
									
									
								
							@ -1,19 +1,39 @@
 | 
				
			|||||||
OBJ:= main.o fs.o
 | 
					OBJ:= main.o fs.o strhash.o hashtable.o
 | 
				
			||||||
 | 
					CC ?= clang
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# OS dependend targets
 | 
				
			||||||
 | 
					OBJ += fs_linux.o
 | 
				
			||||||
OUTPUT:= texdepends
 | 
					OUTPUT:= texdepends
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.PHONY: test debug clean
 | 
					.PHONY: test debug clean
 | 
				
			||||||
 | 
					
 | 
				
			||||||
all: debug
 | 
					all: debug
 | 
				
			||||||
test: debug
 | 
					test: ctests debug
 | 
				
			||||||
	./$(OUTPUT) test.tex
 | 
						./$(OUTPUT) test.tex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
debug: CXXFLAGS:= -g -std=c++11
 | 
					ctests: test_path test_hashtable
 | 
				
			||||||
 | 
						$(foreach exe,$^,./$(exe);)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.INTERMEDIATE: test_path tests.o test_path.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_path: test_path.o fs.o fs_linux.o tests.o
 | 
				
			||||||
 | 
						$(CC) $^ -o test_path
 | 
				
			||||||
 | 
					test_path.c: fs.o tests.o 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_hashtable: test_hashtable.o strhash.o tests.o hashtable.o
 | 
				
			||||||
 | 
						$(CC) $^ -o test_hashtable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_hashtable.c: hashtable.h
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					debug: CXXFLAGS += -g -std=c++11
 | 
				
			||||||
 | 
					debug: CFLAGS += -g
 | 
				
			||||||
debug: $(OUTPUT)
 | 
					debug: $(OUTPUT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
clean:
 | 
					clean:
 | 
				
			||||||
	$(RM) $(OBJ) $(OUTPUT)
 | 
						$(RM) $(OBJ) $(OUTPUT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
main.o: fs.o
 | 
					fs.c: fs_linux.o
 | 
				
			||||||
 | 
					main.c: fs.o strhash.o hashtable.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$(OUTPUT): main.o
 | 
					$(OUTPUT): main.o
 | 
				
			||||||
	$(CXX) $(OBJ) -o $(OUTPUT)
 | 
						$(CXX) $(OBJ) -o $(OUTPUT)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										40
									
								
								fs.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								fs.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,40 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * fs.c
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Created on: 20.10.2017
 | 
				
			||||||
 | 
					 *      Author: julian
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "fs.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void path_join(struct path *p1, struct path *p2) {
 | 
				
			||||||
 | 
						size_t other = p2->len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while(other) {
 | 
				
			||||||
 | 
							p1->entries = realloc(p1->entries, sizeof(const char*) * (p1->len+1));
 | 
				
			||||||
 | 
							if (p1->entries == NULL) {
 | 
				
			||||||
 | 
								// OUT OF MEM, oper incomplete
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							p1->entries[p1->len] = strdup(p2->entries[p2->len - other]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							other--;
 | 
				
			||||||
 | 
							p1->len++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void free_path(struct path * p) {
 | 
				
			||||||
 | 
						while(p->len) {
 | 
				
			||||||
 | 
							free(p->entries[p->len-1]);
 | 
				
			||||||
 | 
							p->len--;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// free the old array
 | 
				
			||||||
 | 
						free(p->entries);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										30
									
								
								fs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								fs.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * fs.h
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Created on: 20.10.2017
 | 
				
			||||||
 | 
					 *      Author: julian
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef FS_H_
 | 
				
			||||||
 | 
					#define FS_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stddef.h>	// size_t
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct path {
 | 
				
			||||||
 | 
						char ** entries;
 | 
				
			||||||
 | 
						size_t len;
 | 
				
			||||||
 | 
						int absolute:1;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern void path_join(struct path *p1, struct path *p2);
 | 
				
			||||||
 | 
					extern void free_path(struct path *p);
 | 
				
			||||||
 | 
					extern void create_path(struct path * p, const char * fsPath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// behaves like fopen, but uses the path struct as path
 | 
				
			||||||
 | 
					extern FILE * path_fopen(struct path * p, const char * flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* FS_H_ */
 | 
				
			||||||
							
								
								
									
										44
									
								
								fs_linux.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								fs_linux.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * fs_linux.c
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Created on: 20.10.2017
 | 
				
			||||||
 | 
					 *      Author: julian
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#include "fs.h"
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void create_path(struct path * p, const char * fsPath) {
 | 
				
			||||||
 | 
						free_path(p);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const char *start = fsPath, *current = fsPath;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (*start == '/') {
 | 
				
			||||||
 | 
							// absolute path
 | 
				
			||||||
 | 
							p->absolute = 1;
 | 
				
			||||||
 | 
							current = ++start;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (;*current != '\0'; ++current) {
 | 
				
			||||||
 | 
							if (*current == '/')  {
 | 
				
			||||||
 | 
								p->entries = realloc(p->entries, sizeof(p->entries[0]) * (p->len+1));
 | 
				
			||||||
 | 
								p->entries[p->len] = strndup(start, current-start);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// skip delimiter
 | 
				
			||||||
 | 
								start = current+1;
 | 
				
			||||||
 | 
								p->len++;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (start != current) {
 | 
				
			||||||
 | 
							p->entries = realloc(p->entries, sizeof(p->entries[0]) *(p->len+1));
 | 
				
			||||||
 | 
							p->entries[p->len] = strdup(start);
 | 
				
			||||||
 | 
							p->len++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FILE * path_fopen(struct path * p, const char * flags) {
 | 
				
			||||||
 | 
						// reconstruct system path
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										185
									
								
								hashtable.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										185
									
								
								hashtable.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,185 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * hashtable.c
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Created on: 24.10.2017
 | 
				
			||||||
 | 
					 *      Author: julian
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "strhash.h"
 | 
				
			||||||
 | 
					#include "hashtable.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stddef.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int key_compare(entry_key_t one, entry_key_t two) {
 | 
				
			||||||
 | 
						return strcmp(one, two) == 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					entry_hash_t key_hash(entry_key_t key) {
 | 
				
			||||||
 | 
						return strhash_str(key) + 1; // make hash always nonzero
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void hashtable_init(struct hashtable * table) {
 | 
				
			||||||
 | 
						memset(table, 0, sizeof(table));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					hashtable_iterator_t hashtable_end(struct hashtable * table) {
 | 
				
			||||||
 | 
						return table->data + table->len;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					hashtable_iterator_t hashtable_next(struct hashtable * table, hashtable_iterator_t current) {
 | 
				
			||||||
 | 
						if (table == NULL) {
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (current == NULL) {
 | 
				
			||||||
 | 
							current = table->data;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							// we want the NEXT pointer :)
 | 
				
			||||||
 | 
							current++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while(current != hashtable_end(table)) {
 | 
				
			||||||
 | 
							if (current->hash != 0)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							current++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return current;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					hashtable_iterator_t hashtable_get_hash(struct hashtable * table, entry_hash_t hash) {
 | 
				
			||||||
 | 
						if (!table->len) {
 | 
				
			||||||
 | 
							return hashtable_end(table);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						size_t index = hash % table->len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (table->data[index].hash == 0) {
 | 
				
			||||||
 | 
							return hashtable_end(table);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return table->data + index;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					hashtable_iterator_t hashtable_get(struct hashtable * table, entry_key_t key) {
 | 
				
			||||||
 | 
						entry_hash_t hash = key_hash(key);
 | 
				
			||||||
 | 
						return hashtable_get_hash(table, hash);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void hashtable_clear(struct hashtable * table) {
 | 
				
			||||||
 | 
						if (table->dealloc_data) {
 | 
				
			||||||
 | 
							hashtable_iterator_t it = hashtable_next(table, NULL);
 | 
				
			||||||
 | 
							for(;it != hashtable_end(table); it = hashtable_next(table, it)){
 | 
				
			||||||
 | 
								table->dealloc_data(it->data);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						free(table->data);
 | 
				
			||||||
 | 
						table->data = NULL;
 | 
				
			||||||
 | 
						table->count = table->len = 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int hashtable_resize(struct hashtable * table, size_t newsize) {
 | 
				
			||||||
 | 
						if (table == NULL) {
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (newsize == 0) {
 | 
				
			||||||
 | 
							// will fail, correct to 1
 | 
				
			||||||
 | 
							newsize = 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct hashtable temp = *table;
 | 
				
			||||||
 | 
						table->data = calloc(newsize, sizeof(struct entry));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (table->data == NULL) {
 | 
				
			||||||
 | 
							table->data = temp.data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							errno = ENOMEM;
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// try to reinsert old data
 | 
				
			||||||
 | 
						table->len = newsize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (size_t i = 0; i < temp.len; i++) {
 | 
				
			||||||
 | 
							if (temp.data[i].hash && hashtable_add(table, temp.data[i]) == -1) {
 | 
				
			||||||
 | 
								// abort mission, restore old table
 | 
				
			||||||
 | 
								free(table->data);
 | 
				
			||||||
 | 
								*table = temp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return -2;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// delete old table
 | 
				
			||||||
 | 
						free(temp.data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int hashtable_add(struct hashtable * table, struct entry entry) {
 | 
				
			||||||
 | 
						if (table == NULL) {
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (table->len == 0) {
 | 
				
			||||||
 | 
							// initial alloc
 | 
				
			||||||
 | 
							int err = hashtable_resize(table, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (err < 0) {
 | 
				
			||||||
 | 
								return err;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return hashtable_add(table, entry);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// try to insert into table
 | 
				
			||||||
 | 
						size_t index = entry.hash % table->len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (table->data->hash && !key_compare(table->data[index].key, entry.key)) {
 | 
				
			||||||
 | 
							// key collision
 | 
				
			||||||
 | 
							// make table bigger
 | 
				
			||||||
 | 
							if (hashtable_resize(table, table->len*2) != 0) {
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return hashtable_add(table, entry);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// insert new entry
 | 
				
			||||||
 | 
						table->data[index] = entry;
 | 
				
			||||||
 | 
						table->count++;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct entry hashtable_make_entry(entry_key_t key, void * data) {
 | 
				
			||||||
 | 
						return (struct entry){ .data = data,
 | 
				
			||||||
 | 
							.key = key,
 | 
				
			||||||
 | 
							.hash = key_hash(key),
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int hashtable_remove(struct hashtable * table, hashtable_iterator_t it) {
 | 
				
			||||||
 | 
						if (!it || it->hash == 0) {
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (table->dealloc_data) {
 | 
				
			||||||
 | 
							table->dealloc_data(it->data);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						it->data = NULL;
 | 
				
			||||||
 | 
						it->hash = 0;
 | 
				
			||||||
 | 
						table->count--;
 | 
				
			||||||
 | 
						return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										116
									
								
								hashtable.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								hashtable.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,116 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * hashtable.h
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Created on: 21.10.2017
 | 
				
			||||||
 | 
					 *      Author: julian
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef HASHTABLE_H_
 | 
				
			||||||
 | 
					#define HASHTABLE_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stddef.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include "strhash.h"
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef strhash_t entry_hash_t;
 | 
				
			||||||
 | 
					typedef const char * entry_key_t;
 | 
				
			||||||
 | 
					typedef struct entry * hashtable_iterator_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// data deallocator
 | 
				
			||||||
 | 
					typedef void(*hashtable_dealloc)(void*);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int key_compare(entry_key_t one, entry_key_t two);
 | 
				
			||||||
 | 
					extern entry_hash_t key_hash(entry_key_t key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct entry {
 | 
				
			||||||
 | 
						entry_hash_t hash;
 | 
				
			||||||
 | 
						entry_key_t key;
 | 
				
			||||||
 | 
						void * data;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct hashtable {
 | 
				
			||||||
 | 
						struct entry * data;
 | 
				
			||||||
 | 
						size_t len, count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hashtable_dealloc dealloc_data;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern void hashtable_init(struct hashtable * table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern hashtable_iterator_t hashtable_end(struct hashtable * table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Iterate of the hashmap.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * pass the return value to current to iterate over the entire map
 | 
				
			||||||
 | 
					 * pass NULL to get the beginning
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * returns the next set entry in the table from current
 | 
				
			||||||
 | 
					 * returns hashtable_end() when there is nons
 | 
				
			||||||
 | 
					 * example loop:
 | 
				
			||||||
 | 
					 * hashmap_iterator_t current = hashtable_next(table, NULL);
 | 
				
			||||||
 | 
					 * for(;current != hashtable_end(table); current = hashtable_next(table, current)) {}
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					hashtable_iterator_t hashtable_next(struct hashtable * table, hashtable_iterator_t current);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * returns the entry identified by the given hash
 | 
				
			||||||
 | 
					 * returns hashtable_end() if no entry matched
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					hashtable_iterator_t hashtable_get_hash(struct hashtable * table, entry_hash_t hash);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * returns the entry identified by the given key
 | 
				
			||||||
 | 
					 * returns hashtable_end() if no entry matched
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					hashtable_iterator_t hashtable_get(struct hashtable * table, entry_key_t key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * delete all entries of the given table
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * calls dealloc of the table for every data element, if it was set.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void hashtable_clear(struct hashtable * table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * insert a new element in the table
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int hashtable_add(struct hashtable * table, struct entry entry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * resize the hashtable to a new physical size
 | 
				
			||||||
 | 
					 * can also try to make the hashtable smaller
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * returns 0 on success
 | 
				
			||||||
 | 
					 * returns -1 on error (sets errno)
 | 
				
			||||||
 | 
					 * returns -2 if hashtable does not fit in new size.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int hashtable_resize(struct hashtable * table, size_t newsize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * add new element in hashtable
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * returns 0 on success
 | 
				
			||||||
 | 
					 * returns -1 on error
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int hashtable_add(struct hashtable * table, struct entry entry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * make a new entry that can be added out of key and data
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct entry hashtable_make_entry(entry_key_t key, void * data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * remove one entry using the key
 | 
				
			||||||
 | 
					 * @return -1 on error
 | 
				
			||||||
 | 
					 * @return 1 on success
 | 
				
			||||||
 | 
					 * @return 0 on not found
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int hashtable_remove(struct hashtable * table, hashtable_iterator_t it);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* HASHTABLE_H_ */
 | 
				
			||||||
							
								
								
									
										296
									
								
								main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										296
									
								
								main.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,296 @@
 | 
				
			|||||||
 | 
					#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);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -44,9 +44,6 @@ protected:
 | 
				
			|||||||
	std::set<Path::Path> includes;
 | 
						std::set<Path::Path> includes;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <functional>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template <typename iterator>
 | 
					template <typename iterator>
 | 
				
			||||||
std::string readTill(iterator &start, const iterator &end, std::function<bool(const iterator&)> limiter) {
 | 
					std::string readTill(iterator &start, const iterator &end, std::function<bool(const iterator&)> limiter) {
 | 
				
			||||||
	iterator current = start;
 | 
						iterator current = start;
 | 
				
			||||||
@ -137,7 +134,7 @@ InputExtractor::List InputExtractor::Include(Path::Path path) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cout << endl;
 | 
						cout << endl;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
	// add to include list
 | 
						// add to include list
 | 
				
			||||||
	includes.insert(path);
 | 
						includes.insert(path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										28
									
								
								strhash.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								strhash.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * strhash.c
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Created on: 21.10.2017
 | 
				
			||||||
 | 
					 *      Author: julian
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "strhash.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// use rule:
 | 
				
			||||||
 | 
					// hash(i) = hash(i - 1) * 33 ^ str[i]
 | 
				
			||||||
 | 
					// see: http://www.cse.yorku.ca/~oz/hash.html
 | 
				
			||||||
 | 
					strhash_t strhash_add(strhash_t hash, char  c) {
 | 
				
			||||||
 | 
						return hash * 33 ^ c;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					strhash_t strhash_str(const char * str) {
 | 
				
			||||||
 | 
						strhash_t hash = 0;
 | 
				
			||||||
 | 
						while(*str) {
 | 
				
			||||||
 | 
							hash = strhash_add(hash, *str);
 | 
				
			||||||
 | 
							str++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return hash;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										23
									
								
								strhash.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								strhash.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * strhash.h
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Created on: 21.10.2017
 | 
				
			||||||
 | 
					 *      Author: julian
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef STRHASH_H_
 | 
				
			||||||
 | 
					#define STRHASH_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stddef.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef size_t strhash_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// "rehash" string with new char added to end
 | 
				
			||||||
 | 
					strhash_t strhash_add(strhash_t hash, char c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// hash a given string
 | 
				
			||||||
 | 
					strhash_t strhash_str(const char * str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* STRHASH_H_ */
 | 
				
			||||||
							
								
								
									
										150
									
								
								test_hashtable.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								test_hashtable.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,150 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * test_hashtable.c
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Created on: 21.10.2017
 | 
				
			||||||
 | 
					 *      Author: julian
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "tests.h"
 | 
				
			||||||
 | 
					#include "hashtable.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct hashtable table = {};
 | 
				
			||||||
 | 
					struct entry nEntry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void testresize() {
 | 
				
			||||||
 | 
						init("resize");
 | 
				
			||||||
 | 
						int err = hashtable_resize(&table, 20);
 | 
				
			||||||
 | 
						if (err != 0) {
 | 
				
			||||||
 | 
							fail("resize return code was error %d", err);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (table.len != 20) {
 | 
				
			||||||
 | 
							fail("table has wrong size %d", table.len);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pass();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void testadd() {
 | 
				
			||||||
 | 
						init("add");
 | 
				
			||||||
 | 
						nEntry = hashtable_make_entry("hi", "20");
 | 
				
			||||||
 | 
						size_t count = table.count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int err = hashtable_add(&table, nEntry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (err != 0) {
 | 
				
			||||||
 | 
							fail("add gave error %d", err);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (table.count != count +1) {
 | 
				
			||||||
 | 
							fail("table has wrong count (has %d, needs %d)", table.count, count+1);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pass();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					volatile int number_copied = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void* test_copy(void * data) {
 | 
				
			||||||
 | 
						number_copied++;
 | 
				
			||||||
 | 
						return data;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void testget()  {
 | 
				
			||||||
 | 
						init("get");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hashtable_clear(&table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (hashtable_get(&table, "hi") != hashtable_end(&table)) {
 | 
				
			||||||
 | 
							fail("found entry in empty table");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hashtable_add(&table, nEntry);
 | 
				
			||||||
 | 
						hashtable_iterator_t elem = hashtable_get(&table, "hi");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (elem == hashtable_end(&table)) {
 | 
				
			||||||
 | 
							fail("element was not found");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (elem->data != nEntry.data) {
 | 
				
			||||||
 | 
							fail("returned wrong element");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pass();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void testiterate() {
 | 
				
			||||||
 | 
						init("iterate");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hashtable_iterator_t it = hashtable_next(&table, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (it == hashtable_end(&table)) {
 | 
				
			||||||
 | 
							fail("table seems empty?");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (strcmp(it->key, "hi")) {
 | 
				
			||||||
 | 
							fail("wrong entry (smh)");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pass();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					volatile int dealloc_called = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void test_dealloc(void* data) {
 | 
				
			||||||
 | 
						dealloc_called++;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void testremove() {
 | 
				
			||||||
 | 
						init("remove");
 | 
				
			||||||
 | 
						dealloc_called = 0;
 | 
				
			||||||
 | 
						table.dealloc_data = test_dealloc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (hashtable_add(&table, hashtable_make_entry("woop", NULL)) < 0) {
 | 
				
			||||||
 | 
							fail("could not add");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hashtable_iterator_t it = hashtable_get(&table, "woop");
 | 
				
			||||||
 | 
						int ret = hashtable_remove(&table, it);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ret < 0) {
 | 
				
			||||||
 | 
							fail("negative return code");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!ret) {
 | 
				
			||||||
 | 
							fail("could not remove");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!dealloc_called) {
 | 
				
			||||||
 | 
							fail("deallocator not called");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pass();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					void testclear() {
 | 
				
			||||||
 | 
						init("clear");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						size_t count = table.count;
 | 
				
			||||||
 | 
						table.dealloc_data = test_dealloc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hashtable_clear(&table);
 | 
				
			||||||
 | 
						if (table.count != 0 || table.len != 0 || table.data != NULL) {
 | 
				
			||||||
 | 
							fail("memory was not freed");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (dealloc_called != count) {
 | 
				
			||||||
 | 
							fail("dealloc was not called for all the data");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pass();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main() {
 | 
				
			||||||
 | 
						init("hashtable");
 | 
				
			||||||
 | 
						testresize();
 | 
				
			||||||
 | 
						testadd();
 | 
				
			||||||
 | 
						testget();
 | 
				
			||||||
 | 
						testiterate();
 | 
				
			||||||
 | 
						testclear();
 | 
				
			||||||
 | 
						pass();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										74
									
								
								test_path.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								test_path.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,74 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * test_path.c
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Created on: 20.10.2017
 | 
				
			||||||
 | 
					 *      Author: julian
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "tests.h"
 | 
				
			||||||
 | 
					#include "fs.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char * reason_invalid_entry = "invalid entry";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void test1() {
 | 
				
			||||||
 | 
						init("a/b/c");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct path p = {};
 | 
				
			||||||
 | 
						create_path(&p, "a/b/c");
 | 
				
			||||||
 | 
						if (p.len < 3) {
 | 
				
			||||||
 | 
							fail("%d, not enough path splits", p.len);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (p.absolute) {
 | 
				
			||||||
 | 
							fail("path should be relative");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (strcmp(p.entries[0], "a") != 0) {
 | 
				
			||||||
 | 
							fail(reason_invalid_entry);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (strcmp(p.entries[1], "b") != 0) {
 | 
				
			||||||
 | 
							fail(reason_invalid_entry);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (strcmp(p.entries[2], "c") != 0) {
 | 
				
			||||||
 | 
							fail(reason_invalid_entry);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						free_path(&p);
 | 
				
			||||||
 | 
						pass();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void test2() {
 | 
				
			||||||
 | 
						init("/a/b/c");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct path p = {};
 | 
				
			||||||
 | 
						create_path(&p, "/a/b/c");
 | 
				
			||||||
 | 
						if (p.len != 3) {
 | 
				
			||||||
 | 
							fail("%d, not enough path splits", p.len);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!p.absolute) {
 | 
				
			||||||
 | 
							fail("path should be absolute");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (strcmp(p.entries[0], "a") != 0) {
 | 
				
			||||||
 | 
							fail(reason_invalid_entry);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (strcmp(p.entries[1], "b") != 0) {
 | 
				
			||||||
 | 
							fail(reason_invalid_entry);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (strcmp(p.entries[2], "c") != 0) {
 | 
				
			||||||
 | 
							fail(reason_invalid_entry);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						free_path(&p);
 | 
				
			||||||
 | 
						pass();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main() {
 | 
				
			||||||
 | 
						init("test_path");
 | 
				
			||||||
 | 
						test1();
 | 
				
			||||||
 | 
						test2();
 | 
				
			||||||
 | 
						pass();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										72
									
								
								tests.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								tests.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,72 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * tests.c
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Created on: 20.10.2017
 | 
				
			||||||
 | 
					 *      Author: julian
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "tests.h"
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <signal.h>
 | 
				
			||||||
 | 
					#include <stdarg.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char * teststack[20];
 | 
				
			||||||
 | 
					int current = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void segfault(int i) {
 | 
				
			||||||
 | 
						fail("segfault");
 | 
				
			||||||
 | 
						exit(2);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void push(const char * name) {
 | 
				
			||||||
 | 
						if (current < 20) {
 | 
				
			||||||
 | 
							teststack[current] = name;
 | 
				
			||||||
 | 
							current++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pop() {
 | 
				
			||||||
 | 
						if (current != 0)
 | 
				
			||||||
 | 
							current--;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void test_name() {
 | 
				
			||||||
 | 
						int i = 0;
 | 
				
			||||||
 | 
						for (; i < current-1;i++) {
 | 
				
			||||||
 | 
							printf("%s@", teststack[i]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (i < current)
 | 
				
			||||||
 | 
							printf("%s", teststack[i]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void init(const char * name) {
 | 
				
			||||||
 | 
						push(name);
 | 
				
			||||||
 | 
						test_name();
 | 
				
			||||||
 | 
						puts(": START");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// install signal handlers
 | 
				
			||||||
 | 
						signal(SIGSEGV, segfault);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void fail(const char * reason, ...) {
 | 
				
			||||||
 | 
						va_list list;
 | 
				
			||||||
 | 
						va_start(list, reason);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						test_name();
 | 
				
			||||||
 | 
						fputs(": FAIL (", stdout);
 | 
				
			||||||
 | 
						vprintf(reason, list);
 | 
				
			||||||
 | 
						va_end(list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						puts(")");
 | 
				
			||||||
 | 
						exit(1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pass() {
 | 
				
			||||||
 | 
						test_name();
 | 
				
			||||||
 | 
						puts(": PASS");
 | 
				
			||||||
 | 
						pop();
 | 
				
			||||||
 | 
					//	exit(0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user