00001
00008
00009
00010 #include <stdlib.h>
00011 #include <stdio.h>
00012 #include <string.h>
00013 #include "zip.h"
00014 #include "NME.h"
00015 #include "NMEAutolink.h"
00016 #include "NMEEPub.h"
00017 #include "NE.h"
00018
00020 #define SIZE (8 * 1024 * 1024L)
00021
00022 #define kNMENEEndnoteError kNMEErr1stUser
00023
00024 static NMEBoolean debug = FALSE;
00025
00027 static NMEAutoconvert autoconverts[16];
00028
00030 static NMEInterwiki const interwikis[] =
00031 {
00032 {"Dictionary:",
00033 "http://www.dict.org/bin/Dict?Database=*&Form=Dict1&Strategy=*&Query="},
00034 {"Foldoc:", "http://www.foldoc.org/foldoc/foldoc.cgi?"},
00035 {"Google:", "http://www.google.com/search?q="},
00036 {"WhoIs:", "http://www.whois.sc/"},
00037 {"WikiPedia:", "http://en.wikipedia.org/wiki/"},
00038 {NULL, NULL}
00039 };
00040
00041 static void DisplayUsageAndExit(char const *progName, int status)
00042 {
00043 fprintf(stderr, "Usage: %s [options] -o epubFilename file1 ...\n"
00044 "Required arguments:\n"
00045 "-o epubFilename specified the EPUB file to create (e.g. book.epub)\n"
00046 "file1 ... NME files constituting the contents of the book\n"
00047 "Options:\n"
00048 "--1eol single eol as paragraph breaks\n"
00049 "--2eol double eol as paragraph breaks (default)\n"
00050 "--autocclink automatic conversion of camelCase words to links\n"
00051 "--autourllink automatic conversion of URLs to links\n"
00052 "--debug XML debug format, sublists outside list items\n"
00053 "--headernum1 numbering of level-1 headers\n"
00054 "--headernum2 numbering of level-2 headers\n",
00055 progName);
00056 exit(status);
00057 }
00058
00060 typedef struct
00061 {
00062 NMEOutputFormat *outputFormat;
00063 NE *ne;
00064
00065
00066 char const *filename;
00067 int titleSrcOffset;
00068
00069
00070 NEBoolean inImageMarkup;
00071 } HookData;
00072
00086 static NMEErr parHookTOC(NMEInt level,
00087 NMEInt item,
00088 NMEBoolean enter,
00089 NMEConstText markup,
00090 NMEInt srcIndex,
00091 NMEInt srcLineNumber,
00092 NMEContext *context,
00093 void *data)
00094 {
00095 HookData *d = (HookData *)data;
00096
00097 if (markup[0] == '=' && level == 1)
00098 if (enter)
00099 {
00100 NMEResetOutput(context);
00101 *d->outputFormat = NMEOutputFormatNull;
00102 d->outputFormat->space = " ";
00103 d->outputFormat->encodeCharFun = NULL;
00104 d->outputFormat->parHookFun = parHookTOC;
00105 d->outputFormat->hookData = data;
00106 d->titleSrcOffset = NMECurrentInputIndex(context);
00107 }
00108 else
00109 {
00110 NMEConstText output;
00111 NMEInt outputLength;
00112 char title[512], url[512];
00113
00114 NMECurrentOutput(context, &output, &outputLength);
00115 if (outputLength > 511)
00116 outputLength = 511;
00117 sprintf(title, "%.*s", outputLength, output);
00118 sprintf(url, "%s#h%d", d->filename, d->titleSrcOffset);
00119 NEAddTOCEntry(d->ne, title, url, 1);
00120
00121 *d->outputFormat = NMEOutputFormatNull;
00122 d->outputFormat->parHookFun = parHookTOC;
00123 d->outputFormat->hookData = data;
00124 }
00125
00126 return kNMEErrOk;
00127 }
00128
00143 static NMEErr spanHookImg(NMEInt level,
00144 NMEInt item,
00145 NMEBoolean enter,
00146 NMEConstText markup,
00147 NMEInt srcIndex,
00148 NMEInt srcLineNumber,
00149 NMEContext *context,
00150 void *data)
00151 {
00152 HookData *d = (HookData *)data;
00153
00154 if (!strcmp(markup, "{{"))
00155 d->inImageMarkup = enter;
00156
00157 return kNMEErrOk;
00158 }
00159
00169 static NMEErr encodeURL(NMEConstText link, NMEInt linkLen,
00170 NMEContext *context, void *data)
00171 {
00172 HookData *d = (HookData *)data;
00173
00174 if (d->inImageMarkup)
00175 NEAddOther(d->ne, link, linkLen, NULL);
00176
00177 return NMEAddRawString(link, linkLen, context);
00178 }
00179
00192 NMEErr PluginEndnote(NMEConstText name, NMEInt nameLen,
00193 NMEConstText data, NMEInt dataLen,
00194 NMEContext *context,
00195 void *userData)
00196 {
00197 NMEText buf, output;
00198 NMEInt bufSize, outputLen;
00199 NMEErr nmeerr;
00200 NEErr neerr;
00201 char const *refLink;
00202
00203 NMEGetTempMemory(context, &buf, &bufSize);
00204 nmeerr = NMEProcess(data, dataLen,
00205 buf, bufSize,
00206 kNMEProcessOptNoPreAndPost, "\n", &NMEOutputFormatOPSXHTML, 0,
00207 &output, &outputLen, NULL);
00208 if (nmeerr != kNMEErrOk)
00209 return nmeerr;
00210
00211 neerr = NEAddEndnote((NEPtr)userData,
00212 output, outputLen,
00213 ((NEPtr)userData)->currentDoc, -1,
00214 &refLink);
00215 if (neerr != kNEErrOk)
00216 return kNMENEEndnoteError;
00217
00218
00219 if (!NMEAddString(refLink, -1, '\0', context))
00220 return kNMEErrNotEnoughMemory;
00221
00222 return kNMEErrOk;
00223 }
00224
00241 NMEErr PluginMeta(NMEConstText name, NMEInt nameLen,
00242 NMEConstText data, NMEInt dataLen,
00243 NMEContext *context,
00244 void *userData)
00245 {
00246 NEPtr ne = (NEPtr)userData;
00247
00248
00249 while (dataLen > 0 && data[dataLen - 1] <= ' ' && data[dataLen - 1] >= '\0')
00250 dataLen--;
00251
00252 if (!strncmp(name, "title", nameLen))
00253 NEAddMetadata(ne, kNEMetaTitle, data, dataLen);
00254 else if (!strncmp(name, "author", nameLen))
00255 NEAddMetadata(ne, kNEMetaCreator, data, dataLen);
00256 else if (!strncmp(name, "identifier", nameLen))
00257 NEAddMetadata(ne, kNEMetaIdentifier, data, dataLen);
00258 else if (!strncmp(name, "language", nameLen))
00259 NEAddMetadata(ne, kNEMetaLanguage, data, dataLen);
00260 else if (!strncmp(name, "subject", nameLen))
00261 NEAddMetadata(ne, kNEMetaSubject, data, dataLen);
00262 else if (!strncmp(name, "description", nameLen))
00263 NEAddMetadata(ne, kNEMetaDescription, data, dataLen);
00264 else if (!strncmp(name, "publisher", nameLen))
00265 NEAddMetadata(ne, kNEMetaPublisher, data, dataLen);
00266 else if (!strncmp(name, "date", nameLen))
00267 NEAddMetadata(ne, kNEMetaDate, data, dataLen);
00268 else if (!strncmp(name, "source", nameLen))
00269 NEAddMetadata(ne, kNEMetaSource, data, dataLen);
00270 else if (!strncmp(name, "rights", nameLen))
00271 NEAddMetadata(ne, kNEMetaRights, data, dataLen);
00272 else if (!strncmp(name, "cover", nameLen))
00273 NESetCoverImage(ne, data, dataLen);
00274 return kNMEErrOk;
00275 }
00276
00299 NMEErr PluginGuide(NMEConstText name, NMEInt nameLen,
00300 NMEConstText data, NMEInt dataLen,
00301 NMEContext *context,
00302 void *userData)
00303 {
00304
00305 return kNMEErrOk;
00306 }
00307
00309 int main(int argc, char **argv)
00310 {
00311 char const *epubFilename = NULL;
00312 char epubFilenameStr[512];
00313 FILE *fp;
00314 NMEText src = NULL, buf, dest;
00315 NMEInt srcLen, destLen;
00316 NMEOutputFormat outputFormat;
00317 NMEInt options = kNMEProcessOptDefault | kNMEProcessOptXRef;
00318 NMEBoolean autoURLLink = FALSE, autoCCLink = FALSE;
00319 int i;
00320 int iFiles;
00321 char const *imgFilename;
00322 int imgFilenameLength;
00323 NEErr neerr;
00324 NMEErr nmeerr;
00325 NE ne;
00326 HookData hookData;
00327 NMEPlugin plugins[] =
00328 {
00329 {"endnote", kNMEPluginOptDefault, PluginEndnote, NULL},
00330 {"title", kNMEPluginOptDefault, PluginMeta, NULL},
00331 {"author", kNMEPluginOptDefault, PluginMeta, NULL},
00332 {"identifier", kNMEPluginOptDefault, PluginMeta, NULL},
00333 {"language", kNMEPluginOptDefault, PluginMeta, NULL},
00334 {"subject", kNMEPluginOptDefault, PluginMeta, NULL},
00335 {"description", kNMEPluginOptDefault, PluginMeta, NULL},
00336 {"publisher", kNMEPluginOptDefault, PluginMeta, NULL},
00337 {"date", kNMEPluginOptDefault, PluginMeta, NULL},
00338 {"source", kNMEPluginOptDefault, PluginMeta, NULL},
00339 {"rights", kNMEPluginOptDefault, PluginMeta, NULL},
00340 {"cover", kNMEPluginOptDefault, PluginMeta, NULL},
00341 {"guide", kNMEPluginOptDefault, PluginGuide, NULL},
00342 NMEPluginTableEnd
00343 };
00344
00345 for (i = 1; i < argc; i++)
00346 if (!strcmp(argv[i], "-o") && i + 1 < argc)
00347 epubFilename = argv[++i];
00348 else if (!strcmp(argv[i], "--1eol"))
00349 options |= kNMEProcessOptNoMultilinePar;
00350 else if (!strcmp(argv[i], "--2eol"))
00351 options &= ~kNMEProcessOptNoMultilinePar;
00352 else if (!strcmp(argv[i], "--autocclink"))
00353 autoCCLink = TRUE;
00354 else if (!strcmp(argv[i], "--autourllink"))
00355 autoURLLink = TRUE;
00356 else if (!strcmp(argv[i], "--headernum1"))
00357 options |= kNMEProcessOptH1Num;
00358 else if (!strcmp(argv[i], "--headernum2"))
00359 options |= kNMEProcessOptH2Num;
00360 else if (!strcmp(argv[i], "--debug"))
00361 debug = TRUE;
00362 else if (!strcmp(argv[i], "--strictcreole"))
00363 options |= kNMEProcessOptNoUnderline | kNMEProcessOptNoMonospace
00364 | kNMEProcessOptNoSubSuperscript | kNMEProcessOptNoIndentedPar
00365 | kNMEProcessOptNoDL | kNMEProcessOptVerbatimMono;
00366 else if (!strcmp(argv[i], "--help"))
00367 DisplayUsageAndExit(argv[0], 0);
00368 else if (argv[i][0] == '-')
00369 {
00370 fprintf(stderr, "Unknown option %s\n", argv[i]);
00371 DisplayUsageAndExit(argv[0], 1);
00372 }
00373 else
00374 break;
00375
00376 if (i == argc)
00377 {
00378 fprintf(stderr, "No document file.\n");
00379 DisplayUsageAndExit(argv[0], 1);
00380 }
00381
00382 iFiles = i;
00383
00384 if (!epubFilename && !debug)
00385 {
00386 strncpy(epubFilenameStr, argv[iFiles], 505);
00387 epubFilenameStr[505] = '\0';
00388 for (i = strlen(epubFilenameStr); i > 1 && epubFilenameStr[i] != '.'; i--)
00389 ;
00390 strcpy(epubFilenameStr + i, ".epub");
00391 epubFilename = epubFilenameStr;
00392 }
00393
00394 NEBegin(&ne, epubFilename);
00395
00396
00397 src = malloc(SIZE);
00398 buf = malloc(SIZE);
00399 if (!src || !buf)
00400 {
00401 fprintf(stderr, "Not enough memory.\n");
00402 exit(1);
00403 }
00404
00405
00406 outputFormat = NMEOutputFormatOPSXHTML;
00407
00408
00409 hookData.outputFormat = &outputFormat;
00410 hookData.ne = ≠
00411 hookData.titleSrcOffset = 0;
00412 hookData.inImageMarkup = FALSE;
00413 outputFormat.encodeURLFun = encodeURL;
00414 outputFormat.encodeURLData = (void *)&hookData;
00415 outputFormat.spanHookFun = spanHookImg;
00416 outputFormat.hookData = (void *)&hookData;
00417
00418 for (i = 0; ; i++)
00419 if (plugins[i].cb == PluginEndnote || plugins[i].cb == PluginMeta)
00420 plugins[i].userData = ≠
00421 else if (plugins[i].cb == NULL)
00422 break;
00423 outputFormat.plugins = plugins;
00424 outputFormat.interwikis = interwikis;
00425 if (autoCCLink || autoURLLink)
00426 {
00427 int n = 0;
00428 if (autoCCLink)
00429 autoconverts[n++].cb = NMEAutoconvertCamelCase;
00430 if (autoURLLink)
00431 autoconverts[n++].cb = NMEAutoconvertURL;
00432 outputFormat.autoconverts = autoconverts;
00433 }
00434 for (i = iFiles; i < argc; i++)
00435 {
00436
00437 fp = fopen(argv[i], "rb");
00438 if (!fp)
00439 {
00440 fprintf(stderr, "Cannot open file \"%s\".\n", argv[i]);
00441 exit(1);
00442 }
00443 srcLen = fread(src, 1, SIZE, fp);
00444 if (srcLen < 0)
00445 {
00446 free(src);
00447 exit(1);
00448 }
00449 fclose(fp);
00450
00451 ne.currentDoc = argv[i];
00452
00453 nmeerr = NMEProcess(src, srcLen,
00454 buf, SIZE,
00455 options, "\n", &outputFormat, 0,
00456 &dest, &destLen, NULL);
00457
00458 if (nmeerr != kNMEErrOk)
00459 {
00460 fprintf(stderr, "Conversion error %d\n", nmeerr);
00461 exit(1);
00462 }
00463
00464
00465 NENewFile(&ne, argv[i]);
00466 NEWriteToFile(&ne, dest, destLen);
00467 NECloseFile(&ne);
00468 NEAddPart(&ne, argv[i], FALSE);
00469 }
00470
00471
00472 imgFilename = NULL;
00473 for (;;)
00474 {
00475 char f[512];
00476 NEEnumOther(&ne, &imgFilename, &imgFilenameLength);
00477 if (!imgFilename)
00478 break;
00479 if (imgFilenameLength > 511)
00480 imgFilenameLength = 511;
00481 strncpy(f, imgFilename, imgFilenameLength);
00482 f[imgFilenameLength] = '\0';
00483 neerr = NEAddFile(&ne, f, f);
00484 if (neerr != kNEErrOk)
00485 {
00486 fprintf(stderr, "Cannot add image \"%s\"\n", f);
00487 exit(1);
00488 }
00489 }
00490
00491
00492 outputFormat = NMEOutputFormatTextCompact;
00493 outputFormat.parHookFun = parHookTOC;
00494 outputFormat.hookData = (void *)&hookData;
00495
00496 for (i = iFiles; i < argc; i++)
00497 {
00498
00499 fp = fopen(argv[i], "rb");
00500 if (!fp)
00501 {
00502 fprintf(stderr, "Cannot open file \"%s\".\n", argv[i]);
00503 exit(1);
00504 }
00505 srcLen = fread(src, 1, SIZE, fp);
00506 if (srcLen < 0)
00507 {
00508 free(src);
00509 exit(1);
00510 }
00511 fclose(fp);
00512
00513 hookData.filename = argv[i];
00514 nmeerr = NMEProcess(src, srcLen,
00515 buf, SIZE,
00516 kNMEProcessOptDefault, "\n", &outputFormat, 0,
00517 &dest, &destLen, NULL);
00518
00519 if (nmeerr != kNMEErrOk)
00520 {
00521 fprintf(stderr, "Conversion error %d\n", nmeerr);
00522 exit(1);
00523 }
00524 }
00525
00526 NEMakeCover(&ne);
00527
00528 NEEnd(&ne);
00529
00530
00531 free((void *)buf);
00532 free((void *)src);
00533
00534 return 0;
00535 }