#include #include #include #include #include #include "conf.h" #include "err.h" #include "mem.h" /* Allocates memory and loads a file, returns file length */ static int load_file (char *path, void **mem) { int fd, len; if ((fd = open (path, O_RDONLY)) == -1) return ERROR; len = lseek (fd, 0, SEEK_END); lseek (fd, 0, SEEK_SET); mem_resize (mem, len); if (read (fd, *mem, len) != len) { free (*mem); *mem = 0; close (fd); return ERROR; } close (fd); return len; } /* Returns ERROR if there are no more lines */ static int next_line (struct CONFIG *cfg) { while (cfg->line_pos < cfg->file_len){ if (cfg->file[cfg->line_pos] == 10) { cfg->line_pos++; break; } cfg->line_pos++; } if (cfg->line_pos >= cfg->file_len) return ERROR; return E_OK; } /* Returns ERROR if there are no characters on the line */ static int set_line_end (struct CONFIG *cfg) { char c; int pos = cfg->line_pos; while (pos < cfg->file_len) { c = cfg->file[pos]; if (c == 10 || c == '#') { pos--; break; } pos++; } if (pos < cfg->line_pos) return ERROR; cfg->line_end = pos; return E_OK; } /* Returns ERROR if there are no more arguments */ static int next_arg (struct CONFIG *cfg) { char c; while (cfg->arg_pos <= cfg->line_end) { c = cfg->file[cfg->arg_pos]; if (c != 9 && c != 32) break; cfg->arg_pos++; } if (cfg->arg_pos > cfg->line_end) return ERROR; return E_OK; } /* Returns length of argument */ static int get_arg_len (struct CONFIG *cfg) { int c, len = 0; while (cfg->arg_pos <= cfg->line_end) { c = cfg->file[cfg->arg_pos]; if (c == 9 || c == 32) break; cfg->arg_pos++; len++; } return len; } static void evaluate (struct CONFIG *cfg) { int arg_pos, arg_len, args, fno = 0, str_len, i; char *s1 = 0, *s2; do { if (set_line_end (cfg) == E_OK) { cfg->arg_pos = cfg->line_pos; args = 0; str_len = 0; while (next_arg (cfg) != ERROR) { arg_pos = cfg->arg_pos; arg_len = get_arg_len (cfg); if (!args) { fno = cfg->formats; cfg->formats++; mem_resize ((void **)&cfg->format, cfg->formats * sizeof (struct CFG_FORMAT)); s1 = cfg->format[fno].strings; } str_len += arg_len + 1; if (str_len > CFG_STRLEN) { fprintf (stderr, "error: Arguments in juke.conf longer " "than %d characters\n", CFG_STRLEN); exit (ERROR); } s2 = cfg->file + arg_pos; for (i=arg_len; i>0;i--) *s1++ = *s2++; *s1++ = 0; args++; if (args > CFG_ARGS) { fprintf (stderr, "error: Arguments in juke.conf more " "than %d\n", CFG_ARGS); exit (ERROR); } } cfg->format[fno].args = args; cfg->format[fno].match_len = strlen (cfg->format[fno].strings); } } while (next_line (cfg) == E_OK); } static void build_arg_lists (struct CONFIG *cfg) { int i, j, pos, len; for (i=0;iformats;i++) { pos = cfg->format[i].match_len + 1; for (j=0; jformat[i].args-1; j++) { len = strlen (cfg->format[i].strings + pos); cfg->format[i].arg_list[j] = cfg->format[i].strings + pos; pos += len + 1; } cfg->format[i].arg_list[j+1] = 0; } } void config_load (struct CONFIG *cfg) { char *home, config[]="/.juke.conf", *str = 0; int str_len; if ((home = getenv ("HOME"))) { str_len = strlen (home) + strlen (config) + 1; mem_resize ((void *)&str, str_len); *str = 0; strcat (str, home); strcat (str, config); cfg->file_len = load_file (str, (void **)&cfg->file); free (str); if (cfg->file_len != ERROR) { evaluate (cfg); if (! cfg->formats) { fprintf (stderr, "error: No formats in ~/.juke.conf\n"); exit (ERROR); } build_arg_lists (cfg); free (cfg->file); return; } } cfg->file_len = load_file (CFG_RCFILE, (void **)&cfg->file); if (cfg->file_len != ERROR) { evaluate (cfg); if (! cfg->formats) { fprintf (stderr, "error: No formats in " CFG_RCFILE "\n"); exit (ERROR); } build_arg_lists (cfg); free (cfg->file); } else { fprintf (stderr, "error: Could not find any configuration file\n"); exit (ERROR); } }