13 Commits

Author SHA1 Message Date
e42a53786a add path impl for linux 2020-12-02 15:36:48 +01:00
ab099339b2 more changes 2020-12-02 15:35:20 +01:00
6b020756af implement macro lookup 2017-10-25 20:42:33 +02:00
d5e58616a2 add init function 2017-10-25 20:30:00 +02:00
ee37ac4da9 remove copy allocator, since it is not needed 2017-10-25 20:28:01 +02:00
5970eae220 rename hash functions to strhash functions 2017-10-25 18:38:33 +02:00
30f97cf955 begin new main in C 2017-10-25 18:36:17 +02:00
2fcc59270b add fs abstraction 2017-10-25 18:36:02 +02:00
ecb5e1bcf3 add testsuit 2017-10-25 18:35:45 +02:00
2bd12a392a add string hashmap 2017-10-25 18:35:04 +02:00
640046ee1e fix target name not written when not overridden 2017-10-09 14:35:53 +02:00
98b44ec923 add options to command 2017-10-09 13:56:48 +02:00
4382ad6d59 cleanup (a bit) 2017-10-09 11:41:14 +02:00
16 changed files with 1202 additions and 110 deletions

View File

@@ -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
View 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
View 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
View 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;
}

View File

185
hashtable.c Normal file
View 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
View 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
View 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);
}
}

View File

