--- /dev/null
+/* babel.c The babel command line program\r
+ * (c) 2006 By L. Ross Raszewski\r
+ *\r
+ * This code is freely usable for all purposes.\r
+ *\r
+ * This work is licensed under the Creative Commons Attribution2.5 License.\r
+ * To view a copy of this license, visit\r
+ * http://creativecommons.org/licenses/by/2.5/ or send a letter to\r
+ * Creative Commons,\r
+ * 543 Howard Street, 5th Floor,\r
+ * San Francisco, California, 94105, USA.\r
+ *\r
+ * This file depends upon misc.c and babel.h\r
+ *\r
+ * This file exports one variable: char *rv, which points to the file name\r
+ * for an ifiction file. This is used only by babel_ifiction_verify\r
+ */\r
+\r
+#include "babel.h"\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+int chdir(const char *);\r
+char *getcwd(char *, int);\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+char *fn;\r
+\r
+/* checked malloc function */\r
+void *my_malloc(int, char *);\r
+\r
+/* babel performs several fundamental operations, which are specified\r
+ by command-line objects. Each of these functions corresponds to\r
+ a story function (defined in babel_story_functions.c) or an\r
+ ifiction function (defined in babel_ifiction_functions.c) or both.\r
+ These are the types of those functions.\r
+*/\r
+\r
+typedef void (*story_function)(void);\r
+typedef void (*ifiction_function)(char *);\r
+typedef void (*multi_function)(char **, char *, int);\r
+/* This structure tells babel what to do with its command line arguments.\r
+ if either of story or ifiction are NULL, babel considers this command line\r
+ option inappropriate for that type of file.\r
+*/\r
+struct function_handler {\r
+ char *function; /* the textual command line option */\r
+ story_function story; /* handler for story files */\r
+ ifiction_function ifiction; /* handler for ifiction files */\r
+ char *desc; /* Textual description for help text */\r
+ };\r
+\r
+struct multi_handler {\r
+ char *function;\r
+ char *argnames;\r
+ multi_function handler;\r
+ int nargsm;\r
+ int nargsx;\r
+ char *desc;\r
+ };\r
+/* This is an array of function_handler objects which specify the legal\r
+ arguments. It is terminated by a function_handler with a NULL function\r
+ */\r
+static struct function_handler functions[] = {\r
+ { "-ifid", babel_story_ifid, babel_ifiction_ifid, "Deduce IFID"},\r
+ { "-format", babel_story_format, NULL, "Deduce story format" },\r
+ { "-ifiction", babel_story_ifiction, NULL, "Extract iFiction file" },\r
+ { "-meta", babel_story_meta, NULL, "Print story metadata" },\r
+ { "-identify", babel_story_identify, NULL, "Describe story file" },\r
+ { "-cover", babel_story_cover, NULL, "Extract cover art" },\r
+ { "-story", babel_story_story, NULL, "Extract story file (ie. from a blorb)" },\r
+ { "-verify", NULL, babel_ifiction_verify, "Verify integrity of iFiction file" },\r
+ { "-lint", NULL, babel_ifiction_lint, "Verify style of iFiction file" },\r
+ { "-fish", babel_story_fish, babel_ifiction_fish, "Extract all iFiction and cover art"},\r
+ { "-unblorb", babel_story_unblorb, NULL, "As -fish, but also extract story files"},\r
+ { NULL, NULL, NULL }\r
+ };\r
+static struct multi_handler multifuncs[] = {\r
+ { "-blorb", "<storyfile> <ifictionfile> [<cover art>]", babel_multi_blorb, 2, 3, "Bundle story file and (sparse) iFiction into blorb" },\r
+ { "-blorbs", "<storyfile> <ifictionfile> [<cover art>]", babel_multi_blorb1, 2, 3, "Bundle story file and (sparse) iFiction into sensibly-named blorb" },\r
+ { "-complete", "<storyfile> <ifictionfile>", babel_multi_complete, 2, 2, "Create complete iFiction file from sparse iFiction" },\r
+ { NULL, NULL, NULL, 0, 0, NULL }\r
+};\r
+\r
+int main(int argc, char **argv)\r
+{\r
+ char *todir=".";\r
+ char cwd[512];\r
+ int ok=1,i, l, ll;\r
+ FILE *f;\r
+ char *md=NULL;\r
+ /* Set the input filename. Note that if this is invalid, babel should\r
+ abort before anyone notices\r
+ */\r
+ fn=argv[2];\r
+\r
+ if (argc < 3) ok=0;\r
+ /* Detect the presence of the "-to <directory>" argument.\r
+ */\r
+ if (ok && argc >=5 && strcmp(argv[argc-2], "-to")==0)\r
+ {\r
+ todir=argv[argc-1];\r
+ argc-=2;\r
+ }\r
+ if (ok) for(i=0;multifuncs[i].function;i++)\r
+ if (strcmp(argv[1],multifuncs[i].function)==0 &&\r
+ argc>= multifuncs[i].nargsm+2 &&\r
+ argc <= multifuncs[i].nargsx+2)\r
+ {\r
+\r
+ multifuncs[i].handler(argv+2, todir, argc-2);\r
+ exit(0);\r
+ }\r
+\r
+ if (argc!=3) ok=0;\r
+\r
+ /* Find the apropriate function_handler */\r
+ if (ok) {\r
+ for(i=0;functions[i].function && strcmp(functions[i].function,argv[1]);i++);\r
+ if (!functions[i].function) ok=0;\r
+ else if (strcmp(fn,"-")) {\r
+ f=fopen(argv[2],"r");\r
+ if (!f) ok=0;\r
+ }\r
+ }\r
+\r
+ /* Print usage error if anything has gone wrong */\r
+ if (!ok)\r
+ {\r
+ printf("%s: Treaty of Babel Analysis Tool (%s, %s)\n"\r
+ "Usage:\n", argv[0],BABEL_VERSION, TREATY_COMPLIANCE);\r
+ for(i=0;functions[i].function;i++)\r
+ {\r
+ if (functions[i].story)\r
+ printf(" babel %s <storyfile>\n",functions[i].function);\r
+ if (functions[i].ifiction)\r
+ printf(" babel %s <ifictionfile>\n",functions[i].function);\r
+ printf(" %s\n",functions[i].desc);\r
+ }\r
+ for(i=0;multifuncs[i].function;i++)\r
+ {\r
+ printf("babel %s %s\n %s\n",\r
+ multifuncs[i].function,\r
+ multifuncs[i].argnames,\r
+ multifuncs[i].desc);\r
+ }\r
+\r
+ printf ("\nFor functions which extract files, add \"-to <directory>\" to the command\n"\r
+ "to set the output directory.\n"\r
+ "The input file can be specified as \"-\" to read from standard input\n"\r
+ "(This may only work for .iFiction files)\n");\r
+ return 1;\r
+ }\r
+\r
+ /* For story files, we end up reading the file in twice. This\r
+ is unfortunate, but unavoidable, since we want to be all\r
+ cross-platformy, so the first time we read it in, we\r
+ do the read in text mode, and the second time, we do it in binary\r
+ mode, and there are platforms where this makes a difference.\r
+ */\r
+ ll=0;\r
+ if (strcmp(fn,"-"))\r
+ {\r
+ fseek(f,0,SEEK_END);\r
+ l=ftell(f)+1;\r
+ fseek(f,0,SEEK_SET);\r
+ md=(char *)my_malloc(l,"Input file buffer");\r
+ fread(md,1,l-1,f);\r
+ md[l-1]=0;\r
+ }\r
+ else\r
+ while(!feof(stdin))\r
+ {\r
+ char *tt, mdb[1024];\r
+ int ii;\r
+ ii=fread(mdb,1,1024,stdin);\r
+ tt=(char *)my_malloc(ll+ii,"file buffer");\r
+ if (md) { memcpy(tt,md,ll); free(md); }\r
+ memcpy(tt+ll,mdb,ii);\r
+ md=tt;\r
+ ll+=ii;\r
+ if (ii<1024) break;\r
+ }\r
+\r
+\r
+ if (strstr(md,"<?xml version=") && strstr(md,"<ifindex"))\r
+ { /* appears to be an ifiction file */\r
+ char *pp;\r
+ pp=strstr(md,"</ifindex>");\r
+ if (pp) *(pp+10)=0;\r
+ getcwd(cwd,512);\r
+ chdir(todir);\r
+ l=0;\r
+ if (functions[i].ifiction)\r
+ functions[i].ifiction(md);\r
+ else\r
+ fprintf(stderr,"Error: option %s is not valid for iFiction files\n",\r
+ argv[1]);\r
+ chdir(cwd);\r
+ }\r
+\r
+ if (strcmp(fn,"-"))\r
+ {\r
+ free(md);\r
+ fclose(f);\r
+ }\r
+ if (l)\r
+ { /* Appears to be a story */\r
+ char *lt;\r
+ if (functions[i].story)\r
+ {\r
+ if (strcmp(fn,"-")) lt=babel_init(argv[2]);\r
+ else { lt=babel_init_raw(md,ll);\r
+ free(md);\r
+ }\r
+\r
+ if (lt)\r
+ {\r
+ getcwd(cwd,512);\r
+ chdir(todir);\r
+ if (!babel_get_authoritative() && strcmp(argv[1],"-format"))\r
+ printf("Warning: Story format could not be positively identified. Guessing %s\n",lt);\r
+ functions[i].story();\r
+\r
+ chdir(cwd);\r
+ }\r
+ else if (strcmp(argv[1],"-ifid")==0) /* IFID is calculable for all files */\r
+ {\r
+ babel_md5_ifid(cwd,512);\r
+ printf("IFID: %s\n",cwd);\r
+ }\r
+ else\r
+ fprintf(stderr,"Error: Did not recognize format of story file\n");\r
+ babel_release();\r
+ }\r
+ else\r
+ fprintf(stderr,"Error: option %s is not valid for story files\n",\r
+ argv[1]);\r
+ } \r
+\r
+ return 0;\r
+}\r