1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <fcntl.h>
6 #include "conf.h"
7 #include "err.h"
8 #include "mem.h"
9 
10 
11 /* Allocates memory and loads a file, returns file length
12  */
13 
load_file(char * path,void ** mem)14 static int load_file (char *path, void **mem)
15 {
16   int fd, len;
17 
18   if ((fd = open (path, O_RDONLY)) == -1)
19     return ERROR;
20 
21   len = lseek (fd, 0, SEEK_END);
22   lseek (fd, 0, SEEK_SET);
23 
24   mem_resize (mem, len);
25 
26   if (read (fd, *mem, len) != len) {
27     free (*mem);
28     *mem = 0;
29     close (fd);
30     return ERROR;
31   }
32   close (fd);
33 
34   return len;
35 }
36 
37 
38 /* Returns ERROR if there are no more lines
39  */
40 
next_line(struct CONFIG * cfg)41 static int next_line (struct CONFIG *cfg)
42 {
43   while (cfg->line_pos < cfg->file_len){
44     if (cfg->file[cfg->line_pos] == 10) {
45       cfg->line_pos++;
46       break;
47     }
48     cfg->line_pos++;
49   }
50   if (cfg->line_pos >= cfg->file_len)
51     return ERROR;
52 
53   return E_OK;
54 }
55 
56 
57 /* Returns ERROR if there are no characters on the line
58  */
59 
set_line_end(struct CONFIG * cfg)60 static int set_line_end (struct CONFIG *cfg)
61 {
62   char c;
63   int pos = cfg->line_pos;
64 
65   while (pos < cfg->file_len) {
66     c = cfg->file[pos];
67     if (c == 10 || c == '#') {
68       pos--;
69       break;
70     }
71     pos++;
72   }
73   if (pos < cfg->line_pos)
74     return ERROR;
75 
76   cfg->line_end = pos;
77   return E_OK;
78 }
79 
80 
81 /* Returns ERROR if there are no more arguments
82  */
83 
next_arg(struct CONFIG * cfg)84 static int next_arg (struct CONFIG *cfg)
85 {
86   char c;
87 
88   while (cfg->arg_pos <= cfg->line_end) {
89     c = cfg->file[cfg->arg_pos];
90     if (c != 9 && c != 32)
91       break;
92     cfg->arg_pos++;
93   }
94   if (cfg->arg_pos > cfg->line_end)
95     return ERROR;
96 
97   return E_OK;
98 }
99 
100 
101 /* Returns length of argument
102  */
103 
get_arg_len(struct CONFIG * cfg)104 static int get_arg_len (struct CONFIG *cfg)
105 {
106   int c, len = 0;
107 
108   while (cfg->arg_pos <= cfg->line_end) {
109     c = cfg->file[cfg->arg_pos];
110     if (c == 9 || c == 32)
111       break;
112 
113     cfg->arg_pos++;
114     len++;
115   }
116   return len;
117 }
118 
119 
evaluate(struct CONFIG * cfg)120 static void evaluate (struct CONFIG *cfg)
121 {
122   int arg_pos, arg_len, args, fno = 0, str_len, i;
123   char *s1 = 0, *s2;
124 
125   do {
126     if (set_line_end (cfg) == E_OK) {
127       cfg->arg_pos = cfg->line_pos;
128       args = 0;
129       str_len = 0;
130       while (next_arg (cfg) != ERROR) {
131 	arg_pos = cfg->arg_pos;
132 	arg_len = get_arg_len (cfg);
133 
134 	if (!args) {
135 	  fno = cfg->formats;
136 	  cfg->formats++;
137 	  mem_resize ((void **)&cfg->format,
138 		      cfg->formats * sizeof (struct CFG_FORMAT));
139 	  s1 = cfg->format[fno].strings;
140 	}
141 
142 	str_len += arg_len + 1;
143 	if (str_len > CFG_STRLEN) {
144 	  fprintf (stderr, "error: Arguments in juke.conf longer "
145 		   "than %d characters\n", CFG_STRLEN);
146 	  exit (ERROR);
147 	}
148 
149 	s2 = cfg->file + arg_pos;
150 	for (i=arg_len; i>0;i--)
151 	  *s1++ = *s2++;
152 	*s1++ = 0;
153 
154 	args++;
155 	if (args > CFG_ARGS) {
156 	  fprintf (stderr, "error: Arguments in juke.conf more "
157 		   "than %d\n", CFG_ARGS);
158 	  exit (ERROR);
159 	}
160       }
161       cfg->format[fno].args = args;
162       cfg->format[fno].match_len = strlen (cfg->format[fno].strings);
163     }
164   } while (next_line (cfg) == E_OK);
165 }
166 
167 
build_arg_lists(struct CONFIG * cfg)168 static void build_arg_lists (struct CONFIG *cfg)
169 {
170   int i, j, pos, len;
171 
172   for (i=0;i<cfg->formats;i++) {
173     pos = cfg->format[i].match_len + 1;
174     for (j=0; j<cfg->format[i].args-1; j++) {
175       len = strlen (cfg->format[i].strings + pos);
176       cfg->format[i].arg_list[j] = cfg->format[i].strings + pos;
177       pos += len + 1;
178     }
179     cfg->format[i].arg_list[j+1] = 0;
180   }
181 }
182 
183 
config_load(struct CONFIG * cfg)184 void config_load (struct CONFIG *cfg)
185 {
186   char *home, config[]="/.juke.conf", *str = 0;
187   int str_len;
188 
189   if ((home = getenv ("HOME"))) {
190     str_len = strlen (home) + strlen (config) + 1;
191     mem_resize ((void *)&str, str_len);
192     *str = 0;
193     strcat (str, home);
194     strcat (str, config);
195 
196     cfg->file_len = load_file (str, (void **)&cfg->file);
197     free (str);
198 
199     if (cfg->file_len != ERROR) {
200       evaluate (cfg);
201       if (! cfg->formats) {
202 	fprintf (stderr, "error: No formats in ~/.juke.conf\n");
203 	exit (ERROR);
204       }
205       build_arg_lists (cfg);
206       free (cfg->file);
207       return;
208     }
209   }
210   cfg->file_len = load_file (CFG_RCFILE, (void **)&cfg->file);
211   if (cfg->file_len != ERROR) {
212     evaluate (cfg);
213     if (! cfg->formats) {
214       fprintf (stderr, "error: No formats in " CFG_RCFILE "\n");
215       exit (ERROR);
216     }
217     build_arg_lists (cfg);
218     free (cfg->file);
219   } else {
220     fprintf (stderr, "error: Could not find any configuration file\n");
221     exit (ERROR);
222   }
223 }
224