@@ -7,16 +7,17 @@
#include <sys/mman.h> // for mmap() #include <sys/mman.h> // for mmap()
#include <sys/stat.h> // for fstat() #include <sys/stat.h> // for fstat()
#include <fcntl.h> // for open() #include <fcntl.h> // for open(), O_RDONLY
#include <unistd.h> // for close() #include <unistd.h> // for close()
#include <errno.h> // for perror() #include <errno.h> // for perror()
#include <iostream> #include <iostream>
#include <fstream>
#include <string> #include <string>
#include <cstring>
#include <vector> #include <vector>
#include <map> #include <map>
#include <set> #include <set>
#include <functional>
#include "fs.hpp" #include "fs.hpp"
#include "memory_string.hpp" #include "memory_string.hpp"
@@ -43,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;
@@ -60,8 +58,6 @@ std::string readTill(iterator &start, const iterator &end, std::function<bool(co
template <typename iterator> template <typename iterator>
std::string readBrackets(iterator &current, const iterator &end, const char * brackets) { std::string readBrackets(iterator &current, const iterator &end, const char * brackets) {
// auto current = begin;
if (current == end || *current != brackets[0]) { if (current == end || *current != brackets[0]) {
std::cout << brackets[0] << "!=" << *current; std::cout << brackets[0] << "!=" << *current;
return std::string(); return std::string();
@@ -122,24 +118,9 @@ std::string InputExtractor::macroExpand(const std::string &input) {
return result; return result;
} }
#include <functional>
typedef std::map<std::string, std::function<void(InputExtractor::List&, std::string)>> CommandList; typedef std::map<std::string, std::function<void(InputExtractor::List&, std::string)>> CommandList;
#include <unistd.h>
#include <fstream>
bool Exists(std::string path) {
std::ifstream file(path);
if (!file) {
return false;
}
file.close();
return true;
}
InputExtractor::List InputExtractor::Include(Path::Path path) { InputExtractor::List InputExtractor::Include(Path::Path path) {
path = Path::Clean(path); path = Path::Clean(path);
List list; List list;
@@ -178,11 +159,13 @@ InputExtractor::List InputExtractor::Include(Path::Path path) {
return list; return list;
} }
// Substring str((const char *)memptr, (const char*)memptr + fileinfo.st_size); // create iteratable memory object
MemoryString file((char*)memptr, fileinfo.st_size); MemoryString file((char*)memptr, fileinfo.st_size);
std::string basedir = Path::Dir(path); std::string basedir = Path::Dir(path);
list = (*this)(basedir, file); // follow include
// evaluate memory region (aka the file)
list = (*this)(basedir, file);
// cleanup // cleanup
munmap(memptr, fileinfo.st_size); munmap(memptr, fileinfo.st_size);
@@ -192,6 +175,8 @@ InputExtractor::List InputExtractor::Include(Path::Path path) {
cout << path << "done" << endl; cout << path << "done" << endl;
} }
// make a relative filepath absolute using the root filename
// and/or the process working directory
Path::Path fixFilename(const Path::Path &file, const Path::Path &root) { Path::Path fixFilename(const Path::Path &file, const Path::Path &root) {
Path::Path temp(file); Path::Path temp(file);
@@ -208,7 +193,7 @@ Path::Path fixFilename(const Path::Path &file, const Path::Path &root) {
return Path::Clean(temp); return Path::Clean(temp);
} }
// evaluate a tex file searching for input statements
InputExtractor::List InputExtractor::operator()(const Path::Path &file, const MemoryString &str){ InputExtractor::List InputExtractor::operator()(const Path::Path &file, const MemoryString &str){
List result; List result;
CommandList IncludeCommands; CommandList IncludeCommands;
@@ -292,104 +277,116 @@ InputExtractor::List InputExtractor::operator()(const Path::Path &file, const Me
return result; return result;
} }
struct Config {
std::string targetName;
Path::Path outfilePath;
bool outfileOverride;
} config ;
std::ostream &writeTarget(std::ostream &stream, const std::string &target_name) {
stream << target_name << ":";
return stream;
}
std::ostream &writeTargetDepends(std::ostream &stream, const Path::Path &path) {
stream << path << "\\\n";
return stream;
}
int openOutfile(std::ofstream &stream) {
cout << "writing dependency rules to " << config.outfilePath << endl;
stream.close();
stream.open(config.outfilePath);
if (!stream) {
cerr << "could not write to " << config.outfilePath << endl;
return 0;
}
if (!config.targetName.empty()) {
writeTarget(stream, config.targetName);
}
return 1;
}
#include <getopt.h>
struct option long_opts[] = {
{"output", required_argument, NULL, 'o'},
{"target", required_argument, NULL, 't'},
{}, // terminator
};
void help(int argc, char ** args) {
cout << args[0] << " [-o output] files..." << endl;
cout << "--output" << endl;
cout << "-o\tby default the program will create a depfile for every input" << endl;
cout << "\tnaming it like the tex file with a .d extension. By giving the -o Option" << endl;
cout << "\tthe output fill instead be put in this file exclusivly" << endl;
}
int main(int argc, char ** args) { int main(int argc, char ** args) {
// find all the files the given tex files depend on // find all the files the given tex files depend on
int fd = 0; int fd = 0;
struct stat filestat; struct stat filestat;
int long_index = 0;
int opt = 0;
while((opt = getopt_long(argc, args, "o:t:", long_opts, &long_index)) != -1) {
switch(opt) {
case 'o':
config.outfilePath = optarg;
config.outfileOverride = true;
break;
case 't':
config.targetName = optarg;
break;
case '?':
help(argc, args);
return 0;
}
}
for(;argc > 1; --argc) { std::ofstream outfile;
Path::Path filename = args[argc-1]; if (!config.outfilePath.empty() && !openOutfile(outfile)) {
return -1; // failed to open outfile
}
// scan remaining arguments as input filenames
for(; optind < argc; optind++) {
Path::Path filename = args[optind];
InputExtractor parser; InputExtractor parser;
// parse file
InputExtractor::List list = parser.Include(filename); InputExtractor::List list = parser.Include(filename);
// output results in makefile rule style // output results in makefile rule style
Path::Path outfile_name = Path::Basename(filename) + ".d"; // check for open outfile
cout << "writing dependecy rules to " << outfile_name << "..."; if (!config.outfileOverride) {
config.outfilePath = Path::Basename(filename) + ".d";
std::ofstream outfile(outfile_name); if (!openOutfile(outfile)) {
continue; // just skip this file
if (!outfile) {
cout << "could not create file!" << endl;
continue;
}
outfile << filename << ":";
for (auto it = list.begin(); it != list.end(); it++) {
outfile << *it << "\t\\\n";
}
cout << "done" << endl;
/*
char * filename = args[argc-1];
cout << "opening " << filename << "...";
// try to open file
fd = open(filename, O_RDONLY);
if (fd == -1) {
perror("could not open input file");
continue;
}
fstat(fd, &filestat);
//cout << "file size: " << filestat.st_size << endl;
// try to mmap file
void * memory_area = mmap(NULL, filestat.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (memory_area == nullptr) {
perror("could not mmap the input");
continue;
}
cout << "start parsing" << endl;
MemoryString file((char*)memory_area, filestat.st_size);
try {
InputExtractor::List list = InputExtractor()(file);
Path::Path outfilename = Path::Basename(Path::Path(filename)) + ".d";
cout << "writing makedeps file to " << outfilename << "..." << endl;
// write in makefile style
std::ofstream output(outfilename);
if (!output) {
std::cout << "could not create output file" << std::endl;
} else {
output << filename << ": ";
for (auto it = list.begin(); it != list.end(); it++) {
if (Path::isRelative(*it)) {
if (Path::isRelative(filename)) {
*it = Path::Join(fs::cwd(), filename, *it);
} else {
*it = Path::Join(Path::Path(filename), *it);
}
}
cout << "depends: " << *it << endl;
output << '\t' << *it << "\t\\\n";
}
output << endl;
} }
cout << filename << done; writeTarget(outfile, filename);
} catch(InputExtractor::Exception &e) {
cout << e.what() << endl;
} }
// cleanup for (auto it = list.begin(); it != list.end(); it++) {
munmap(memory_area, filestat.st_size); writeTargetDepends(outfile, *it);
close(fd); }
*/ // add newline for cleanness
outfile << endl;
cout << "done" << endl;
} }
} }

28
strhash.c Normal file
View 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
View 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_ */

View File

@@ -1,6 +1,7 @@
\documentclass{article} \documentclass{article}
\usepackage[ngerman]{babel} \usepackage[ngerman]{babel}
\def\test{}
\author{Julian Daube} \author{Julian Daube}
\title{Ein Test} \title{Ein Test}

150
test_hashtable.c Normal file
View 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
View 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
View 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);
}

16
tests.h Normal file
View File

@@ -0,0 +1,16 @@
/*
* tests.h
*
* Created on: 20.10.2017
* Author: julian
*/
#ifndef TESTS_H_
#define TESTS_H_
void init();
void fail(const char * err, ...);
void pass();
#endif /* TESTS_H_ */