fixed new lines
[ikh.git] / miconf / miconf.c
blob62f593b16b1f2e2b49c1fa64ed3cf3539fce75e6
1 /*
2 * Copyright (c) 2012 ikh software, inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
7 * 1) Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 * 2) Redistributions of source code with modification must include a notice
10 * that the code was modified.
11 * 3) Neither the names of the authors nor the names of their contributors may
12 * be used to endorse or promote products derived from this software without
13 * specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <dirent.h>
32 #include <string.h>
33 #include <sys/stat.h>
34 #include "lua.h"
35 #include "lauxlib.h"
36 #include "lualib.h"
38 #include "version"
40 #define WRITE_BATCH 50
41 #define WRITE_BEG "[=====["
42 #define WRITE_END "]=====]"
44 #define EQ '='
45 #define LA '<'
46 #define RA '>'
47 #define NL '\n'
49 #define doNewLine(c) fprintf(fo,"io.write('\\n') -- %d\n",lineno)
51 #define begText() fprintf(fo,"io.write(%s",WRITE_BEG)
52 #define doText(c) fputc(c,fo)
53 #define endText() fprintf(fo,"%s) -- %d\n",WRITE_END,lineno)
55 #define begStat() fputc(NL,fo)
56 #define doStat(c) fputc(c,fo)
57 #define endStat() fprintf(fo," -- %d\n",lineno)
59 #define begExpr() fprintf(fo,"io.write(tostring(")
60 #define doExpr(c) fputc(c,fo)
61 #define endExpr() fprintf(fo,")) -- %d\n", lineno)
63 // if (lineno % WRITE_BATCH == 0) {
65 void convert(FILE* fi, FILE* fo) {
66 int lineno = 1;
67 int c;
68 int s = 1; //state
69 do {
70 c=getc(fi);
71 switch (s) {
72 case 1:
73 switch (c) {
74 case EQ: s=2; break;
75 case LA: s=6; break;
76 case EOF: s=1; break;
77 case NL: s=1; doNewLine(); break;
78 default: s=5; begText(); doText(c); break;
80 break;
81 case 2:
82 switch (c) {
83 case EQ: s=3; break;
84 case EOF: s=5; doText(EQ); endText(); break;
85 case NL: s=1; doText(EQ); endText(); break;
86 default: s=5; doText(EQ); doText(c); break;
88 break;
89 case 3:
90 switch (c) {
91 case EQ: s=4; begStat(); break;
92 case EOF: s=5; doText(EQ); doText(EQ); endText(); break;
93 case NL: s=1; doText(EQ); doText(EQ); endText(); break;
94 default: s=5; doText(EQ); doText(EQ); doText(c); break;
96 break;
97 case 4:
98 switch (c) {
99 case EOF: s=1; endStat(); break;
100 case NL: s=1; endStat(); break;
101 default: s=4; doStat(c); break;
103 break;
104 case 5:
105 switch (c) {
106 case LA: s=6; break;
107 case NL: s=1; doText(c); endText(); break;
108 case EOF: s=5; endText(); break;
109 default: s=5; doText(c); break;
111 break;
112 case 6:
113 switch (c) {
114 case LA: s=7; break;
115 case EOF: s=5; doText(LA); endText(); break;
116 case NL: s=1; doText(LA); endText(); break;
117 default: s=5; doText(LA); doText(c); break;
119 break;
120 case 7:
121 switch (c) {
122 case LA: s=8; endText(); begExpr(); break;
123 case EOF: s=5; doText(LA); doText(LA); endText(); break;
124 case NL: s=1; doText(LA); doText(LA); endText(); break;
125 default: s=5; doText(LA); doText(LA); doText(c); break;
127 break;
128 case 8:
129 switch (c) {
130 case RA: s=9; break;
131 case EOF: s=8; endExpr(); break;
132 default: s=8; doExpr(c); break;
134 break;
135 case 9:
136 switch (c) {
137 case RA: s=10; break;
138 case EOF: s=8; doExpr(RA); endExpr(); break;
139 default: s=8; doExpr(RA); doExpr(c); break;
141 break;
142 case 10:
143 switch (c) {
144 case RA: s=5; endExpr(); begText(); break;
145 case EOF: s=8; doExpr(RA); doExpr(RA); endExpr(); break;
146 default: s=8; doExpr(RA); doExpr(RA); doExpr(c); break;
148 break;
150 if (c==NL) {
151 lineno++;
154 } while (c!=EOF);
156 if (ferror(fi)) {
157 fprintf(stderr,"file read error (errno=%d: %s)\n", errno, strerror(errno));
158 exit(1);
162 void process_file(lua_State *L, const char* iname, const char* oname, int tflag, int mflag, int vflag, const char* pattern) {
164 if (vflag) {
165 fprintf(stderr, "processing file '%s' -> '%s'\n", iname, oname);
168 const char* tname;
169 FILE* fi;
170 FILE* ft;
171 struct stat tstats;
172 int isStdin = (strcmp(iname,"-")==0);
173 int isStdout = (strcmp(oname,"-")==0);
175 mflag = mflag || isStdin || isStdout;
177 if (isStdin) {
178 fi = stdin;
179 } else {
180 fi = fopen(iname,"r");
181 if (fi==NULL) {
182 fprintf(stderr,"can't open input file (file='%s', errno=%d: %s)\n", iname, errno, strerror(errno));
183 exit(1);
187 if (!isStdout) {
188 stdout = freopen(oname, "w", stdout);
189 if (stdout==NULL) {
190 fprintf(stderr,"can't open output file (file='%s', errno=%d: %s)\n", oname, errno, strerror(errno));
191 exit(1);
195 tname = tmpnam(NULL);
196 if (tname==NULL) {
197 fprintf(stderr,"can't obtain temporary file name (errno=%d: %s)\n", errno, strerror(errno));
198 exit(1);
200 ft = fopen(tname,"w");
201 if (ft==NULL) {
202 fprintf(stderr,"can't open temporary file (file='%s', errno=%d: %s)\n", tname, errno, strerror(errno));
203 exit(1);
205 convert(fi,ft);
206 fclose(ft);
208 if (!isStdin) {
209 fclose(fi);
212 if (luaL_dofile(L,tname)!=0) {
213 fprintf(stderr,"%s (file='%s')\n",lua_tostring(L,-1),tname);
214 lua_pop(L,1);
215 exit(1);
218 // if (!isStdout) {
219 // stdout = freopen("/dev/null", "w", stdout);
220 // if (stdout==NULL) {
221 // fprintf(stderr,"can't open /dev/null (errno=%d: %s)\n", errno, strerror(errno));
222 // exit(1);
223 // }
224 // }
226 if (!mflag) {
227 if (stat(iname,&tstats) != 0) {
228 fprintf(stderr,"can't stat input file (file='%s', errno=%d: %s)\n", iname, errno, strerror(errno));
229 exit(1);
231 if (chmod(oname,tstats.st_mode)!=0) {
232 fprintf(stderr,"can't chmod output file (file='%s', mode=%o, errno=%d: %s)\n", tname, tstats.st_mode, errno, strerror(errno));
233 exit(1);
237 if (!tflag) {
238 if (unlink(tname)!=0) {
239 fprintf(stderr,"can't remove temporary file (file='%s', errno=%d: %s)\n", tname, errno, strerror(errno));
240 exit(1);
242 } else if (vflag){
243 fprintf(stderr,"temporary file '%s'\n",tname);
247 void process_dir(lua_State *L, const char* dname, int tflag, int mflag, int vflag, const char* pattern, int level) {
249 if (vflag) {
250 fprintf(stderr, "processing dir(%d) '%s'\n", level, dname);
253 DIR *dirp = opendir(dname);
254 if (dirp==NULL) {
255 fprintf(stderr,"can't open directory (name='%s', errno=%d: %s)\n", dname, errno, strerror(errno));
256 exit(1);
258 struct dirent* dp;
259 while ((dp=readdir(dirp)) != NULL) {
260 switch(dp->d_type) {
261 case DT_REG:
262 lua_getglobal(L,"miconf_fname_hook");
263 lua_pushinteger(L,level);
264 lua_pushstring(L,pattern);
265 lua_pushstring(L,dname);
266 lua_pushstring(L,dp->d_name);
267 lua_pushinteger(L,dp->d_type);
268 if (lua_pcall(L, 5, 2, 0) != 0) {
269 fprintf(stderr,"error running lua function 'miconf_fname_hook': %s\n", lua_tostring(L,-1));
270 exit(1);
272 if (lua_isstring(L,-1) && lua_isstring(L,-1)) {
273 const char* iname = lua_tostring(L,-2);
274 const char* oname = lua_tostring(L,-1);
275 process_file(L,iname,oname,tflag,mflag,vflag,pattern);
277 lua_pop(L,2);
278 break;
279 case DT_DIR:
280 if (strcmp(dp->d_name,".")==0 || strcmp(dp->d_name,"..")==0)
281 break;
282 lua_getglobal(L,"miconf_dname_hook");
283 lua_pushinteger(L,level);
284 lua_pushstring(L,dname);
285 lua_pushstring(L,dp->d_name);
286 if (lua_pcall(L, 3, 1, 0) != 0) {
287 fprintf(stderr,"error running lua function 'miconf_dname_hook': %s\n", lua_tostring(L,-1));
288 exit(1);
290 if (lua_isstring(L,-1)) {
291 process_dir(L,lua_tostring(L,-1),tflag,mflag,vflag,pattern,level+1);
293 lua_pop(L,1);
294 break;
297 closedir(dirp);
302 void usage() {
303 fprintf(stderr,"Miconf: configuration utility\n\n");
304 fprintf(stderr,"Miconf %s Copyright (c) 2012 ikh software, inc.\n", strchr(MICONF_RELEASE,'-')+1);
305 fprintf(stderr,"%s\n\n", LUA_COPYRIGHT);
306 fprintf(stderr,"Usage:\n");
307 fprintf(stderr," miconf [options] template_file output_file\n");
308 fprintf(stderr," miconf [options] -r directory\n\n");
309 fprintf(stderr,"Options:\n");
310 fprintf(stderr," -c file -- config file, for example: -c config.lua \n");
311 fprintf(stderr," -e block -- config block, for example: -e 'host=\"foo\"; ip=\"127.0.0.1\"' \n");
312 fprintf(stderr," -p pattern -- template file name pattern (default: '[.]template$')\n");
313 fprintf(stderr," -t -- preserve temp files\n");
314 fprintf(stderr," -m -- disable chmod\n");
315 fprintf(stderr," -v -- verbose\n");
316 fprintf(stderr," -h -- help\n\n");
320 int main(int argc, char* argv[]) {
321 int ch;
322 int rflag = 0;
323 int tflag = 0;
324 int mflag = 0;
325 int vflag = 0;
326 const char* pattern = "[.]template$";
327 lua_State *L = luaL_newstate();
328 luaL_openlibs(L);
331 const char* hooks =
332 "function miconf_dname_hook(level,path,file)\n"
333 " return path..(file and (\"/\"..file) or \"\")\n"
334 "end\n"
335 "function miconf_fname_hook(level,pattern,path,file,type)\n"
336 " ofile,cnt = file:gsub(pattern,\"\")\n"
337 " if ofile and cnt==1 and ofile:len()>0 then\n"
338 " return path..(file and (\"/\"..file) or \"\"), path..\"/\"..ofile\n"
339 " else\n"
340 " return nil,nil\n"
341 " end\n"
342 "end\n"
345 if (luaL_dostring(L,hooks)!=0) {
346 fprintf(stderr,"%s (string='%s')\n",lua_tostring(L,-1),hooks);
347 lua_pop(L,1);
348 exit(1);
351 while ((ch = getopt(argc, argv, "hrtmvp:e:c:")) != -1) {
352 switch (ch) {
353 case 'h':
354 usage();
355 fprintf(stderr,"Default config:\n\n",hooks);
356 fprintf(stderr,"%s\n",hooks);
357 fprintf(stderr,"----\n\n");
358 exit(0);
359 case 'r': rflag = 1; break;
360 case 't': tflag = 1; break;
361 case 'm': mflag = 1; break;
362 case 'v': vflag = 1; break;
363 case 'p': pattern = optarg; break;
364 case 'c':
365 if (luaL_dofile(L,optarg)!=0) {
366 fprintf(stderr,"%s (file='%s')\n",lua_tostring(L,-1),optarg);
367 lua_pop(L,1);
368 exit(1);
370 break;
371 case 'e':
372 if (luaL_dostring(L,optarg)!=0) {
373 fprintf(stderr,"%s (block='%s')\n",lua_tostring(L,-1),optarg);
374 lua_pop(L,1);
375 exit(1);
377 break;
378 default:
379 usage();
380 exit(1);
383 argc -= optind;
384 argv += optind;
386 if (!rflag) {
387 const char* iname = argc>0 ? argv[0] : "-";
388 const char* oname = argc>1 ? argv[1] : "-";
389 process_file(L,iname,oname,tflag,mflag,vflag,pattern);
390 } else {
391 const char* dname = argc>0 ? argv[0] : ".";
392 lua_getglobal(L,"miconf_dname_hook");
393 lua_pushinteger(L,0);
394 lua_pushstring(L,dname);
395 lua_pushnil(L);
396 if (lua_pcall(L, 3, 1, 0) != 0) {
397 fprintf(stderr,"error running lua function 'miconf_dname_hook': %s\n", lua_tostring(L,-1));
398 exit(1);
400 if (lua_isstring(L,-1)) {
401 process_dir(L,lua_tostring(L,-1),tflag,mflag,vflag,pattern,1);
403 lua_pop(L,1);
406 lua_close(L);
408 return(0);