#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define VERSION "codeform version 1.2.0 by DWK"
struct strings_t {
char **data;
size_t *len;
size_t number;
};
enum type_t {
TYPE_KEYWORD,
TYPE_MIDWORD,
TYPE_COMMENT,
TYPE_STRING,
TYPE_NESTCOM,
TYPE_NUMBER,
TYPE_FPNUMBER,
TYPE_START,
TYPE_END,
TYPES,
TYPE_ERROR = -1
};
enum pos_t {
POS_START = 1,
POS_END = 2
};
struct onerule_t {
struct strings_t data;
size_t type;
size_t prev;
};
struct onevar_t {
char *from, *to;
size_t flen, tlen;
};
struct ruledata_t {
struct onerule_t **data;
size_t number;
};
struct funclist_t {
size_t *which;
enum type_t *type;
size_t number;
int nest;
};
struct rulelist_t {
const char *from, *to;
char *ws;
size_t wslen;
};
struct typefunc_t {
FILE *out;
char **p;
int iw;
enum pos_t pos;
int n;
size_t number;
enum type_t type;
struct funclist_t func;
struct rulelist_t *list;
};
struct ruletype_t {
const char *name;
size_t sort;
int parts, xparts;
int (*func)(struct onerule_t *rule, struct typefunc_t *tf);
};
struct rulevars_t {
struct onevar_t **data;
size_t number;
};
struct rules_t {
struct ruletype_t type[TYPES];
struct rulevars_t vars;
struct rulelist_t list;
struct ruledata_t data;
struct onerule_t *cdat[TYPES];
};
void add_string(struct strings_t *data, const char *str);
void add_string_len(struct strings_t *data, const char *str, size_t len);
void add_string_copy(struct strings_t *data, const struct strings_t *prev);
void shrink_string(char **str, size_t *len);
int check_usage(int argc, char *argv[]);
void print_usage(const char *progname);
void print_version(void);
void out_of_memory(const char *file, int line);
void free_ruledata(const struct ruledata_t *ruledata);
void free_rulecdat(const struct rules_t *rules);
void free_onerule(const struct ruledata_t *ruledata, size_t which);
void free_strings(const struct strings_t *strings);
void free_dup_onerule(struct onerule_t *rule, const struct onerule_t *prev);
void free_rulevars(const struct rulevars_t *rulevars);
void free_onevar(const struct onevar_t *var);
FILE *open_file(const char *fn, const char *mode);
size_t get_string(char **line, size_t len, size_t *alen, FILE *fp);
void load_rules(struct rules_t *rules, const struct strings_t *rulefn);
void add_ilrules(struct rules_t *rules, const struct strings_t *ilrule);
void add_rules_file_dir(struct rules_t *rules, const char *fn,
const char *dir);
void add_rules_file(struct rules_t *rules, const char *fn);
void add_rule_var(struct rules_t *rules, char *str, const char *file,
int line);
void add_var(struct rulevars_t *vars, char *str, char *eq);
int find_var_pos(struct rulevars_t *vars, const char *p, size_t *pos);
int add_rule_type(struct rules_t *rules, enum type_t *type, enum type_t *t,
char **str, const char *file, int line);
int add_rule_pos(struct rules_t *rules, size_t rsort, struct onerule_t *one);
struct onerule_t *rule_new(void);
void add_rule_new(struct ruledata_t *rd);
void add_rule(struct rules_t *rules, char *str, const char *file, int line);
int add_allocated_rule(struct rules_t *rules, struct onerule_t **cdat,
struct onerule_t *one, struct onerule_t *prev, size_t sort, int freep);
void add_parts(struct strings_t *data, const struct strings_t *prev,
const char *str);
int check_parts(int rparts, int xparts, const char *str);
void process_escapes(struct strings_t *data);
void remove_escapes(char **str, size_t *len);
void process_vars(const struct rulevars_t *vars, struct strings_t *data);
void replace_var_str(const struct rulevars_t *vars, char **str);
void resize_var_string(char **str, char **pos, size_t len);
void find_var_replace(const struct rulevars_t *vars, char **str, char **p,
char *end);
int replace_onevar(const struct onevar_t *var, char **str, char **pos,
char *end);
void replace_novar(size_t cp, char **str, char **pos);
size_t get_type(struct rules_t *rules, const char *str, enum type_t *type);
void parse_files(struct rules_t *rules, struct strings_t *inputfn,
struct strings_t *outputfn);
void read_file(struct rules_t *rules, const char *fn, FILE *out);
void parse_line(struct rules_t *rules, char *line, FILE *out,
struct typefunc_t *tf);
int call_one_type(struct rules_t *rules, struct typefunc_t *tf);
int call_type_cdat(struct rules_t *rules, struct typefunc_t *tf);
int call_type_funcs(struct rules_t *rules, struct typefunc_t *tf);
void set_rules_prev(struct rules_t *rules);
void set_follow_prev(struct rules_t *rules, size_t start);
int find_rule_match(const struct rules_t *rules, const char *p, size_t *pos);
int find_rule_new(const struct rules_t *rules, const char *p, size_t *pos);
int find_rule_prev(const struct rules_t *rules, const char *p, size_t *pos);
void copy_file(FILE *from, const char *fn);
int is_number(const char *p);
int is_fpnumber(const char *p);
void print_number(char **p, FILE *out);
int is_word(int c);
int is_backslashed(const char *start, const char *p);
void remove_char(char *p);
int is_word(int c);
int is_word_prev(const char *line, const char *p);
void remove_comments(char *s);
char *is_var(char *s);
int is_current_dir(const char *s);
void print_chars(char **p, size_t len, FILE *out);
void add_to_funclist(struct funclist_t *func, size_t which, enum type_t type);
void remove_from_funclist(struct funclist_t *func);
void add_ws_rulelist(struct rulelist_t *list, char c);
void print_ws_rulelist(struct rulelist_t *list, FILE *out);
void append_rulelist(const char *from, const char *to, struct rulelist_t *list,
FILE *out);
int type_keyword(struct onerule_t *rule, struct typefunc_t *tf);
int type_midword(struct onerule_t *rule, struct typefunc_t *tf);
int type_comment_end(struct onerule_t *rule, struct typefunc_t *tf);
int type_comment(struct onerule_t *rule, struct typefunc_t *tf);
int type_string(struct onerule_t *rule, struct typefunc_t *tf);
int type_nestcom(struct onerule_t *rule, struct typefunc_t *tf);
int type_number(struct onerule_t *rule, struct typefunc_t *tf);
int type_fpnumber(struct onerule_t *rule, struct typefunc_t *tf);
int type_start(struct onerule_t *rule, struct typefunc_t *tf);
int type_end(struct onerule_t *rule, struct typefunc_t *tf);
int main(int argc, char *argv[]) {
int x;
struct strings_t inputfn, outputfn, rulefn, ilrule, *p;
struct rules_t rules = {
{
{"keyword", 0, 3, 1, type_keyword},
{"midword", 0, 3, 1, type_midword},
{"comment", 0, 3, 1, type_comment},
{"string", 0, 3, 1, type_string},
{"nestcom", 0, 3, 1, type_nestcom},
{"number", (size_t)-1, 2, 0, type_number},
{"fpnumber", (size_t)-1, 2, 0, type_fpnumber},
{"start", (size_t)-1, 1, 0, type_start},
{"end", (size_t)-1, 1, 0, type_end},
},
{
0, 0
},
{
0, 0, 0, 0
},
{
0, 0
},
{
0
}
};
inputfn.data = outputfn.data = rulefn.data = ilrule.data = 0;
inputfn.len = outputfn.len = rulefn.len = ilrule.len = 0;
inputfn.number = outputfn.number = rulefn.number = ilrule.number = 0;
if(check_usage(argc, argv)) return 0;
for(x = 1; x < argc; x ++) {
if(!strcmp(argv[x], "--")) {
x ++;
break;
}
else if(!strcmp(argv[x], "-e")) p = &ilrule;
else if(!strcmp(argv[x], "-f")) p = &rulefn;
else if(!strcmp(argv[x], "-o")) p = &outputfn;
else break;
add_string(p, argv[++x]);
}
for( ; x < argc; x ++) {
add_string(rulefn.number || ilrule.number ? &inputfn : &rulefn,
argv[x]);
}
add_ilrules(&rules, &ilrule);
load_rules(&rules, &rulefn);
set_rules_prev(&rules);
parse_files(&rules, &inputfn, &outputfn);
free_ruledata(&rules.data);
free_rulecdat(&rules);
free_rulevars(&rules.vars);
free(inputfn.data);
free(outputfn.data);
free(rulefn.data);
free(ilrule.data);
return 0;
}
void add_string(struct strings_t *data, const char *str) {
add_string_len(data, str, (size_t)-1);
}
void add_string_len(struct strings_t *data, const char *str, size_t len) {
char **p;
size_t slen, *tlen;
slen = (len == (size_t)-1 ? strlen(str) : len);
p = realloc(data->data, (data->number + 1) * sizeof(char *));
if(!p) out_of_memory(__FILE__, __LINE__);
data->data = p;
data->data[data->number] = malloc(slen + 1);
if(!data->data[data->number]) out_of_memory(__FILE__, __LINE__);
if(len == (size_t)-1) {
strcpy(data->data[data->number], str);
}
else {
strncpy(data->data[data->number], str, len);
data->data[data->number][len] = 0;
}
tlen = realloc(data->len, (data->number + 1) * sizeof(size_t));
if(!tlen) out_of_memory(__FILE__, __LINE__);
data->len = tlen;
data->len[data->number] = slen;
data->number ++;
}
void add_string_copy(struct strings_t *data, const struct strings_t *prev) {
char **p;
size_t *tlen;
p = realloc(data->data, (data->number + 1) * sizeof(char *));
if(!p) out_of_memory(__FILE__, __LINE__);
data->data = p;
data->data[data->number] = prev->data[data->number];
tlen = realloc(data->len, (data->number + 1) * sizeof(size_t));
if(!tlen) out_of_memory(__FILE__, __LINE__);
data->len = tlen;
data->len[data->number] = prev->len[data->number];
data->number ++;
}
void shrink_string(char **str, size_t *len) {
size_t nlen = strlen(*str);
char *p;
if(*len != nlen) {
*len = nlen;
p = realloc(*str, *len + 1);
if(!p) out_of_memory(__FILE__, __LINE__);
*str = p;
}
}
int check_usage(int argc, char *argv[]) {
int x;
for(x = 1; x < argc; x ++) {
if(!strcmp(argv[x], "--help") || !strcmp(argv[x], "-h")
|| !strcmp(argv[x], "--usage")) {
print_usage(argv[0]);
return 1;
}
else if(!strcmp(argv[x], "--version") || !strcmp(argv[x], "-v")) {
print_version();
return 1;
}
}
return 0;
}
void print_usage(const char *progname) {
fprintf(stderr, "\n" VERSION
"\nExecutable path: %s\n"
"\nusage: codeform [-f rule-file] [-e inline-rule] [-o output]"
"\n [--help] [-h] [--usage] [--version] [-v]"
"\n [--] [rule-file-if-no-other-rules] [files...]\n"
"\nThe arguments are very similar to sed's (and -o is from GCC).\n"
"\nOutput can go to multiple files -- just specify more than one -o"
" argument. With\nno -o arguments (or if none of the output files"
" could be opened), stdout is\nused instead.\n", progname);
fprintf(stderr,
"\nIf no rules are specified, the first argument that isn't preceded"
" by an option\nis taken as a rules file instead of an input file."
" With no input files, stdin\nis used.\n"
"\nA simple usage of codeform might look like the following:"
"\n $ ./codeform -o codeform.htm rules/c_1_html codeform.c"
"\nThis formats codeform.c according to the rules in rules/c_1_html,"
" storing the\noutput in codeform.htm.\n");
}
void print_version(void) {
fprintf(stderr, "\n" VERSION " (" __TIME__ " " __DATE__ ")"
"\nCopyright (C) 2006 DWK\n"
"\nThis is free software; see the source for copying conditions. "
" There is NO"
"\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR"
" PURPOSE,"
"\nto the extent permitted by law.\n"
"\nSee the file history that comes with the distribution for a"
" complete history\nlist of versions of codeform.\n");
}
void out_of_memory(const char *file, int line) {
fprintf(stderr, "codeform: (%s:%i): Out of memory\n", file, line);
exit(1);
}
void free_ruledata(const struct ruledata_t *ruledata) {
size_t x;
for(x = 0; x < ruledata->number; x ++) {
free_onerule(ruledata, x);
free(ruledata->data[x]);
}
free(ruledata->data);
}
void free_rulecdat(const struct rules_t *rules) {
enum type_t x;
for(x = 0; x < TYPES; x ++) {
free(rules->cdat[x]);
}
}
void free_onerule(const struct ruledata_t *ruledata, size_t which) {
size_t x, y;
for(x = 0; x < ruledata->data[which]->data.number; x ++) {
if(ruledata->data[which]->data.data[x]) {
for(y = which + 1; y < ruledata->number; y ++) {
if(y != which && ruledata->data[which]->data.data[x]
== ruledata->data[y]->data.data[x]) {
ruledata->data[y]->data.data[x] = 0;
}
}
}
free(ruledata->data[which]->data.data[x]);
}
free(ruledata->data[which]->data.data);
free(ruledata->data[which]->data.len);
}
void free_strings(const struct strings_t *strings) {
size_t x;
for(x = 0; x < strings->number; x ++) {
free(strings->data[x]);
}
free(strings->data);
free(strings->len);
}
void free_dup_onerule(struct onerule_t *rule, const struct onerule_t *prev) {
size_t x;
for(x = 0; x < rule->data.number; x ++) {
if(x >= prev->data.number
|| rule->data.data[x] != prev->data.data[x]) {
free(rule->data.data[x]);
}
}
free(rule->data.data);
free(rule);
}
void free_rulevars(const struct rulevars_t *rulevars) {
size_t x;
for(x = 0; x < rulevars->number; x ++) {
free_onevar(rulevars->data[x]);
free(rulevars->data[x]);
}
free(rulevars->data);
}
void free_onevar(const struct onevar_t *var) {
free(var->from);
free(var->to);
}
FILE *open_file(const char *fn, const char *mode) {
FILE *fp;
if(!strcmp(fn, "-")) {
return strchr(mode, 'r') ? stdin : stdout;
}
if(!(fp = fopen(fn, mode))) {
fprintf(stderr, "codeform: Can't open file \"%s\" for mode \"%s\"\n",
fn, mode);
}
return fp;
}
size_t get_string(char **line, size_t len, size_t *alen, FILE *fp) {
char *p;
int c = 0;
do {
if(c == '\n') c = 0;
else c = getc(fp);
if(c == EOF) {
c = 0;
}
if(len >= *alen) {
*alen += BUFSIZ;
p = realloc(*line, *alen);
if(!p) out_of_memory(__FILE__, __LINE__);
*line = p;
}
(*line)[len++] = c;
} while(c);
return len - 1;
}
void load_rules(struct rules_t *rules, const struct strings_t *rulefn) {
size_t x;
for(x = 0; x < rulefn->number; x ++) {
add_rules_file(rules, rulefn->data[x]);
}
}
void add_ilrules(struct rules_t *rules, const struct strings_t *ilrule) {
size_t x;
for(x = 0; x < ilrule->number; x ++) {
add_rule_var(rules, ilrule->data[x], NULL, x + 1);
}
}
void add_rules_file_dir(struct rules_t *rules, const char *fn,
const char *dir) {
char *last = strrchr(dir, '/'), *p = strrchr(dir, '\\');
if(p > last) last = p;
if(fn && !is_current_dir(fn) && last ++) {
p = malloc(strlen(fn) + last - dir + 1);
if(!p) out_of_memory(__FILE__, __LINE__);
strncpy(p, dir, last - dir);
strcpy(p + (last - dir), fn);
add_rules_file(rules, p);
free(p);
}
else add_rules_file(rules, fn);
}
void add_rules_file(struct rules_t *rules, const char *fn) {
FILE *fp = open_file(fn, "r");
char *str = 0;
int line = 0, isb;
size_t tlen, len, flen = 0, alen = 0;
if(!fp) return;
do {
len = 0;
isb = 1;
while(isb && (tlen = get_string(&str, len, &alen, fp)) != len) {
flen = tlen;
if(flen && str[flen-1] == '\n') str[--flen] = 0;
isb = is_backslashed(str+len, str+flen);
len = flen;
line ++;
if(len && str[len-1] == '\\') str[--len] = 0;
}
add_rule_var(rules, str, fn, line);
} while(tlen != len);
if(fp != stdin) fclose(fp);
free(str);
}
void add_rule_var(struct rules_t *rules, char *str, const char *file,
int line) {
char *p;
remove_comments(str);
if(*str == '.') {
if(file && !strcmp(file, str+1)) {
fprintf(stderr, "codeform: Error in rule (%s:%i):"
" Recursive sourcing: \"%s\"\n",
file ? file : "-e", line, str);
}
else {
if(file && !strchr(str+1, '/') && !strchr(str+1, '\\')) {
add_rules_file_dir(rules, str+1, file);
}
else add_rules_file(rules, str+1);
}
}
else if((p = is_var(str))) add_var(&rules->vars, str, p);
else if(*str) add_rule(rules, str, file, line);
}
void add_var(struct rulevars_t *vars, char *str, char *eq) {
struct onevar_t **p;
size_t eqlen = strlen(eq), pos;
*eq = 0;
if(find_var_pos(vars, str, &pos)) return;
if(pos == (size_t)-1) pos = 0;
p = realloc(vars->data, (vars->number + 1) * sizeof(struct onevar_t *));
if(!p) out_of_memory(__FILE__, __LINE__);
vars->data = p;
memmove(vars->data + pos + 1, vars->data + pos,
(vars->number - pos) * sizeof(struct onevar_t *));
vars->data[pos] = malloc(sizeof(struct onevar_t));
if(!vars->data[pos]) out_of_memory(__FILE__, __LINE__);
vars->data[pos]->from = malloc(eq - str + 1);
if(!vars->data[pos]->from) out_of_memory(__FILE__, __LINE__);
strncpy(vars->data[pos]->from, str, eq - str + 1);
vars->data[pos]->from[eq - str] = 0;
vars->data[pos]->flen = eq - str;
vars->data[pos]->to = malloc(eqlen);
if(!vars->data[pos]->to) out_of_memory(__FILE__, __LINE__);
strcpy(vars->data[pos]->to, eq+1);
vars->data[pos]->tlen = eqlen - 1;
vars->number ++;
}
int find_var_pos(struct rulevars_t *vars, const char *p, size_t *pos) {
size_t mid = (size_t)-1, first = 0, last = vars->number-1;
int v = 0;
*pos = (size_t)-1;
if(!vars->number) return 0;
while(first <= last && last != (size_t)-1) {
mid = (first + last) / 2;
v = strcmp(p, vars->data[mid]->from);
if(first == last && v) break;
if(v < 0) last = mid-1;
else if(v > 0) first = mid+1;
else {
*pos = mid;
first = mid+1;
}
}
if(*pos != (size_t)-1) return 1;
if(v < 0) *pos = mid;
else *pos = mid+1;
return 0;
}
int add_rule_type(struct rules_t *rules, enum type_t *type, enum type_t *t,
char **str, const char *file, int line) {
size_t v = get_type(rules, *str, t);
if(!v) {
if(*type == TYPE_ERROR) {
fprintf(stderr, "codeform: Error in rule (%s:%i):"
" Rule not under a header: \"%s\"\n",
file ? file : "-e", line, *str);
return 1;
}
else {
*t = *type;
}
}
else if(v == (size_t)-1) {
*type = TYPE_ERROR;
fprintf(stderr, "codeform: Error in rule (%s:%i):"
" Invalid header: \"%s\"\n",
file ? file : "-e", line, *str);
return 1;
}
else {
*type = *t;
if(v != 1) {
*str += v;
}
else return 1;
}
return 0;
}
int add_rule_pos(struct rules_t *rules, size_t rsort, struct onerule_t *one) {
size_t sort;
int r;
r = find_rule_new(rules, one->data.data[rsort], &sort);
if(r == 2) return 2;
add_rule_new(&rules->data);
if(r) {
if(sort+1 == rules->data.number) {
rules->data.data[rules->data.number] = one;
}
else {
memmove(rules->data.data+sort+2, rules->data.data+sort+1,
(rules->data.number - sort - 1) * sizeof(struct onerule_t *));
rules->data.data[sort+1] = one;
}
}
else {
if(sort == (size_t)-1) {
rules->data.data[rules->data.number] = one;
}
else {
memmove(rules->data.data+sort+1, rules->data.data+sort,
(rules->data.number - sort) * sizeof(struct onerule_t *));
rules->data.data[sort] = one;
}
}
return r;
}
struct onerule_t *rule_new(void) {
struct onerule_t *one = malloc(sizeof(struct onerule_t));
if(!one) out_of_memory(__FILE__, __LINE__);
one->prev = (size_t)-1;
one->data.data = 0;
one->data.len = 0;
one->data.number = 0;
return one;
}
void add_rule_new(struct ruledata_t *rd) {
struct onerule_t **p;
p = realloc(rd->data, (rd->number + 1) * sizeof(struct onerule_t *));
if(!p) out_of_memory(__FILE__, __LINE__);
rd->data = p;
}
void add_rule(struct rules_t *rules, char *str, const char *file, int line) {
static enum type_t type = TYPE_ERROR;
enum type_t t;
static struct onerule_t *prev = 0;
struct onerule_t *one;
static int freep = 0;
if(add_rule_type(rules, &type, &t, &str, file, line)) return;
if(!check_parts(rules->type[t].parts, rules->type[t].xparts, str)) {
fprintf(stderr, "codeform: Error in rule (%s:%i):"
" Incorrect number of parts (must be %i-%i): \"%s\"\n",
file ? file : "-e", line, rules->type[t].parts,
rules->type[t].parts + rules->type[t].xparts, str);
return;
}
one = rule_new();
one->type = t;
add_parts(&one->data, rules->data.number ? &prev->data : 0, str);
process_vars(&rules->vars, &one->data);
process_escapes(&one->data);
type = t;
if(add_allocated_rule(rules, &rules->cdat[t], one, prev,
rules->type[t].sort, freep)) {
prev = one;
freep = 1;
return;
}
if(freep) {
free_dup_onerule(prev, one);
freep = 0;
}
prev = one;
}
int add_allocated_rule(struct rules_t *rules, struct onerule_t **cdat,
struct onerule_t *one, struct onerule_t *prev, size_t sort, int freep) {
if(sort == (size_t)-1) {
if(!*cdat) *cdat = one;
else return 1;
}
else {
if(add_rule_pos(rules, sort, one) == 2) {
if(freep) free_dup_onerule(prev, one);
return 1;
}
rules->data.number ++;
}
return 0;
}
void add_parts(struct strings_t *data, const struct strings_t *prev,
const char *str) {
const char *p = str;
do {
p = strchr(p, ':');
if(!p) {
if(prev && *str == '*' && !str[1] && data->number < prev->number) {
add_string_copy(data, prev);
}
else add_string(data, str);
}
else {
if(!is_backslashed(str, p)) {
if(prev && *str == '*' && str[1] == ':') {
add_string_copy(data, prev);
}
else add_string_len(data, str, p-str);
str = p+1;
}
p ++;
}
} while(p);
}
int check_parts(int rparts, int xparts, const char *str) {
const char *s = str, *p;
int parts = 0;
do {
p = strchr(s, ':');
if(!p && *s) {
parts ++;
}
else {
if(!is_backslashed(str, p)) {
parts ++;
str = s = p+1;
}
else s ++;
}
} while(p);
return parts >= rparts && parts <= rparts+xparts;
}
void process_escapes(struct strings_t *data) {
size_t x;
for(x = 0; x < data->number; x ++) {
remove_escapes(&data->data[x], &data->len[x]);
}
}
void remove_escapes(char **str, size_t *len) {
char *p = *str;
int x = 0;
for( ; (p = strchr(p, '\\')); x ++, p ++) {
switch(*(p+1)) {
case '\\':
*p = '\\';
remove_char(p+1);
break;
case 'n':
*p = '\n';
remove_char(p+1);
break;
case 't':
*p = '\t';
remove_char(p+1);
break;
default:
remove_char(p);
break;
}
}
if(x) shrink_string(str, len);
}
void process_vars(const struct rulevars_t *vars, struct strings_t *data) {
size_t x;
for(x = 0; x < data->number; x ++) {
replace_var_str(vars, &data->data[x]);
}
}
void replace_var_str(const struct rulevars_t *vars, char **str) {
char *p, *end;
for(p = *str; (p = strchr(p, '$')); p ++) {
if(!is_backslashed(*str, p) && p[1] == '('
&& (end = strchr(p+2, ')'))) {
find_var_replace(vars, str, &p, end);
}
}
}
void resize_var_string(char **str, char **pos, size_t len) {
char *p = realloc(*str, len);
if(!p) {
out_of_memory(__FILE__, __LINE__);
}
*pos = *pos-*str + p;
*str = p;
}
void find_var_replace(const struct rulevars_t *vars, char **str, char **p,
char *end) {
size_t mid = (size_t)-1, first = 0, last = vars->number-1;
size_t pos = (size_t)-1;
int v = 0;
pos = (size_t)-1;
if(!vars->number) return;
while(first <= last && last != (size_t)-1) {
mid = (first + last) / 2;
v = replace_onevar(vars->data[mid], str, p, end);
if(v < 0) last = mid-1;
else if(v > 0) first = mid+1;
else {
pos = mid;
first = mid+1;
*p = *str-1;
break;
}
}
if(pos == (size_t)-1) replace_novar(end-*p-2, str, p);
else {
if(v < 0) pos = mid;
else pos = mid+1;
}
}
int replace_onevar(const struct onevar_t *var, char **str, char **pos,
char *end) {
size_t olen, plen;
int v;
if(!(v = strncmp(*pos+2, var->from, end - *pos - 2))) {
if(var->from[end - *pos - 2]) return -1;
olen = strlen(*str);
plen = olen + *str - *pos;
if(var->flen+2 < var->tlen) {
resize_var_string(str, pos, olen - var->flen + var->tlen - 2);
memmove(*pos + var->tlen, *pos + var->flen+3, plen - var->flen-2);
}
else {
memmove(*pos + var->tlen, *pos + var->flen+3, plen - var->flen-2);
resize_var_string(str, pos, olen - var->flen + var->tlen - 2);
}
memmove(*pos, var->to, var->tlen);
}
return v;
}
void replace_novar(size_t cp, char **str, char **pos) {
size_t olen, plen;
olen = strlen(*str);
plen = olen + *str - *pos;
memmove(*pos, *pos + cp+3, plen - cp-2);
resize_var_string(str, pos, olen - cp-2);
}
size_t get_type(struct rules_t *rules, const char *str, enum type_t *type) {
enum type_t x;
const char *p;
size_t len = (size_t)-1;
if(*str != '=') return 0;
if((p = strchr(str, ':'))) len = p-str-1;
for(x = 0; x < TYPES; x ++) {
if(!strncmp(rules->type[x].name, str+1, len)) {
*type = x;
return (p ? len+2 : 1);
}
}
return (size_t)-1;
}
void parse_files(struct rules_t *rules, struct strings_t *inputfn,
struct strings_t *outputfn) {
FILE *out = 0;
size_t x, y;
for(x = 0; x < outputfn->number
&& !(out = open_file(outputfn->data[x], "w+")); x ++);
if(!out) {
if(x) fprintf(stderr, "codeform: No output files could be opened,"
" using stdout\n");
out = stdout;
}
for(y = 0; y < inputfn->number; y ++) {
read_file(rules, inputfn->data[y], out);
}
if(!inputfn->number) read_file(rules, "-", out);
for(y = 1; y < outputfn->number; y ++) {
copy_file(out, outputfn->data[y]);
}
if(out != stdout) fclose(out);
}
void read_file(struct rules_t *rules, const char *fn, FILE *out) {
FILE *in = open_file(fn, "r");
char *line = malloc(BUFSIZ);
struct typefunc_t tf;
size_t len, alen = BUFSIZ;
int quit = 0;
if(!in) return;
if(!line) out_of_memory(__FILE__, __LINE__);
*line = 0;
tf.func.which = 0;
tf.func.type = 0;
tf.func.number = 0;
tf.func.nest = 1;
tf.pos = POS_START;
tf.list = &rules->list;
tf.out = out;
parse_line(rules, line, out, &tf);
do {
len = 0;
if(!get_string(&line, 0, &alen, in)) {
tf.pos |= POS_END;
quit = 1;
}
tf.out = out;
parse_line(rules, line, out, &tf);
tf.pos = 0;
} while(!quit);
if(in != stdin) fclose(in);
}
void parse_line(struct rules_t *rules, char *line, FILE *out,
struct typefunc_t *tf) {
char *p = line;
int iw = 0, redo;
tf->p = &p;
do {
do {
redo = 0;
tf->iw = iw;
tf->n = p - line;
if(tf->func.number) {
if(call_one_type(rules, tf)) redo = 1;
}
if(!redo && call_type_funcs(rules, tf)) redo = 1;
if(!redo) {
if(*p) {
if(!isspace(*p)) {
append_rulelist(0, 0, &rules->list, out);
putc(*p, out);
}
else if(rules->list.to) {
add_ws_rulelist(&rules->list, *p);
}
else putc(*p, out);
}
iw = is_word(*p);
}
else iw = is_word_prev(line, p);
} while(redo);
} while(*p++);
append_rulelist(0, 0, &rules->list, out);
}
int call_one_type(struct rules_t *rules, struct typefunc_t *tf) {
int r;
if(call_type_cdat(rules, tf)) return 1;
tf->number = tf->func.which[tf->func.number-1];
tf->type = tf->func.type[tf->func.number-1];
r = (*rules->type[tf->type].func)
(rules->data.data[tf->number], tf);
if(r < 0) remove_from_funclist(&tf->func);
return r;
}
int call_type_cdat(struct rules_t *rules, struct typefunc_t *tf) {
enum type_t x;
for(x = 0; x < TYPES; x ++) {
if(rules->type[x].sort == (size_t)-1 && rules->cdat[x]) {
tf->number = (size_t)-1;
tf->type = x;
if((*rules->type[x].func)(rules->cdat[x], tf)) {
return 1;
}
}
}
return 0;
}
int call_type_funcs(struct rules_t *rules, struct typefunc_t *tf) {
size_t match;
if(call_type_cdat(rules, tf)) return 1;
if(find_rule_match(rules, *tf->p, &match)) {
tf->number = match;
tf->type = rules->data.data[match]->type;
if((*rules->type[tf->type].func)(rules->data.data[match], tf)) {
return 1;
}
}
return 0;
}
void set_rules_prev(struct rules_t *rules) {
size_t x, y;
for(x = 0; x < TYPES; x ++) {
for(y = 0; y < rules->data.number; y ++) {
if(rules->type[x].sort != (size_t)-1) {
set_follow_prev(rules, y);
}
}
}
}
void set_follow_prev(struct rules_t *rules, size_t start) {
size_t x;
for(x = start+1; x < rules->data.number; x ++) {
if(strncmp(rules->data.data[start]->data
.data[rules->type[rules->data.data[start]->type].sort],
rules->data.data[x]->data
.data[rules->type[rules->data.data[x]->type].sort],
rules->data.data[start]->data
.len[rules->type[rules->data.data[start]->type].sort])) {
break;
}
rules->data.data[x]->prev = start;
}
}
int find_rule_match(const struct rules_t *rules, const char *p, size_t *pos) {
if(find_rule_new(rules, p, pos)) return 1;
if(*pos < rules->data.number) return find_rule_prev(rules, p, pos);
return 0;
}
int find_rule_new(const struct rules_t *rules, const char *p, size_t *pos) {
size_t mid = (size_t)-1, first = 0, last = rules->data.number-1, sort;
int v = 0;
*pos = (size_t)-1;
if(!rules->data.number) return 0;
while(first <= last && last != (size_t)-1) {
mid = (first + last) / 2;
sort = rules->type[rules->data.data[mid]->type].sort;
v = strncmp(p, rules->data.data[mid]->data.data[sort],
rules->data.data[mid]->data.len[sort]);
if(first == last && v) break;
if(v < 0) last = mid-1;
else if(v > 0) first = mid+1;
else {
*pos = mid;
return !p[rules->data.data[mid]->data.len[sort]] ? 2 : 1;
}
}
if(v < 0) *pos = mid;
else *pos = mid+1;
return 0;
}
int find_rule_prev(const struct rules_t *rules, const char *p, size_t *pos) {
size_t n = *pos-1, sort;
if(*pos) {
while(rules->data.data[n]->prev != (size_t)-1) {
n = rules->data.data[n]->prev;
sort = rules->type[rules->data.data[n]->type].sort;
if(!strncmp(p, rules->data.data[n]->data.data[sort],
rules->data.data[n]->data.len[sort])) {
*pos = n;
return 1;
}
}
}
return 0;
}
void copy_file(FILE *from, const char *fn) {
FILE *to = open_file(fn, "w");
int c;
if(!to) return;
rewind(from);
while((c = getc(from)) != EOF) {
putc(c, to);
}
if(to != stdout) fclose(to);
}
int is_number(const char *p) {
int n = 0;
while(isdigit(*p)) p ++, n = 1;
return n && *p != '.';
}
int is_fpnumber(const char *p) {
int n = 0;
while(isdigit(*p)) p ++, n = 1;
return *p == '.' && (n || isdigit(p[1]));
}
void print_number(char **p, FILE *out) {
while(isalnum(**p) || **p == '.' || **p == '_') {
fputc(*(*p)++, out);
}
}
int is_backslashed(const char *start, const char *p) {
int x = 0;
while(p > start && *(--p) == '\\') x ++;
return x % 2;
}
void remove_char(char *p) {
for( ; *p; p++) *p = *(p+1);
}
int is_word(int c) {
return c == '_' || isalnum(c);
}
int is_word_prev(const char *line, const char *p) {
return p == line ? 0 : is_word(*(p-1));
}
void remove_comments(char *s) {
char *p;
for(p = s; (p = strchr(p, '#')); p ++) {
if(!is_backslashed(s, p)) {
*p = 0;
break;
}
}
}
char *is_var(char *s) {
char *p = s;
while(*p++) {
if(!is_word(*p) && !isdigit(*p)) {
if(*p == '=') {
return is_backslashed(s, p) ? 0 : p;
}
else return 0;
}
}
return 0;
}
int is_current_dir(const char *s) {
return *s == '.' && (s[1] == '/' || s[1] == '\\');
}
void print_chars(char **p, size_t len, FILE *out) {
while(len --) fputc(*(*p)++, out);
}
void add_to_funclist(struct funclist_t *func, size_t which, enum type_t type) {
size_t *f = realloc(func->which, (func->number + 1) * sizeof(size_t));
enum type_t *t;
if(!f) out_of_memory(__FILE__, __LINE__);
func->which = f;
t = realloc(func->type, (func->number + 1) * sizeof(enum type_t));
if(!t) out_of_memory(__FILE__, __LINE__);
func->type = t;
func->which[func->number] = which;
func->type[func->number] = type;
func->number ++;
}
void remove_from_funclist(struct funclist_t *func) {
size_t *f;
enum type_t *t;
if(func->number > 1) {
func->number --;
f = realloc(func->which, func->number * sizeof(size_t));
if(!f) out_of_memory(__FILE__, __LINE__);
func->which = f;
t = realloc(func->type, func->number * sizeof(enum type_t));
if(!t) out_of_memory(__FILE__, __LINE__);
func->type = t;
}
else {
free(func->which);
free(func->type);
func->which = 0;
func->type = 0;
func->number = 0;
}
func->nest = 1;
}
void add_ws_rulelist(struct rulelist_t *list, char c) {
char *p;
p = realloc(list->ws, list->wslen + 2);
if(!p) out_of_memory(__FILE__, __LINE__);
list->ws = p;
list->ws[list->wslen ++] = c;
list->ws[list->wslen] = 0;
}
void print_ws_rulelist(struct rulelist_t *list, FILE *out) {
if(list->ws) {
fputs(list->ws, out);
free(list->ws);
list->ws = 0;
list->wslen = 0;
}
}
void append_rulelist(const char *from, const char *to, struct rulelist_t *list,
FILE *out) {
if(!from) {
if(list->to) {
fputs(list->to, out);
list->to = 0;
list->from = 0;
print_ws_rulelist(list, out);
}
}
else if(!list->from || strcmp(from, list->from)) {
if(list->to) fputs(list->to, out);
print_ws_rulelist(list, out);
fputs(from, out);
list->from = from;
list->to = to;
}
else print_ws_rulelist(list, out);
}
int type_keyword(struct onerule_t *rule, struct typefunc_t *tf) {
if(!tf->iw && !is_word((*tf->p)[rule->data.len[0]])) {
return type_midword(rule, tf);
}
return 0;
}
int type_midword(struct onerule_t *rule, struct typefunc_t *tf) {
size_t x;
if(!strncmp(rule->data.data[0], *tf->p, rule->data.len[0])) {
if(!tf->func.number) {
append_rulelist(rule->data.data[1],
rule->data.data[rule->data.number-1], tf->list, tf->out);
}
if(rule->data.number == 3) {
print_chars(tf->p, rule->data.len[0], tf->out);
}
else {
for(x = 0; x < rule->data.len[0]; x ++) {
(*tf->p)++;
}
fputs(rule->data.data[2], tf->out);
}
return 1;
}
return 0;
}
int type_comment_end(struct onerule_t *rule, struct typefunc_t *tf) {
if(rule->data.number == 3) {
if(tf->type == TYPE_COMMENT || tf->type == TYPE_NESTCOM) {
if((**tf->p == '\n' || **tf->p == '\r') && !is_backslashed(*tf->p - tf->n, *tf->p)) {
fputs(rule->data.data[2], tf->out);
return -1;
}
}
else if(!strncmp(rule->data.data[0], *tf->p, rule->data.len[0])) {
print_chars(tf->p, rule->data.len[0], tf->out);
if(tf->func.number == 1) fputs(rule->data.data[2], tf->out);
return -1;
}
}
else if(!strncmp(rule->data.data[1], *tf->p, rule->data.len[1])) {
print_chars(tf->p, rule->data.len[1], tf->out);
if(tf->type != TYPE_STRING || tf->func.number == 1) {
fputs(rule->data.data[3], tf->out);
}
return -1;
}
if(tf->pos & POS_END) {
if(tf->type != TYPE_STRING || tf->func.number == 1) {
fputs(rule->data.data[rule->data.number-1], tf->out);
}
return -1;
}
return 0;
}
int type_comment(struct onerule_t *rule, struct typefunc_t *tf) {
if(tf->func.number && tf->func.which[tf->func.number-1] == tf->number
&& tf->func.type[tf->func.number-1] == tf->type) {
if(type_comment_end(rule, tf)) return -1;
}
if(tf->func.nest
&& !strncmp(rule->data.data[0], *tf->p, rule->data.len[0])) {
append_rulelist(0, 0, tf->list, tf->out);
if(tf->type != TYPE_STRING || !tf->func.number) {
fputs(rule->data.data[rule->data.number-2], tf->out);
}
print_chars(tf->p, rule->data.len[0], tf->out);
add_to_funclist(&tf->func, tf->number, tf->type);
tf->func.nest = (tf->type == TYPE_NESTCOM);
return 1;
}
return 0;
}
int type_string(struct onerule_t *rule, struct typefunc_t *tf) {
if(tf->func.nest || !is_backslashed(*tf->p - tf->n, *tf->p)) {
return type_comment(rule, tf);
}
return 0;
}
int type_nestcom(struct onerule_t *rule, struct typefunc_t *tf) {
return type_comment(rule, tf);
}
int type_number(struct onerule_t *rule, struct typefunc_t *tf) {
if(!tf->iw && is_number(*tf->p)) {
if(!tf->func.number) {
append_rulelist(rule->data.data[0], rule->data.data[1], tf->list,
tf->out);
}
print_number(tf->p, tf->out);
return 1;
}
return 0;
}
int type_fpnumber(struct onerule_t *rule, struct typefunc_t *tf) {
if(!tf->iw && is_fpnumber(*tf->p)) {
if(!tf->func.number) {
append_rulelist(rule->data.data[0], rule->data.data[1], tf->list,
tf->out);
}
print_number(tf->p, tf->out);
return 1;
}
return 0;
}
int type_start(struct onerule_t *rule, struct typefunc_t *tf) {
if(tf->pos & POS_START && !tf->n) {
tf->pos &= ~POS_START;
fputs(rule->data.data[0], tf->out);
}
return 0;
}
int type_end(struct onerule_t *rule, struct typefunc_t *tf) {
if(tf->pos & POS_END && !**tf->p) {
tf->pos &= ~POS_END;
fputs(rule->data.data[0], tf->out);
}
return 0;
}