1 /* babel.c The babel command line program
\r
2 * (c) 2006 By L. Ross Raszewski
\r
4 * This code is freely usable for all purposes.
\r
6 * This work is licensed under the Creative Commons Attribution2.5 License.
\r
7 * To view a copy of this license, visit
\r
8 * http://creativecommons.org/licenses/by/2.5/ or send a letter to
\r
10 * 543 Howard Street, 5th Floor,
\r
11 * San Francisco, California, 94105, USA.
\r
13 * This file depends upon misc.c and babel.h
\r
15 * This file exports one variable: char *rv, which points to the file name
\r
16 * for an ifiction file. This is used only by babel_ifiction_verify
\r
27 int chdir(const char *);
\r
28 char *getcwd(char *, int);
\r
35 /* checked malloc function */
\r
36 void *my_malloc(int, char *);
\r
38 /* babel performs several fundamental operations, which are specified
\r
39 by command-line objects. Each of these functions corresponds to
\r
40 a story function (defined in babel_story_functions.c) or an
\r
41 ifiction function (defined in babel_ifiction_functions.c) or both.
\r
42 These are the types of those functions.
\r
45 typedef void (*story_function)(void);
\r
46 typedef void (*ifiction_function)(char *);
\r
47 typedef void (*multi_function)(char **, char *, int);
\r
48 /* This structure tells babel what to do with its command line arguments.
\r
49 if either of story or ifiction are NULL, babel considers this command line
\r
50 option inappropriate for that type of file.
\r
52 struct function_handler {
\r
53 char *function; /* the textual command line option */
\r
54 story_function story; /* handler for story files */
\r
55 ifiction_function ifiction; /* handler for ifiction files */
\r
56 char *desc; /* Textual description for help text */
\r
59 struct multi_handler {
\r
62 multi_function handler;
\r
67 /* This is an array of function_handler objects which specify the legal
\r
68 arguments. It is terminated by a function_handler with a NULL function
\r
70 static struct function_handler functions[] = {
\r
71 { "-ifid", babel_story_ifid, babel_ifiction_ifid, "Deduce IFID"},
\r
72 { "-format", babel_story_format, NULL, "Deduce story format" },
\r
73 { "-ifiction", babel_story_ifiction, NULL, "Extract iFiction file" },
\r
74 { "-meta", babel_story_meta, NULL, "Print story metadata" },
\r
75 { "-identify", babel_story_identify, NULL, "Describe story file" },
\r
76 { "-cover", babel_story_cover, NULL, "Extract cover art" },
\r
77 { "-story", babel_story_story, NULL, "Extract story file (ie. from a blorb)" },
\r
78 { "-verify", NULL, babel_ifiction_verify, "Verify integrity of iFiction file" },
\r
79 { "-lint", NULL, babel_ifiction_lint, "Verify style of iFiction file" },
\r
80 { "-fish", babel_story_fish, babel_ifiction_fish, "Extract all iFiction and cover art"},
\r
81 { "-unblorb", babel_story_unblorb, NULL, "As -fish, but also extract story files"},
\r
82 { NULL, NULL, NULL }
\r
84 static struct multi_handler multifuncs[] = {
\r
85 { "-blorb", "<storyfile> <ifictionfile> [<cover art>]", babel_multi_blorb, 2, 3, "Bundle story file and (sparse) iFiction into blorb" },
\r
86 { "-blorbs", "<storyfile> <ifictionfile> [<cover art>]", babel_multi_blorb1, 2, 3, "Bundle story file and (sparse) iFiction into sensibly-named blorb" },
\r
87 { "-complete", "<storyfile> <ifictionfile>", babel_multi_complete, 2, 2, "Create complete iFiction file from sparse iFiction" },
\r
88 { NULL, NULL, NULL, 0, 0, NULL }
\r
91 int main(int argc, char **argv)
\r
98 /* Set the input filename. Note that if this is invalid, babel should
\r
99 abort before anyone notices
\r
103 if (argc < 3) ok=0;
\r
104 /* Detect the presence of the "-to <directory>" argument.
\r
106 if (ok && argc >=5 && strcmp(argv[argc-2], "-to")==0)
\r
108 todir=argv[argc-1];
\r
111 if (ok) for(i=0;multifuncs[i].function;i++)
\r
112 if (strcmp(argv[1],multifuncs[i].function)==0 &&
\r
113 argc>= multifuncs[i].nargsm+2 &&
\r
114 argc <= multifuncs[i].nargsx+2)
\r
117 multifuncs[i].handler(argv+2, todir, argc-2);
\r
123 /* Find the apropriate function_handler */
\r
125 for(i=0;functions[i].function && strcmp(functions[i].function,argv[1]);i++);
\r
126 if (!functions[i].function) ok=0;
\r
127 else if (strcmp(fn,"-")) {
\r
128 f=fopen(argv[2],"r");
\r
133 /* Print usage error if anything has gone wrong */
\r
136 printf("%s: Treaty of Babel Analysis Tool (%s, %s)\n"
\r
137 "Usage:\n", argv[0],BABEL_VERSION, TREATY_COMPLIANCE);
\r
138 for(i=0;functions[i].function;i++)
\r
140 if (functions[i].story)
\r
141 printf(" babel %s <storyfile>\n",functions[i].function);
\r
142 if (functions[i].ifiction)
\r
143 printf(" babel %s <ifictionfile>\n",functions[i].function);
\r
144 printf(" %s\n",functions[i].desc);
\r
146 for(i=0;multifuncs[i].function;i++)
\r
148 printf("babel %s %s\n %s\n",
\r
149 multifuncs[i].function,
\r
150 multifuncs[i].argnames,
\r
151 multifuncs[i].desc);
\r
154 printf ("\nFor functions which extract files, add \"-to <directory>\" to the command\n"
\r
155 "to set the output directory.\n"
\r
156 "The input file can be specified as \"-\" to read from standard input\n"
\r
157 "(This may only work for .iFiction files)\n");
\r
161 /* For story files, we end up reading the file in twice. This
\r
162 is unfortunate, but unavoidable, since we want to be all
\r
163 cross-platformy, so the first time we read it in, we
\r
164 do the read in text mode, and the second time, we do it in binary
\r
165 mode, and there are platforms where this makes a difference.
\r
168 if (strcmp(fn,"-"))
\r
170 fseek(f,0,SEEK_END);
\r
172 fseek(f,0,SEEK_SET);
\r
173 md=(char *)my_malloc(l,"Input file buffer");
\r
178 while(!feof(stdin))
\r
180 char *tt, mdb[1024];
\r
182 ii=fread(mdb,1,1024,stdin);
\r
183 tt=(char *)my_malloc(ll+ii,"file buffer");
\r
184 if (md) { memcpy(tt,md,ll); free(md); }
\r
185 memcpy(tt+ll,mdb,ii);
\r
188 if (ii<1024) break;
\r
192 if (strstr(md,"<?xml version=") && strstr(md,"<ifindex"))
\r
193 { /* appears to be an ifiction file */
\r
195 pp=strstr(md,"</ifindex>");
\r
196 if (pp) *(pp+10)=0;
\r
200 if (functions[i].ifiction)
\r
201 functions[i].ifiction(md);
\r
203 fprintf(stderr,"Error: option %s is not valid for iFiction files\n",
\r
208 if (strcmp(fn,"-"))
\r
214 { /* Appears to be a story */
\r
216 if (functions[i].story)
\r
218 if (strcmp(fn,"-")) lt=babel_init(argv[2]);
\r
219 else { lt=babel_init_raw(md,ll);
\r
227 if (!babel_get_authoritative() && strcmp(argv[1],"-format"))
\r
228 printf("Warning: Story format could not be positively identified. Guessing %s\n",lt);
\r
229 functions[i].story();
\r
233 else if (strcmp(argv[1],"-ifid")==0) /* IFID is calculable for all files */
\r
235 babel_md5_ifid(cwd,512);
\r
236 printf("IFID: %s\n",cwd);
\r
239 fprintf(stderr,"Error: Did not recognize format of story file\n");
\r
243 fprintf(stderr,"Error: option %s is not valid for story files\n",
\r