00001
00007
00008
00009 #include "NME.h"
00010
00011 #define kMaxNesting 8
00012
00013
00014 enum
00015 {
00016 kNMEListNumUL = -100,
00017 kNMEListNumDT,
00018 kNMEListNumDD,
00019 kNMEListIndented,
00020 kNMEListNumTableCell,
00021 kNMEListNumTableHCell
00022 };
00023
00025 #define isBlank(c) ((c) == ' ' || (c) == '\t')
00026
00028 #define isEol(c) ((c) == '\r' || (c) == '\n')
00029
00031 #define isDigit(c) ((c) >= '0' && (c) <= '9')
00032
00034 #define isAlphaNum(c) \
00035 ((c) >= 'a' && (c) <= 'z' || (c) >= 'A' && (c) <= 'Z' || isDigit(c))
00036
00038 #define isFirstUTF8Byte(c) \
00039 (((c) & 0x80) == 0 || ((c) & 0xe0) == 0xc0 || ((c) & 0xf0) == 0xe0)
00040
00042 #define kMaxNumberedHeadingLevels 2
00043
00045 #define kMaxSectionLevels 4
00046
00048 #define kTabWidth 4
00049
00051 #define CheckError(c) \
00052 do { err = (c); if (err != kNMEErrOk) return err; } while (0)
00053
00057 typedef enum NMEState
00058 {
00059 kNMEStatePar,
00060 kNMEStatePre,
00061 kNMEStateHeading,
00062 kNMEStateParAfterEol,
00063 kNMEStatePreAfterEol,
00064 kNMEStateBetweenPar
00065 } NMEState;
00066
00068 typedef enum NMEToken
00069 {
00070 kNMETokenChar,
00071 kNMETokenSpace,
00072 kNMETokenTab,
00073 kNMETokenEOL,
00074 kNMETokenHeading,
00075 kNMETokenLineBreak,
00076 kNMETokenLI,
00077 kNMETokenDD,
00078 kNMETokenTableCell,
00079 kNMETokenTableHCell,
00080 kNMETokenHR,
00081 kNMETokenPre,
00082 kNMETokenStyle,
00083 kNMETokenLinkBegin,
00084 kNMETokenLinkEnd,
00085 kNMETokenImageBegin,
00086 kNMETokenImageEnd,
00087 kNMETokenPlugin,
00088 kNMETokenPluginBlock,
00089 kNMETokenPlaceholder,
00090 kNMETokenPlaceholderBlock
00091 } NMEToken;
00092
00094 typedef enum NMEStyle
00095 {
00096 kNMEStyleBold = 0,
00097
00098 kNMEStyleItalic,
00099 kNMEStyleUnderline,
00100 kNMEStyleSuperscript,
00101 kNMEStyleSubscript,
00102 kNMEStyleMonospace,
00103 kNMEStyleVerbatim,
00104 kNMEStyleLink,
00105 kNMEStyleImage,
00106 kNMEStylesCount
00107 } NMEStyle;
00108
00110 struct NMEContextStruct
00111 {
00112 NMEText dest;
00113 NMEInt destLen;
00114
00115 NMEInt destLenUCS16;
00116
00117 NMEText src;
00118 NMEInt srcIndex;
00119 NMEInt srcIndexOffset;
00120 NMEInt srcLen;
00121
00122 NMEInt bufSize;
00123
00124 NMEInt currentIndent;
00125 NMEInt col;
00126
00127 NMEInt listNum[kMaxNesting];
00128 NMEInt nesting;
00129
00130 NMEOutputFormat const *outputFormat;
00131 NMEConstText eol;
00132 NMEChar ctrlChar;
00133 NMEInt options;
00134
00135 NMEInt fontSize;
00136
00137 NMEInt level;
00138 NMEInt item;
00139 NMEInt linkOffset;
00140 NMEInt linkLength;
00141
00142 NMEBoolean xref;
00143 };
00144
00146 #define setContext(c, l, i) do { (c).level = l; (c).item = (i) < 0 ? 0 : (i); } while (0)
00147
00153 static void skipBlanks(NMEConstText src, NMEInt srcLen, NMEInt *i)
00154 {
00155 while (*i < srcLen && isBlank(src[*i]))
00156 (*i)++;
00157 }
00158
00164 static void execOperator(NMEInt stack[], NMEInt *stackDepth, NMEChar op)
00165 {
00166 switch (op)
00167 {
00168 case '+':
00169 stack[*stackDepth-2] += stack[*stackDepth-1];
00170 break;
00171 case '-':
00172 stack[*stackDepth-2] -= stack[*stackDepth-1];
00173 break;
00174 case '*':
00175 stack[*stackDepth-2] *= stack[*stackDepth-1];
00176 break;
00177 case '/':
00178 stack[*stackDepth-2] /= stack[*stackDepth-1];
00179 break;
00180 case '=':
00181 stack[*stackDepth-2] = stack[*stackDepth-2] == stack[*stackDepth-1];
00182 break;
00183 case '!':
00184 stack[*stackDepth-2] = stack[*stackDepth-2] != stack[*stackDepth-1];
00185 break;
00186 case '<':
00187 stack[*stackDepth-2] = stack[*stackDepth-2] < stack[*stackDepth-1];
00188 break;
00189 case '>':
00190 stack[*stackDepth-2] = stack[*stackDepth-2] > stack[*stackDepth-1];
00191 break;
00192 case '&':
00193 if (stack[*stackDepth-2] != 0)
00194 stack[*stackDepth-2] = stack[*stackDepth-1];
00195 break;
00196 case '|':
00197 if (stack[*stackDepth-2] == 0)
00198 stack[*stackDepth-2] = stack[*stackDepth-1];
00199 break;
00200 }
00201 (*stackDepth)--;
00202 }
00203
00211 static NMEInt evalExpression(NMEConstText src, NMEInt srcLen,
00212 NMEContext const *context)
00213 {
00214 #define kExprStackSize 16
00215 #define kExprErrorValue 1
00216 static struct
00217 {
00218 NMEChar op;
00219 NMEInt priority;
00220 } const opList[] =
00221 {
00222 {'|', 1},
00223 {'&', 2},
00224 {'=', 3}, {'!', 3}, {'<', 3}, {'>', 3},
00225 {'+', 4}, {'-', 4},
00226 {'*', 5}, {'/', 5},
00227 {'\0', 0}
00228 };
00229 NMEInt stack[kExprStackSize];
00230 NMEInt stackDepth;
00231 NMEInt opStack[kExprStackSize];
00232
00233 NMEInt opStackDepth;
00234 NMEInt i, j;
00235
00236 for (i = stackDepth = opStackDepth = 0; ; )
00237 {
00238 skipBlanks(src, srcLen, &i);
00239
00240 if (i >= srcLen)
00241 return 1;
00242
00243
00244 while (i < srcLen && src[i] == '(' && opStackDepth < kExprStackSize)
00245 {
00246 opStack[opStackDepth++] = -1;
00247 i++;
00248 skipBlanks(src, srcLen, &i);
00249 }
00250
00251
00252 if (isDigit(src[i]))
00253 for (stack[stackDepth] = 0; i < srcLen && isDigit(src[i]); i++)
00254 stack[stackDepth] = 10 * stack[stackDepth] + src[i] - '0';
00255 else
00256 switch (src[i++])
00257 {
00258 case 'l':
00259 stack[stackDepth] = context->level;
00260 break;
00261 case 'i':
00262 stack[stackDepth] = context->item;
00263 break;
00264 case 's':
00265 stack[stackDepth] = context->fontSize;
00266 break;
00267 case 'o':
00268 stack[stackDepth] = context->srcIndex;
00269 break;
00270 case 'p':
00271 stack[stackDepth] = context->destLen;
00272 break;
00273 case 'x':
00274 stack[stackDepth] = context->xref;
00275 break;
00276 default:
00277 if (src[i - 1] >= 'A' && src[i - 1] <= 'Z')
00278 {
00279
00280 if (context->outputFormat->getVarFun)
00281 stack[stackDepth]
00282 = context->outputFormat->getVarFun(src[i - 1],
00283 context->outputFormat->getVarData);
00284 else
00285 stack[stackDepth] = 0;
00286 }
00287 else
00288 return kExprErrorValue;
00289 }
00290 stackDepth++;
00291
00292 skipBlanks(src, srcLen, &i);
00293
00294
00295 if (i >= srcLen)
00296 {
00297
00298 for ( ; opStackDepth > 0; opStackDepth--)
00299 if (opStack[opStackDepth - 1] >= 0)
00300 execOperator(stack, &stackDepth,
00301 opList[opStack[opStackDepth - 1]].op);
00302 return stack[0];
00303 }
00304
00305
00306 while (i < srcLen && src[i] == ')')
00307 {
00308
00309 for ( ; opStackDepth > 0 && opStack[opStackDepth - 1] >= 0; opStackDepth--)
00310 execOperator(stack, &stackDepth,
00311 opList[opStack[opStackDepth - 1]].op);
00312 if (opStackDepth > 0)
00313 opStackDepth--;
00314
00315
00316 i++;
00317 skipBlanks(src, srcLen, &i);
00318 }
00319
00320
00321 for (j = 0; opList[j].op && src[i] != opList[j].op; j++)
00322 ;
00323 if (!opList[j].op)
00324 return kExprErrorValue;
00325
00326
00327 for ( ; opStackDepth > 0
00328 && opStack[opStackDepth - 1] >= 0
00329 && opList[j].priority <= opList[opStack[opStackDepth - 1]].priority;
00330 opStackDepth--)
00331 execOperator(stack, &stackDepth, opList[opStack[opStackDepth - 1]].op);
00332
00333
00334 if (opStackDepth >= kExprStackSize)
00335 return kExprErrorValue;
00336
00337
00338 opStack[opStackDepth++] = j;
00339
00340
00341 i++;
00342 }
00343 }
00344
00345 NMEBoolean NMEAddString(NMEConstText str,
00346 NMEInt strLen,
00347 NMEChar ctrlChar,
00348 NMEContext *context)
00349 {
00350 NMEInt k;
00351
00352 if (!str)
00353 return TRUE;
00354
00355 if (strLen < 0)
00356 for (strLen = 0; str[strLen]; strLen++)
00357 ;
00358
00359 for (k = 0; k < strLen; )
00360 if (context->destLen
00361 + (str[k] == '\n' ? (context->eol[1] ? 1 : 0)
00362 + context->currentIndent : 0)
00363 >= context->bufSize)
00364 return FALSE;
00365 else if (str[k] == '\n')
00366 {
00367 NMEInt i;
00368
00369 context->dest[context->destLen++] = context->eol[0];
00370 context->destLenUCS16++;
00371 if (context->eol[1])
00372 {
00373 context->dest[context->destLen++] = context->eol[1];
00374 context->destLenUCS16++;
00375 }
00376 k++;
00377 for (i = 0; i < context->currentIndent; i++)
00378 {
00379 context->dest[context->destLen++] = ' ';
00380 context->destLenUCS16++;
00381 }
00382 context->col = context->currentIndent;
00383 }
00384 else if (k + 2 < strLen
00385 && str[k] == ctrlChar
00386 && (str[k + 1] == '{' || str[k + 1] == ctrlChar && str[k + 2] == '{'))
00387 {
00388 NMEBoolean replicate;
00389 NMEText repStr;
00390 NMEInt len, result, i, repStrLen, col0, destLenUCS160;
00391
00392 replicate = str[k + 1] == ctrlChar;
00393 if (replicate)
00394 k++;
00395 for (k += 2, len = 0; k + len < strLen && str[k + len] != '}'; len++)
00396 ;
00397 if (k + len >= strLen)
00398 return TRUE;
00399 result = evalExpression(str + k, len, context);
00400 k += len + 1;
00401 if (replicate)
00402 {
00403
00404 for (len = 0;
00405 k + len + 1 < strLen
00406 && (str[k + len] != ctrlChar
00407 || str[k + len + 1] != ctrlChar);
00408 len++)
00409 ;
00410
00411
00412
00413 repStr = context->dest + context->destLen;
00414 destLenUCS160 = context->destLenUCS16;
00415 col0 = context->col;
00416 if (!NMEAddString(str + k, len, context->ctrlChar, context))
00417 return FALSE;
00418 repStrLen = context->dest + context->destLen - repStr;
00419 context->destLen = repStr - context->dest;
00420 context->destLenUCS16 = destLenUCS160;
00421 context->col = col0;
00422
00423
00424 if (result > 100)
00425 result = 100;
00426 if (result > 0 && context->destLen + result * repStrLen > context->bufSize)
00427 return FALSE;
00428 for (; result > 0; result--)
00429 {
00430 for (i = 0; i < repStrLen; i++)
00431 {
00432 context->dest[context->destLen++] = repStr[i];
00433 if (isFirstUTF8Byte(repStr[i]))
00434 context->destLenUCS16++;
00435 }
00436 context->col += repStrLen;
00437 }
00438
00439 k += len + 2;
00440 }
00441 else
00442 {
00443
00444 if (context->destLen + 12 > context->bufSize)
00445 return FALSE;
00446 if (result < 0)
00447 {
00448 context->dest[context->destLen++] = '-';
00449 context->destLenUCS16++;
00450 result = -result;
00451 context->col++;
00452 }
00453 for (i = 1000000000; i >= 1; i /= 10)
00454 if (result >= i || i == 1)
00455 {
00456 context->dest[context->destLen++] = '0' + (result / i) % 10;
00457 context->destLenUCS16++;
00458 context->col++;
00459 }
00460 }
00461 }
00462 else if (k + 2 < strLen && str[k] == ctrlChar && str[k + 1] == 'L')
00463 {
00464 NMEConstText str = NMECurrentListNesting(context);
00465 NMEInt i;
00466
00467 if (context->destLen + kMaxNesting > context->bufSize)
00468 return FALSE;
00469 for (i = 0; str[i]; i++)
00470 {
00471 context->dest[context->destLen++] = str[i];
00472 context->destLenUCS16++;
00473 context->col++;
00474 }
00475 k += 2;
00476 }
00477 else
00478 {
00479 if (isFirstUTF8Byte(str[k]))
00480 context->destLenUCS16++;
00481 context->dest[context->destLen++] = str[k++];
00482 context->col++;
00483 }
00484
00485 return TRUE;
00486 }
00487
00488 NMEErr NMECopySource(NMEInt length,
00489 NMEBoolean copy,
00490 NMEBoolean encodeChar,
00491 NMEContext *context)
00492 {
00493 if (context->srcIndexOffset + context->srcIndex + length > context->srcLen)
00494 length = context->srcLen - (context->srcIndexOffset + context->srcIndex);
00495 if (copy)
00496 {
00497 NMEInt i;
00498 NMEErr err;
00499
00500 if (encodeChar && context->outputFormat->encodeCharFun)
00501 {
00502 NMEEncodeCharFun fun = context->outputFormat->encodeCharFun;
00503 void *data = context->outputFormat->encodeCharData;
00504
00505 for (i = context->srcIndex; i < context->srcIndex + length; )
00506 CheckError(fun(context->src, context->srcLen, &i, context, data));
00507 }
00508 else
00509 {
00510 NMEConstText s = context->src + context->srcIndex;
00511 NMEText d = context->dest + context->destLen;
00512
00513 if (context->destLen + length > context->bufSize)
00514 return kNMEErrNotEnoughMemory;
00515
00516 for (i = 0; i < length; i++)
00517 {
00518 d[i] = s[i];
00519 if (isFirstUTF8Byte(s[i]))
00520 context->destLenUCS16++;
00521 }
00522 context->srcIndex += length;
00523 context->destLen += length;
00524 }
00525 }
00526
00527 context->srcIndex += length;
00528 context->col = 0;
00529 return kNMEErrOk;
00530 }
00531
00538 static NMEErr checkWordwrap(NMEContext *context,
00539 NMEOutputFormat const *outputFormat)
00540 {
00541 if (outputFormat && outputFormat->textWidth > 0
00542 && context->col >= outputFormat->textWidth)
00543 {
00544
00545
00546 NMEInt i, j, dist;
00547 NMEWordwrapPermission perm;
00548
00549 perm = kNMEWordwrapNo;
00550 if (outputFormat->wordwrapPermFun)
00551 {
00552
00553 for (i = context->destLen - 1;
00554 i >= 0 && !isEol(context->dest[i]);
00555 i--)
00556 {
00557 perm = outputFormat->wordwrapPermFun(context->dest, context->destLen, i,
00558 outputFormat->wordwrapPermData);
00559 if (perm != kNMEWordwrapNo)
00560 break;
00561 }
00562 }
00563 else
00564 {
00565
00566 for (i = context->destLen - 1;
00567 i >= 0 && !isEol(context->dest[i]);
00568 i--)
00569 if (isBlank(context->dest[i]))
00570 {
00571 perm = kNMEWordwrapReplaceChar;
00572 break;
00573 }
00574 }
00575
00576
00577 if (perm == kNMEWordwrapNo)
00578 return kNMEErrOk;
00579
00580
00581 dist = (context->eol[1] ? 2 : 1)
00582 + (perm == kNMEWordwrapReplaceChar ? -1 : 0)
00583 + context->currentIndent;
00584 if (dist > 0)
00585 {
00586 if (context->destLen + dist > context->bufSize)
00587 return kNMEErrNotEnoughMemory;
00588 for (j = context->destLen - 1; j > i; j--)
00589 context->dest[j + dist] = context->dest[j];
00590 context->destLen += dist;
00591 context->destLenUCS16 += dist;
00592 }
00593
00594
00595 if (perm == kNMEWordwrapInsert)
00596 i++;
00597 context->dest[i++] = context->eol[0];
00598 if (context->eol[1])
00599 context->dest[i++] = context->eol[1];
00600 for (j = 0; j < context->currentIndent; j++)
00601 context->dest[i++] = ' ';
00602 context->col = context->destLen - i + context->currentIndent;
00603 }
00604
00605 return kNMEErrOk;
00606 }
00607
00609 static NMEEncodeCharDict const htmlCharDict[] =
00610 {
00611 {'<', "<"},
00612 {'>', ">"},
00613 {'"', """},
00614 {'&', "&"},
00615 {0, NULL}
00616 };
00617
00619 static NMEEncodeCharDict const latexCharDict[] =
00620 {
00621 {'#', "\\#"},
00622 {'^', "$\\,\\hat{}\\,$"},
00623 {'~', "$\\,\\tilde{}\\,$"},
00624 {'\\', "$\\backslash$"},
00625 {'|', "$|$"},
00626 {'\'', "\'{}"},
00627 {'`', "`{}"},
00628 {'<', "$<$"},
00629 {'>', "$>$"},
00630 {'{', "\\{"},
00631 {'}', "\\}"},
00632 {0, NULL}
00633 };
00634
00635 NMEErr NMEEncodeCharFunDict(NMEConstText src, NMEInt srcLen, NMEInt *srcIx,
00636 NMEContext *context, void *data)
00637 {
00638 NMEInt i;
00639 (void)srcLen;
00640
00641 for (i = 0; ((NMEEncodeCharDict const *)data)[i].str; i++)
00642 if (src[*srcIx] == ((NMEEncodeCharDict const *)data)[i].ch)
00643 {
00644 if (!NMEAddString(((NMEEncodeCharDict const *)data)[i].str, -1,
00645 context->ctrlChar, context))
00646 return kNMEErrNotEnoughMemory;
00647 (*srcIx)++;
00648 return kNMEErrOk;
00649 }
00650 if (!NMEAddString(&src[(*srcIx)++], 1, context->ctrlChar, context))
00651 return kNMEErrNotEnoughMemory;
00652 return kNMEErrOk;
00653 }
00654
00665 NMEErr encodeCharFunNME(NMEConstText src, NMEInt srcLen, NMEInt *srcIx,
00666 NMEContext *context, void *data)
00667 {
00668 NMEInt i;
00669 NMEConstText output;
00670 NMEInt outputLength;
00671 NMEChar prev, str[2];
00672 static const struct
00673 {
00674 NMEChar ch;
00675 NMEChar prev;
00677 } dict[] =
00678 {
00679 {'*', '\n'},
00680 {'#', '\n'},
00681 {';', '\n'},
00682 {':', '\n'},
00683 {'=', '\n'},
00684 {'-', '\n'},
00685 {'*', '*'},
00686 {'/', '/'},
00687 {'#', '#'},
00688 {'_', '_'},
00689 {'^', '^'},
00690 {',', ','},
00691 {'[', '['},
00692 {']', ']'},
00693 {'{', '{'},
00694 {'}', '}'},
00695 {'<', '<'},
00696 {'>', '>'},
00697 {'\\', '\\'},
00698 {'~', '\0'},
00699 {'|', '\0'},
00700 {0, 0}
00701 };
00702 (void)srcLen;
00703 (void)data;
00704
00705
00706 NMECurrentOutput(context, &output, &outputLength);
00707 prev = outputLength > 0 ? output[outputLength - 1] : '\n';
00708 for (i = outputLength - 1; i >= 0 && isBlank(output[i] == ' '); i--)
00709 ;
00710 if (i < 0 || isEol(output[i]))
00711 prev = '\n';
00712
00713
00714 for (i = 0; dict[i].ch; i++)
00715 if (src[*srcIx] == dict[i].ch && (!dict[i].prev || prev == dict[i].prev))
00716 {
00717 str[0] = '~';
00718 str[1] = dict[i].ch;
00719 if (!NMEAddString(str, 2, '\0', context))
00720 return kNMEErrNotEnoughMemory;
00721 (*srcIx)++;
00722 return kNMEErrOk;
00723 }
00724 if (!NMEAddString(&src[(*srcIx)++], 1, '\0', context))
00725 return kNMEErrNotEnoughMemory;
00726 return kNMEErrOk;
00727 }
00728
00729 NMEOutputFormat const NMEOutputFormatText =
00730 {
00731 " ",
00732 3,
00733 10,
00734 '%',
00735 "", "",
00736 4,
00737 "%%{4-l} %%%%{i>0}%{i}. %%", "\n\n",
00738 "", "\n\n",
00739 "\n",
00740 "", "\n",
00741 "", "\n",
00742 "", "%%{l=1}\n%%",
00743 "%%{3*l-2} %%- ", "\n",
00744 "", "%%{l=1}\n%%",
00745 "%%{3*l-3} %%%{i}. ", "\n",
00746 "", "%%{l=1}\n%%",
00747 "%%{3*l-3} %%", "\n",
00748 NULL,
00749 "%%{3*l-1} %%", "\n",
00750 "", "%%{l=1}\n%%",
00751 "%%{3*l} %%", "\n",
00752 "", "\n",
00753 "", "\n",
00754 "", "\t",
00755 "", "\t",
00756 "%%{10}-%%\n\n",
00757 "", "",
00758 "", "",
00759 "", "",
00760 "", "",
00761 "", "",
00762 "", "",
00763 "", "", NULL, FALSE,
00764 "", "", NULL, FALSE, FALSE,
00765 NULL,
00766 NULL, NULL,
00767 NULL, NULL,
00768 NULL, NULL,
00769 70, NULL, NULL,
00770 NULL, NULL,
00771 NULL, NULL, NULL, NULL,
00772 NULL,
00773 NULL,
00774 NULL, NULL
00775 };
00776
00777 NMEOutputFormat const NMEOutputFormatTextCompact =
00778 {
00779 " ",
00780 3,
00781 10,
00782 '%',
00783 "", "",
00784 4,
00785 "%%{p>0}\n%%%%{4-l} %%%%{i>0}%{i}. %%", "\n",
00786 "", "\n",
00787 "\n",
00788 "", "",
00789 "", "\n",
00790 "", "%%{l=1}%%",
00791 "%%{3*l-2} %%- ", "\n",
00792 "", "%%{l=1}%%",
00793 "%%{3*l-3} %%%{i}. ", "\n",
00794 "", "%%{l=1}%%",
00795 "%%{3*l-3} %%", "\n",
00796 NULL,
00797 "%%{3*l-1} %%", "\n",
00798 "", "%%{l=1}%%",
00799 "%%{3*l} %%", "\n",
00800 "", "",
00801 "", "\n",
00802 "", "\t",
00803 "", "\t",
00804 "%%{10}-%%\n",
00805 "", "",
00806 "", "",
00807 "", "",
00808 "", "",
00809 "", "",
00810 "", "",
00811 "", "", NULL, FALSE,
00812 "", "", NULL, FALSE, FALSE,
00813 NULL,
00814 NULL, NULL,
00815 NULL, NULL,
00816 NULL, NULL,
00817 70, NULL, NULL,
00818 NULL, NULL,
00819 NULL, NULL, NULL, NULL,
00820 NULL,
00821 NULL,
00822 NULL, NULL
00823 };
00824
00833 static NMEErr encodeURLFunNull(NMEConstText link, NMEInt linkLen,
00834 NMEContext *context, void *data)
00835 {
00836 return kNMEErrOk;
00837 }
00838
00849 static NMEErr encodeCharFunNull(NMEConstText src, NMEInt srcLen, NMEInt *srcIx,
00850 NMEContext *context,
00851 void *data)
00852 {
00853 (*srcIx)++;
00854 return kNMEErrOk;
00855 }
00856
00857 NMEOutputFormat const NMEOutputFormatNull =
00858 {
00859 "",
00860 0,
00861 10,
00862 '%',
00863 "", "",
00864 4,
00865 "", "",
00866 "", "",
00867 "",
00868 "", "",
00869 "", "",
00870 "", "",
00871 "", "",
00872 "", "",
00873 "", "",
00874 "", "",
00875 "", "",
00876 NULL,
00877 "", "",
00878 "", "",
00879 "", "",
00880 "", "",
00881 "", "",
00882 "", "",
00883 "", "",
00884 "",
00885 "", "",
00886 "", "",
00887 "", "",
00888 "", "",
00889 "", "",
00890 "", "",
00891 "", "", NULL, FALSE,
00892 "", "", NULL, FALSE, FALSE,
00893 NULL,
00894 encodeURLFunNull, NULL,
00895 encodeCharFunNull, NULL,
00896 encodeCharFunNull, NULL,
00897 -1, NULL, NULL,
00898 NULL, NULL,
00899 NULL, NULL, NULL, NULL,
00900 NULL,
00901 NULL,
00902 NULL, NULL
00903 };
00904
00914 static NMEWordwrapPermission wordwrapCheckNMEFun(NMEConstText txt,
00915 NMEInt len, NMEInt i,
00916 void *data)
00917 {
00918 (void)data;
00919
00920 return txt[i] == ' ' && i + 1 < len
00921 && txt[i + 1] != '*'
00922 && txt[i + 1] != '#'
00923 && txt[i + 1] != '|'
00924 && txt[i + 1] != '='
00925 ? kNMEWordwrapReplaceChar
00926 : kNMEWordwrapNo;
00927 }
00928
00929 NMEOutputFormat const NMEOutputFormatNME =
00930 {
00931 " ",
00932 0,
00933 10,
00934 '%',
00935 "", "",
00936 6,
00937 "%%{l}=%%", "%%{l}=%%\n",
00938 "", "\n\n",
00939 "\\\\",
00940 "{{{\n", "}}}\n\n",
00941 "", "\n",
00942 "", "%%{l=1}\n%%",
00943 "%L ", "\n",
00944 "", "%%{l=1}\n%%",
00945 "%L ", "\n",
00946 "", "%%{l=1}\n%%",
00947 "%L ", "\n",
00948 NULL,
00949 "%L ", "\n",
00950 "", "%%{l=1}\n%%",
00951 "%%{l}:%% ", "\n",
00952 "", "\n",
00953 "", "\n",
00954 "|=", "",
00955 "|", "",
00956 "----\n\n",
00957 "**", "**",
00958 "//", "//",
00959 "__", "__",
00960 "^^", "^^",
00961 ",,", ",,",
00962 "##", "##",
00963 "[[", "]]", "|", FALSE,
00964 "{{", "}}", "|", FALSE, FALSE,
00965 NULL,
00966 NULL, NULL,
00967 encodeCharFunNME, NULL,
00968 NULL, NULL,
00969 70, wordwrapCheckNMEFun, NULL,
00970 NULL, NULL,
00971 NULL, NULL, NULL, NULL,
00972 NULL,
00973 NULL,
00974 NULL, NULL
00975 };
00976
00977 NMEOutputFormat const NMEOutputFormatHTML =
00978 {
00979 " ",
00980 2,
00981 0,
00982 '%',
00983 "<!-- Generated by Nyctergatis Markup Engine, "
00984 __DATE__ " " __TIME__ " -->\n"
00985 "<html><body>\n", "</body></html>\n",
00986 4,
00987 "<h%{l}%%{s>0} style=\"font-size:%{l=1&3*s|l=2&2*s|l=3&3*s/2|5*s/4}pt\"%%>"
00988 "%%{x}<a name=\"h%{o}\">%%"
00989 "%%{i>0}%{i}. %%",
00990 "%%{x}</a>%%"
00991 "</h%{l}>\n",
00992 "<p%%{s>0} style=\"font-size:%{s}pt\"%%>", "</p>\n",
00993 "<br />",
00994 "<pre%%{s>0} style=\"font-size:%{s}pt\"%%>\n", "</pre>\n",
00995 "", "\n",
00996 "<ul>\n", "</ul>\n",
00997 "<li%%{s>0} style=\"font-size:%{s}pt\"%%>", "</li>\n",
00998 "<ol>\n", "</ol>\n",
00999 "<li%%{s>0} style=\"font-size:%{s}pt\"%%>", "</li>\n",
01000 "<dl>\n", "</dl>\n",
01001 "<dt%%{s>0} style=\"font-size:%{s}pt\"%%>", "</dt>\n",
01002 NULL,
01003 "<dd%%{s>0} style=\"font-size:%{s}pt\"%%>", "</dd>\n",
01004 "<div style=\"margin-left:2em%%{s>0}; font-size:%{s}pt%%\">\n",
01005 "</div>\n",
01006 "<p%%{s>0} style=\"font-size:%{s}pt\"%%>", "</p>\n",
01007 "<table>\n", "</table>\n",
01008 "<tr>", "</tr>\n",
01009 "<th%%{s>0} style=\"font-size:%{s}pt\"%%>", "</th>\n",
01010 "<td%%{s>0} style=\"font-size:%{s}pt\"%%>", "</td>\n",
01011 "<hr />\n",
01012 "<b>", "</b>",
01013 "<i>", "</i>",
01014 "<u>", "</u>",
01015 "<sup>", "</sup>",
01016 "<sub>", "</sub>",
01017 "<tt>", "</tt>",
01018 "<a href=\"", "</a>", "\">", FALSE,
01019 "<img src=\"", "\" />", "\" alt=\"", FALSE, TRUE,
01020 NULL,
01021 NULL, NULL,
01022 NMEEncodeCharFunDict, (void *)htmlCharDict,
01023 NMEEncodeCharFunDict, (void *)htmlCharDict,
01024 70, NULL, NULL,
01025 NULL, NULL,
01026 NULL, NULL, NULL, NULL,
01027 NULL,
01028 NULL,
01029 NULL, NULL
01030 };
01031
01045 static NMEErr encodeCharRTFFun(NMEConstText src, NMEInt srcLen, NMEInt *srcIx,
01046 NMEContext *context, void *data)
01047 {
01048 NMEInt ch, i;
01049 (void)data;
01050
01051 if ((src[*srcIx] & 0x80) == 0)
01052 {
01053 if (context->destLen + 1 >= context->bufSize)
01054 return kNMEErrNotEnoughMemory;
01055 if (src[*srcIx] == '\\' || src[*srcIx] == '{' || src[*srcIx] == '}')
01056 {
01057 context->dest[context->destLen++] = '\\';
01058 context->destLenUCS16++;
01059 }
01060 context->dest[context->destLen++] = src[(*srcIx)++];
01061 context->destLenUCS16++;
01062 return kNMEErrOk;
01063 }
01064 else if (*srcIx + 1 < srcLen && (src[*srcIx] & 0xe0) == 0xc0
01065 && (src[*srcIx + 1] & 0xc0) == 0x80)
01066 {
01067 ch = (((NMEInt)src[*srcIx] & 0x1f) << 6) | (src[*srcIx + 1] & 0x3f);
01068 *srcIx += 2;
01069 }
01070 else if (*srcIx + 2 < srcLen && (src[*srcIx] & 0xf0) == 0xe0
01071 && (src[*srcIx + 1] & 0xc0) == 0x80 && (src[*srcIx + 2] & 0xc0) == 0x80)
01072 {
01073 ch = ((NMEInt)src[*srcIx] << 12) | (((NMEInt)src[*srcIx + 1] & 0x3f) << 6)
01074 | src[*srcIx + 2] & 0x3f;
01075 *srcIx += 3;
01076 }
01077 else
01078 {
01079 *srcIx += 1;
01080 return kNMEErrOk;
01081 }
01082
01083 if (context->destLen + 9 >= context->bufSize)
01084 return kNMEErrNotEnoughMemory;
01085
01086
01087 if (ch >= 32768)
01088 ch -= 65536;
01089
01090 context->dest[context->destLen++] = '\\';
01091 context->dest[context->destLen++] = 'u';
01092 if (ch < 0)
01093 {
01094 context->dest[context->destLen++] = '-';
01095 context->destLenUCS16++;
01096 ch = -ch;
01097 }
01098 for (i = 1; i < ch; i *= 10)
01099 ;
01100 for (i /= 10; i > 0; i /= 10)
01101 {
01102 context->dest[context->destLen++] = '0' + (ch / i) % 10;
01103 context->destLenUCS16++;
01104 }
01105 context->dest[context->destLen++] = '?';
01106 context->destLenUCS16 += 3;
01107
01108 return kNMEErrOk;
01109 }
01110
01118 static NMEErr encodeURLFunRTF(NMEConstText link, NMEInt linkLen,
01119 NMEContext *context, void *data)
01120 {
01121 NMEInt i;
01122 NMEErr err;
01123 (void)data;
01124
01125
01126 for (i = 0; i < linkLen; )
01127 CheckError(encodeCharRTFFun(link, linkLen, &i, context, NULL));
01128 return kNMEErrOk;
01129 }
01130
01139 static NMEWordwrapPermission wordwrapCheckRTFFun(NMEConstText txt,
01140 NMEInt len, NMEInt i,
01141 void *data)
01142 {
01143 (void)data;
01144
01145 return txt[i] == ' ' ? kNMEWordwrapInsert : kNMEWordwrapNo;
01146 }
01147
01148 NMEOutputFormat const NMEOutputFormatRTF =
01149 {
01150 #define SIZE "%{2*s}"
01151 #define SIZEH "%{l=1&3*s|l=2&5*s/2|l=3&2*s|3*s/2}"
01152 " ", // space
01153 0,
01154 10,
01155 '%',
01156 "{\\rtf1\\ansi\\deff0"
01157 "{\\fonttbl"
01158 "{\\f0\\froman Times;}"
01159 "{\\f1\\fswiss Helvetica;}"
01160 "{\\f2\\fmodern Courier;}"
01161 "}\n",
01162 "\n}\n",
01163 4,
01164 "{\\pard\\sb%{500-100*l}\\li60\\sa40%%{l=1}\\qc%%\\f1"
01165 "\\fs" SIZEH "%%{l!2}\\b%% %%{i>0}%{i}. %%",
01166 "\\par}\n",
01167 "{\\pard\\sb80\\li60\\qj\\fi160\\f0\\fs" SIZE " ",
01168 "\\par}\n",
01169 "\\line ",
01170 "{\\pard\\sb80\\li160\\f2\\fs" SIZE " ",
01171 "}\n",
01172 "",
01173 "\\par\n",
01174 "",
01175 "",
01176 "{\\pard\\sb80\\li%{60+100*l}\\qj\\fi160\\f0\\fs" SIZE " * ",
01177 "\\par}\n",
01178 "",
01179 "",
01180 "{\\pard\\sb80\\li%{60+100*l}\\qj\\fi160\\f0\\fs" SIZE " %{i}",
01181 "\\par}\n",
01182 "", "",
01183 "{\\pard\\sb80\\li%{60+100*l}\\qj\\f0\\fs" SIZE "\\i ",
01184 "\\par}\n",
01185 NULL,
01186 "{\\pard\\sb80\\qj\\fi160\\f0\\fs" SIZE "\\li320 ",
01187 "\\par}\n",
01188 "", "",
01189 "{\\pard\\sb80\\li%{60+100*l}\\qj\\fi160\\f0\\fs" SIZE " ",
01190 "\\par}\n",
01191 "{\\par\\li60 ", "\\pard}\n",
01192 "\\trowd\\trautofit1 ", "\\row\n",
01193 "\\pard\\intbl\\sb80\\qc\\fi160\\f0\\fs" SIZE " {\\b ",
01194 "}\\cell\n",
01195 "\\pard\\intbl\\sb80\\qj\\fi160\\f0\\fs" SIZE " ",
01196 "\\cell\n",
01197 "\\hrule\n",
01198 "{\\b ",
01199 "}",
01200 "{\\i ",
01201 "}",
01202 "{\\ul ",
01203 "}",
01204 "{\\super ",
01205 "}",
01206 "{\\sub ",
01207 "}",
01208 "{\\f2 ",
01209 "}",
01210 "{\\field{\\*\\fldinst{HYPERLINK \"", "}}", "\"}}{\\fldrslt ", FALSE,
01211 "", "", NULL, FALSE, FALSE,
01212 NULL,
01213 encodeURLFunRTF, NULL,
01214 encodeCharRTFFun, NULL,
01215 encodeCharRTFFun, NULL,
01216 70, wordwrapCheckRTFFun, NULL,
01217 NULL, NULL,
01218 NULL, NULL, NULL, NULL,
01219 NULL,
01220 NULL,
01221 NULL, NULL
01222 #undef SIZE
01223 #undef SIZEH
01224 };
01225
01226 NMEOutputFormat const NMEOutputFormatLaTeX =
01227 {
01228 " ",
01229 2,
01230 10,
01231 '%',
01232 "\\documentclass[%{s}pt]{article}\n"
01233 "\\usepackage{hyperref}\n"
01234 "\\begin{document}\n",
01235 "\n\\end{document}\n",
01236 4,
01237 "\n\\%%{l>3&2|l-1}sub%%section%%{l>3|i<1}*%%{",
01238 "}\n",
01239 "\n",
01240 "\n",
01241 "\\\\",
01242 "\n\\begin{verbatim}\n",
01243 "\\end{verbatim}\n",
01244 "",
01245 "\n",
01246 "\\begin{itemize}\n",
01247 "\\end{itemize}\n",
01248 "\\item ",
01249 "\n",
01250 "\\begin{itemize}\n",
01251 "\\end{itemize}\n",
01252 "\\item[%{i}] ",
01253 "\n",
01254 "\\begin{itemize}\n",
01255 "\\end{itemize}\n",
01256 "\\item[] {\\bf ", "} \\hspace{1em} ",
01257 NULL,
01258 "\n", "\n",
01259 "\\begin{itemize}\n", "\\end{itemize}\n",
01260 "\\item[] ", "\n",
01261 "\\begin{tabular}{llllllllllllllll}\n", "\\end{tabular}\n",
01262 "", "\\\\\n",
01263 "{\\bf ", "} & ",
01264 "", " & ",
01265 "",
01266 "{\\bfseries ",
01267 "}",
01268 "{\\itshape ",
01269 "}",
01270 "\\underline{",
01271 "}",
01272 "\\textsuperscript{",
01273 "}",
01274 "\\ensuremath{_{\\mbox{",
01275 "}}}",
01276 "{\\ttfamily ",
01277 "}",
01278 "\\href{", "}", "}{", FALSE,
01279 "", "", NULL, FALSE, FALSE,
01280 NULL,
01281 NULL, NULL,
01282 NMEEncodeCharFunDict, (void *)latexCharDict,
01283 NULL, NULL,
01284 70, NULL, NULL,
01285 NULL, NULL,
01286 NULL, NULL, NULL, NULL,
01287 NULL,
01288 NULL,
01289 NULL, NULL
01290 };
01291
01292 NMEOutputFormat const NMEOutputFormatMan =
01293 {
01294 " ",
01295 0,
01296 10,
01297 '%',
01298 ".TH title 1\n", "",
01299 2,
01300 "%%{l=1}.SH%%%%{l>1}.SS%% ", "\n",
01301 ".P\n", "\n",
01302 "",
01303 "", "",
01304 " ", "\n",
01305 "", "",
01306 ".IP *\n", "\n",
01307 "", "",
01308 ".IP %{i}\n", "\n",
01309 "", "",
01310 ".IP ", "\n",
01311 NULL,
01312 "", "\n",
01313 "", "",
01314 "\n.P\n", "\n",
01315 "", "",
01316 "", "\n",
01317 "", " ",
01318 "", " ",
01319 "\n",
01320 "\n.B ", "\n",
01321 "\n.I ", "\n",
01322 "", "",
01323 "", "",
01324 "", "",
01325 "", "",
01326 "", "", NULL, FALSE,
01327 "", "", NULL, FALSE, FALSE,
01328 NULL,
01329 NULL, NULL,
01330 NULL, NULL,
01331 NULL, NULL,
01332 70, NULL, NULL,
01333 NULL, NULL,
01334 NULL, NULL, NULL, NULL,
01335 NULL,
01336 NULL,
01337 NULL, NULL
01338 };
01339
01345 static NMEErr addLink(NMEContext *context,
01346 NMEOutputFormat const *outputFormat)
01347 {
01348 NMEInt i;
01349 NMEConstText link = context->src + context->linkOffset;
01350 NMEInt linkLen = context->linkLength;
01351 NMEErr err;
01352
01353 if (outputFormat->interwikis)
01354 {
01355 NMEInt iw;
01356
01357
01358 for (iw = 0; outputFormat->interwikis[iw].alias; iw++)
01359 {
01360 for (i = 0;
01361 i < linkLen
01362 && outputFormat->interwikis[iw].alias[i] != '\0'
01363 && link[i] == outputFormat->interwikis[iw].alias[i];
01364 i++)
01365 ;
01366 if (outputFormat->interwikis[iw].alias[i] == '\0')
01367 {
01368
01369 if (!NMEAddString(outputFormat->interwikis[iw].urlPrefix, -1,
01370 context->ctrlChar, context))
01371 return kNMEErrNotEnoughMemory;
01372 CheckError(checkWordwrap(context, outputFormat));
01373 link += i;
01374 linkLen -= i;
01375 break;
01376 }
01377 }
01378 }
01379
01380
01381 if (outputFormat->encodeURLFun)
01382 CheckError(outputFormat->encodeURLFun(link, linkLen, context,
01383 outputFormat->encodeURLData));
01384 else
01385 {
01386
01387 if (context->destLen + linkLen > context->bufSize)
01388 return kNMEErrNotEnoughMemory;
01389 for (i = 0; i < linkLen; i++)
01390 {
01391 context->dest[context->destLen++] = link[i];
01392 context->destLenUCS16++;
01393 }
01394 }
01395
01396 return kNMEErrOk;
01397 }
01398
01406 static NMEBoolean findStyleInStyleStack(
01407 NMEStyle const styleStack[],
01408 NMEInt styleNesting,
01409 NMEStyle style,
01410 NMEInt *i)
01411 {
01412 NMEInt j;
01413
01414 for (j = 0; j < styleNesting; j++)
01415 if (styleStack[j] == style)
01416 {
01417 if (i)
01418 *i = j;
01419 return TRUE;
01420 }
01421 return FALSE;
01422 }
01423
01428 static NMEConstText styleMarkerFromStyleID(NMEStyle style)
01429 {
01430 switch (style)
01431 {
01432 case kNMEStyleBold:
01433 return "**";
01434 case kNMEStyleItalic:
01435 return "//";
01436 case kNMEStyleUnderline:
01437 return "__";
01438 case kNMEStyleSuperscript:
01439 return "^^";
01440 case kNMEStyleSubscript:
01441 return ",,";
01442 case kNMEStyleMonospace:
01443 return "##";
01444 case kNMEStyleLink:
01445 return "[[";
01446 case kNMEStyleImage:
01447 return "{{";
01448 default:
01449 return NULL;
01450 }
01451 }
01452
01462 static NMEErr processStyleTag(
01463 NMEStyle styleStack[],
01464 NMEInt *styleNesting,
01465 NMEStyle style,
01466 NMEInt i0,
01467 NMEOutputFormat const *outputFormat,
01468 NMEContext *context)
01469 {
01470 NMEInt i, j;
01471 NMEErr err;
01472
01473 #define HOOK(e, st) \
01474 do { \
01475 if (outputFormat->spanHookFun) \
01476 { \
01477 NMEConstText styleStr = styleMarkerFromStyleID(st); \
01478 if (styleStr) \
01479 CheckError(outputFormat->spanHookFun(kNMEHookLevelSpan, 0, e, styleStr, \
01480 i0 + context->srcIndexOffset, \
01481 context, \
01482 outputFormat->hookData)); \
01483 } \
01484 } while (0)
01485
01486
01487 if (findStyleInStyleStack(styleStack, *styleNesting, style, &i))
01488 {
01489
01490 for (j = *styleNesting - 1; j >= i; j--)
01491 if (styleStack[j] != kNMEStyleVerbatim
01492 || context->options & kNMEProcessOptVerbatimMono
01493 && !findStyleInStyleStack(styleStack, *styleNesting,
01494 kNMEStyleMonospace, NULL))
01495 {
01496
01497 if (styleStack[j] == kNMEStyleLink
01498 && outputFormat->sepLink && outputFormat->linkAfterSep)
01499 {
01500 if (!NMEAddString(outputFormat->sepLink, -1,
01501 context->ctrlChar, context))
01502 return kNMEErrNotEnoughMemory;
01503 CheckError(addLink(context, outputFormat));
01504 CheckError(checkWordwrap(context, outputFormat));
01505 }
01506 else if (styleStack[j] == kNMEStyleImage
01507 && outputFormat->sepImage && outputFormat->imageAfterSep)
01508 {
01509 if (!NMEAddString(outputFormat->sepImage, -1,
01510 context->ctrlChar, context))
01511 return kNMEErrNotEnoughMemory;
01512 CheckError(addLink(context, outputFormat));
01513 CheckError(checkWordwrap(context, outputFormat));
01514 }
01515
01516
01517 if (!NMEAddString(styleStack[j] == kNMEStyleBold
01518 ? outputFormat->endBold
01519 : styleStack[j] == kNMEStyleItalic
01520 ? outputFormat->endItalic
01521 : styleStack[j] == kNMEStyleUnderline
01522 ? outputFormat->endUnderline
01523 : styleStack[j] == kNMEStyleSuperscript
01524 ? outputFormat->endSuperscript
01525 : styleStack[j] == kNMEStyleSubscript
01526 ? outputFormat->endSubscript
01527 : styleStack[j] == kNMEStyleLink
01528 ? outputFormat->endLink
01529 : styleStack[j] == kNMEStyleImage
01530 ? outputFormat->endImage
01531 : outputFormat->endCode,
01532 -1,
01533 context->ctrlChar, context))
01534 return kNMEErrNotEnoughMemory;
01535 CheckError(checkWordwrap(context, outputFormat));
01536
01537
01538 HOOK(FALSE, styleStack[j]);
01539 }
01540
01541 for (j = i + 1; j < *styleNesting; j++)
01542 if (styleStack[j] != kNMEStyleLink && styleStack[j] != kNMEStyleImage)
01543 {
01544 HOOK(TRUE, styleStack[j]);
01545
01546 styleStack[i] = styleStack[j];
01547 if (styleStack[i] != kNMEStyleVerbatim)
01548 {
01549 if (!NMEAddString(styleStack[i] == kNMEStyleBold
01550 ? outputFormat->beginBold
01551 : styleStack[i] == kNMEStyleItalic
01552 ? outputFormat->beginItalic
01553 : styleStack[i] == kNMEStyleUnderline
01554 ? outputFormat->beginUnderline
01555 : styleStack[i] == kNMEStyleSuperscript
01556 ? outputFormat->beginSuperscript
01557 : styleStack[i] == kNMEStyleSubscript
01558 ? outputFormat->beginSubscript
01559 : outputFormat->beginCode,
01560 -1,
01561 context->ctrlChar, context))
01562 return kNMEErrNotEnoughMemory;
01563 CheckError(checkWordwrap(context, outputFormat));
01564 }
01565 i++;
01566 }
01567 *styleNesting -= j - i;
01568 return kNMEErrOk;
01569 }
01570
01571
01572
01573 if (style == kNMEStyleLink || style == kNMEStyleImage
01574 || outputFormat->noStyleInAlt
01575 && findStyleInStyleStack(styleStack, *styleNesting,
01576 kNMEStyleImage, NULL))
01577 return kNMEErrOk;
01578 styleStack[(*styleNesting)++] = style;
01579
01580
01581 if (style == kNMEStyleVerbatim
01582 && (!(context->options & kNMEProcessOptVerbatimMono)
01583 || findStyleInStyleStack(styleStack, *styleNesting,
01584 kNMEStyleMonospace, NULL)))
01585 return kNMEErrOk;
01586 HOOK(TRUE, style);
01587 if (!NMEAddString(style == kNMEStyleBold ? outputFormat->beginBold
01588 : style == kNMEStyleItalic ? outputFormat->beginItalic
01589 : style == kNMEStyleUnderline ? outputFormat->beginUnderline
01590 : style == kNMEStyleSuperscript ? outputFormat->beginSuperscript
01591 : style == kNMEStyleSubscript ? outputFormat->beginSubscript
01592 : outputFormat->beginCode,
01593 -1,
01594 context->ctrlChar, context))
01595 return kNMEErrNotEnoughMemory;
01596 CheckError(checkWordwrap(context, outputFormat));
01597 return kNMEErrOk;
01598
01599 #undef HOOK
01600 }
01601
01610 static NMEErr flushStyleTags(
01611 NMEStyle styleStack[kNMEStylesCount],
01612 NMEInt *styleNesting,
01613 NMEInt i0,
01614 NMEOutputFormat const *outputFormat,
01615 NMEContext *context)
01616 {
01617 NMEInt i;
01618 NMEErr err;
01619
01620 for (i = *styleNesting - 1; i >= 0; i--)
01621 if (styleStack[i] != kNMEStyleVerbatim
01622 || context->options & kNMEProcessOptVerbatimMono
01623 && !findStyleInStyleStack(styleStack, *styleNesting,
01624 kNMEStyleMonospace, NULL))
01625 {
01626 if (styleStack[i] == kNMEStyleLink
01627 && outputFormat->sepLink && outputFormat->linkAfterSep)
01628 {
01629 if (!NMEAddString(outputFormat->sepLink, -1,
01630 context->ctrlChar, context))
01631 return kNMEErrNotEnoughMemory;
01632 CheckError(addLink(context, outputFormat));
01633 CheckError(checkWordwrap(context, outputFormat));
01634 }
01635 else if (styleStack[i] == kNMEStyleImage
01636 && outputFormat->sepImage && outputFormat->imageAfterSep)
01637 {
01638 if (!NMEAddString(outputFormat->sepImage, -1,
01639 context->ctrlChar, context))
01640 return kNMEErrNotEnoughMemory;
01641 CheckError(addLink(context, outputFormat));
01642 CheckError(checkWordwrap(context, outputFormat));
01643 }
01644
01645 if (!NMEAddString(styleStack[i] == kNMEStyleBold
01646 ? outputFormat->endBold
01647 : styleStack[i] == kNMEStyleItalic
01648 ? outputFormat->endItalic
01649 : styleStack[i] == kNMEStyleUnderline
01650 ? outputFormat->endUnderline
01651 : styleStack[i] == kNMEStyleSuperscript
01652 ? outputFormat->endSuperscript
01653 : styleStack[i] == kNMEStyleSubscript
01654 ? outputFormat->endSubscript
01655 : styleStack[i] == kNMEStyleLink
01656 ? outputFormat->endLink
01657 : styleStack[i] == kNMEStyleImage
01658 ? outputFormat->endImage
01659 : outputFormat->endCode,
01660 -1,
01661 context->ctrlChar, context))
01662 return kNMEErrNotEnoughMemory;
01663 CheckError(checkWordwrap(context, outputFormat));
01664
01665
01666 if (outputFormat->spanHookFun)
01667 {
01668 NMEConstText styleStr = styleMarkerFromStyleID(styleStack[i]);
01669 if (styleStr)
01670 CheckError(outputFormat->spanHookFun(kNMEHookLevelSpan, 0,
01671 FALSE, styleStr,
01672 i0 + context->srcIndexOffset,
01673 context,
01674 outputFormat->hookData));
01675 }
01676 }
01677 *styleNesting = 0;
01678 return kNMEErrOk;
01679 }
01680
01687 static NMEErr addEndPar(NMEBoolean forceEndOfList,
01688 NMEOutputFormat const *outputFormat,
01689 NMEContext *context)
01690 {
01691 NMEErr err;
01692
01693 #define HOOK(cb, l, it, e, m) \
01694 do { \
01695 if (outputFormat->cb) \
01696 CheckError(outputFormat->cb(l, it, e, m, \
01697 context->srcIndexOffset + context->srcIndex, \
01698 context, \
01699 outputFormat->hookData)); \
01700 } while (0)
01701
01702 if (context->nesting > 0)
01703 {
01704 NMEInt level0, item0;
01705
01706 level0 = context->level;
01707 item0 = context->item;
01708 setContext(*context, context->nesting, context->listNum[context->nesting - 1]);
01709
01710
01711 if (context->listNum[context->nesting - 1] >= 0)
01712 {
01713 context->listNum[context->nesting - 1]++;
01714 if (!NMEAddString(outputFormat->endOLItem, -1,
01715 context->ctrlChar, context))
01716 return kNMEErrNotEnoughMemory;
01717 CheckError(checkWordwrap(context, outputFormat));
01718 HOOK(parHookFun, context->level, context->item, FALSE, "#");
01719 }
01720 else if (context->listNum[context->nesting - 1] == kNMEListNumTableCell
01721 || context->listNum[context->nesting - 1] == kNMEListNumTableHCell)
01722 {
01723 if (!NMEAddString(context->listNum[context->nesting - 1] == kNMEListNumTableCell
01724 ? outputFormat->endTableCell
01725 : outputFormat->endTableHCell,
01726 -1,
01727 context->ctrlChar, context))
01728 return kNMEErrNotEnoughMemory;
01729 CheckError(checkWordwrap(context, outputFormat));
01730 HOOK(parHookFun, kNMEHookLevelPar, 0, FALSE,
01731 context->listNum[context->nesting - 1] == kNMEListNumTableCell ? "|" : "|=");
01732 if (!NMEAddString(outputFormat->endTableRow, -1,
01733 context->ctrlChar, context))
01734 return kNMEErrNotEnoughMemory;
01735 CheckError(checkWordwrap(context, outputFormat));
01736 }
01737 else
01738 {
01739 if (!NMEAddString(context->listNum[context->nesting - 1] == kNMEListNumUL
01740 ? outputFormat->endULItem
01741 : context->listNum[context->nesting - 1] == kNMEListNumDT
01742 ? outputFormat->endDT
01743 : context->listNum[context->nesting - 1] == kNMEListNumDD
01744 ? outputFormat->endDD
01745 : outputFormat->endIndentedPar,
01746 -1,
01747 context->ctrlChar, context))
01748 return kNMEErrNotEnoughMemory;
01749 CheckError(checkWordwrap(context, outputFormat));
01750 HOOK(parHookFun, context->level, context->item, FALSE,
01751 context->listNum[context->nesting - 1] == kNMEListNumUL ? "*"
01752 : context->listNum[context->nesting - 1] == kNMEListNumDT ? ";"
01753 : context->listNum[context->nesting - 1] == kNMEListNumDD ? ";:"
01754 : ":");
01755 }
01756
01757 if (forceEndOfList)
01758 while (context->nesting > 0)
01759 {
01760 setContext(*context, context->nesting, context->listNum[context->nesting - 1]);
01761 if (!NMEAddString(context->listNum[context->nesting - 1] == kNMEListNumUL
01762 ? outputFormat->endUL
01763 : context->listNum[context->nesting - 1] == kNMEListNumDT
01764 || context->listNum[context->nesting - 1] == kNMEListNumDD
01765 ? outputFormat->endDL
01766 : context->listNum[context->nesting - 1] == kNMEListIndented
01767 ? outputFormat->endIndented
01768 : context->listNum[context->nesting - 1] == kNMEListNumTableCell
01769 || context->listNum[context->nesting - 1] == kNMEListNumTableHCell
01770 ? outputFormat->endTable
01771 : outputFormat->endOL,
01772 -1,
01773 context->ctrlChar, context))
01774 return kNMEErrNotEnoughMemory;
01775 CheckError(checkWordwrap(context, outputFormat));
01776 HOOK(divHookFun,
01777 context->listNum[context->nesting - 1] == kNMEListNumTableCell
01778 || context->listNum[context->nesting - 1] == kNMEListNumTableHCell
01779 ? kNMEHookLevelPar : context->level,
01780 0, FALSE,
01781 context->listNum[context->nesting - 1] == kNMEListNumUL ? "*"
01782 : context->listNum[context->nesting - 1] == kNMEListNumDT
01783 || context->listNum[context->nesting - 1] == kNMEListNumDD ? ";"
01784 : context->listNum[context->nesting - 1] == kNMEListIndented ? ":"
01785 : context->listNum[context->nesting - 1] > 0 ? "#"
01786 : "|");
01787 context->nesting--;
01788 }
01789
01790 setContext(*context, level0, item0);
01791 return kNMEErrOk;
01792 }
01793 else
01794 {
01795 if (!NMEAddString(outputFormat->endPar, -1, context->ctrlChar, context))
01796 return kNMEErrNotEnoughMemory;
01797 CheckError(checkWordwrap(context, outputFormat));
01798 HOOK(parHookFun, kNMEHookLevelPar, 0, FALSE, "p");
01799 return kNMEErrOk;
01800 }
01801 #undef HOOK
01802 }
01803
01814 static NMEErr addLinkBegin(NMEBoolean isImage,
01815 NMEStyle styleStack[kNMEStylesCount],
01816 NMEInt *styleNesting,
01817 NMEInt i0,
01818 NMEOutputFormat const *outputFormat,
01819 NMEContext *context)
01820 {
01821 NMEInt j, k;
01822 NMEErr err;
01823
01824
01825 for (j = 0; j < *styleNesting; j++)
01826 if (styleStack[j] == kNMEStyleLink && !isImage
01827 || styleStack[j] == kNMEStyleImage)
01828 return kNMEErrOk;
01829
01830
01831 skipBlanks(context->src, context->srcLen, &context->srcIndex);
01832
01833
01834 for (j = context->srcIndex; j < context->srcLen
01835 && (!isEol(context->src[j])
01836 || j + 1 < context->srcLen
01837 && (!isEol(context->src[j + 1])
01838 || context->src[j] == '\r' && context->src[j + 1] =='\n'))
01839 && (j + 1 >= context->srcLen
01840 || context->src[j] != (isImage ? '}' : ']')
01841 || context->src[j + 1] != context->src[j])
01842 && context->src[j] != '|';
01843 j++)
01844 ;
01845
01846
01847 for (k = j;
01848 k > context->srcIndex
01849 && (isBlank(context->src[k - 1]) || isEol(context->src[k - 1]));
01850 k--)
01851 ;
01852
01853
01854 if (k <= context->srcIndex)
01855 {
01856 context->srcIndex = j;
01857 return kNMEErrOk;
01858 }
01859
01860
01861 context->linkOffset = context->srcIndex;
01862 context->linkLength = k - context->srcIndex;
01863
01864
01865 if (outputFormat->spanHookFun)
01866 CheckError(outputFormat->spanHookFun(kNMEHookLevelSpan, 0, TRUE,
01867 isImage ? "{{" : "[[",
01868 i0 + context->srcIndexOffset,
01869 context,
01870 outputFormat->hookData));
01871
01872 if (isImage ? outputFormat->sepImage : outputFormat->sepLink)
01873 {
01874
01875 if (!NMEAddString(isImage ? outputFormat->beginImage : outputFormat->beginLink, -1,
01876 context->ctrlChar, context))
01877 return kNMEErrNotEnoughMemory;
01878 CheckError(checkWordwrap(context, outputFormat));
01879
01880 if (!(isImage ? outputFormat->imageAfterSep : outputFormat->linkAfterSep))
01881 {
01882 CheckError(addLink(context, outputFormat));
01883 if (!NMEAddString(isImage ? outputFormat->sepImage : outputFormat->sepLink, -1,
01884 context->ctrlChar, context))
01885 return kNMEErrNotEnoughMemory;
01886 CheckError(checkWordwrap(context, outputFormat));
01887 }
01888 }
01889
01890
01891 if (j < context->srcLen && context->src[j] == '|')
01892 {
01893 context->srcIndex = j + 1;
01894 skipBlanks(context->src, context->srcLen, &context->srcIndex);
01895 }
01896
01897
01898
01899 styleStack[(*styleNesting)++] = isImage ? kNMEStyleImage : kNMEStyleLink;
01900
01901 return kNMEErrOk;
01902 }
01903
01912 static NMEInt findPlugin(NMEConstText src, NMEInt srcLen, NMEInt i,
01913 NMEBoolean isPlaceholder,
01914 NMEOutputFormat const *outputFormat)
01915 {
01916 NMEConstText name;
01917 NMEInt nameLen, j, k;
01918
01919
01920 skipBlanks(src, srcLen, &i);
01921 name = src + i;
01922 for (nameLen = 0;
01923 i + nameLen < srcLen
01924 && !isBlank(src[i + nameLen])
01925 && !isEol(src[i + nameLen])
01926 && src[i + nameLen] != '>';
01927 nameLen++)
01928 ;
01929
01930
01931 if (outputFormat->plugins && nameLen > 0)
01932 for (j = 0; outputFormat->plugins[j].name; j++)
01933 if (isPlaceholder
01934 ^ (outputFormat->plugins[j].options & kNMEPluginOptTripleAngleBrackets) == 0)
01935 {
01936
01937 for (k = 0; k < nameLen && outputFormat->plugins[j].name[k]; k++)
01938 if (name[k] != outputFormat->plugins[j].name[k])
01939 goto continueMainLoop;
01940 if (outputFormat->plugins[j].name[k] != '\0'
01941 || k < nameLen
01942 && !(outputFormat->plugins[j].options & kNMEPluginOptPartialName))
01943 goto continueMainLoop;
01944
01945 return j;
01946 continueMainLoop:
01947 ;
01948 }
01949
01950
01951 return -1;
01952 }
01953
01963 static NMEErr addPlugin(NMEBoolean isBlock,
01964 NMEBoolean isPlaceholder,
01965 NMEInt options,
01966 NMEOutputFormat const *outputFormat,
01967 NMEContext *context,
01968 NMEBoolean *reparseOutput)
01969 {
01970 NMEConstText name, data;
01971 NMEInt nameLen, dataLen;
01972 NMEInt j, k;
01973 NMEErr err;
01974
01975
01976 skipBlanks(context->src, context->srcLen, &context->srcIndex);
01977 name = context->src + context->srcIndex;
01978 for (nameLen = 0;
01979 context->srcIndex + nameLen < context->srcLen
01980 && !isBlank(context->src[context->srcIndex + nameLen])
01981 && !isEol(context->src[context->srcIndex + nameLen])
01982 && context->src[context->srcIndex + nameLen] != '>';
01983 nameLen++)
01984 ;
01985 context->srcIndex += nameLen;
01986 skipBlanks(context->src, context->srcLen, &context->srcIndex);
01987 if (context->srcIndex < context->srcLen && context->src[context->srcIndex] == '\r')
01988 context->srcIndex++;
01989 if (context->srcIndex < context->srcLen && context->src[context->srcIndex] == '\n')
01990 context->srcIndex++;
01991
01992
01993 data = context->src + context->srcIndex;
01994 if (isBlock)
01995 for (dataLen = 0;
01996 context->srcIndex + dataLen + (isPlaceholder ? 2 : 1) < context->srcLen;
01997 dataLen++)
01998 {
01999 if (isEol(context->src[context->srcIndex + dataLen - 1])
02000 && context->src[context->srcIndex + dataLen] == '>'
02001 && context->src[context->srcIndex + dataLen + 1] == '>'
02002 && (!isPlaceholder
02003 || context->src[context->srcIndex + dataLen + 2] == '>'))
02004 {
02005
02006 j = context->srcIndex + dataLen + (isPlaceholder ? 3 : 2);
02007 skipBlanks(context->src, context->srcLen, &j);
02008 if (j >= context->srcLen || isEol(context->src[j]))
02009 break;
02010 }
02011 }
02012 else
02013 for (dataLen = 0;
02014 context->srcIndex + dataLen + (isPlaceholder ? 2 : 1) < context->srcLen
02015 && (context->src[context->srcIndex + dataLen] != '>'
02016 || context->src[context->srcIndex + dataLen + 1] != '>'
02017 || isPlaceholder
02018 && context->src[context->srcIndex + dataLen + 2] != '>');
02019 dataLen++)
02020 ;
02021 context->srcIndex += dataLen;
02022 if (context->srcIndex + (isPlaceholder ? 3 : 2) <= context->srcLen)
02023 context->srcIndex += isPlaceholder ? 3 : 2;
02024
02025
02026 if (dataLen > 0 && data[dataLen - 1] == '\n')
02027 dataLen--;
02028 if (dataLen > 0 && data[dataLen - 1] == '\r')
02029 dataLen--;
02030
02031
02032 if (outputFormat->plugins && nameLen > 0)
02033 for (j = 0; outputFormat->plugins[j].name; j++)
02034 if (isPlaceholder
02035 ^ (outputFormat->plugins[j].options & kNMEPluginOptTripleAngleBrackets) == 0)
02036 {
02037
02038 for (k = 0; k < nameLen && outputFormat->plugins[j].name[k]; k++)
02039 if (name[k] != outputFormat->plugins[j].name[k])
02040 goto continueMainLoop;
02041 if (outputFormat->plugins[j].name[k] != '\0'
02042 || k < nameLen
02043 && !(outputFormat->plugins[j].options & kNMEPluginOptPartialName))
02044 goto continueMainLoop;
02045
02046
02047 CheckError(outputFormat->plugins[j].cb(name, nameLen,
02048 data, dataLen,
02049 context,
02050 outputFormat->plugins[j].userData));
02051
02052 *reparseOutput
02053 = (outputFormat->plugins[j].options & kNMEPluginOptReparseOutput) != 0;
02054
02055 return kNMEErrOk;
02056 continueMainLoop:
02057 ;
02058 }
02059
02060
02061 return kNMEErrOk;
02062 }
02063
02071 static void nextHeading(NMEInt *headingFlags,
02072 NMEInt headingNum[],
02073 NMEInt headingLevel)
02074 {
02075 NMEInt i;
02076
02077 if (headingLevel <= sizeof(*headingFlags))
02078 {
02079
02080 *headingFlags |= 1 << headingLevel - 1;
02081
02082 *headingFlags &= ~((~(NMEInt)0) << headingLevel);
02083 }
02084
02085 if (headingLevel <= kMaxNumberedHeadingLevels)
02086 {
02087 headingNum[headingLevel - 1]++;
02088 for (i = headingLevel; i < kMaxNumberedHeadingLevels; i++)
02089 headingNum[i] = 0;
02090 }
02091 }
02092
02112 static NMEBoolean parseNextToken(NMEConstText src, NMEInt srcLen,
02113 NMEInt *i,
02114 NMEState state,
02115 NMEBoolean verbatim,
02116 NMEInt nesting,
02117 NMEInt const listNum[],
02118 NMEStyle const styleStack[],
02119 NMEInt styleNesting,
02120 NMEOutputFormat const *outputFormat,
02121 NMEToken *token,
02122 NMEInt *headingLevel,
02123 NMEInt *itemNesting,
02124 NMEStyle *style,
02125 NMEInt options)
02126 {
02127 NMEInt k;
02128
02129
02130 if (state == kNMEStateHeading && isBlank(src[*i]))
02131 {
02132 k = *i;
02133 skipBlanks(src, srcLen, &k);
02134 if (k < srcLen && src[k] == '=')
02135 {
02136 NMEInt p;
02137
02138
02139 for (p = k + 1; p < srcLen && src[p] == '='; p++)
02140 ;
02141 skipBlanks(src, srcLen, &p);
02142 if (p >= srcLen || isEol(src[p]))
02143 *i = k;
02144 }
02145 }
02146
02147
02148 switch (src[*i])
02149 {
02150 case ' ':
02151 *token = kNMETokenSpace;
02152 (*i)++;
02153 return TRUE;
02154 case '\t':
02155 *token = kNMETokenTab;
02156 (*i)++;
02157 return TRUE;
02158 case '\r':
02159 *token = kNMETokenEOL;
02160 (*i)++;
02161 if (*i < srcLen && src[*i] == '\n')
02162 (*i)++;
02163 return TRUE;
02164 case '\n':
02165 *token = kNMETokenEOL;
02166 (*i)++;
02167 return TRUE;
02168 case '\\':
02169 if (verbatim)
02170 break;
02171 switch (state)
02172 {
02173 case kNMEStatePar:
02174 case kNMEStateHeading:
02175 case kNMEStateBetweenPar:
02176 case kNMEStateParAfterEol:
02177 if (*i + 1 >= srcLen || src[*i + 1] != '\\')
02178 break;
02179 *token = kNMETokenLineBreak;
02180 *i += 2;
02181 skipBlanks(src, srcLen, i);
02182 return TRUE;
02183 default:
02184
02185 break;
02186 }
02187 break;
02188 case '=':
02189 if (state == kNMEStatePar || state == kNMEStatePre
02190 || state == kNMEStatePreAfterEol || verbatim)
02191 break;
02192 if (state == kNMEStateHeading)
02193 {
02194
02195 for (k = *i; k < srcLen && src[k] == '='; k++)
02196 ;
02197 skipBlanks(src, srcLen, &k);
02198 if (k < srcLen && !isEol(src[k]))
02199 break;
02200 while (*i < srcLen && src[*i] == '=')
02201 (*i)++;
02202 }
02203 else
02204 {
02205 for (*headingLevel = 0;
02206 *i < srcLen && src[*i] == '=';
02207 (*i)++, (*headingLevel)++)
02208 ;
02209 if (options & kNMEProcessOptNoH1 && *headingLevel == 1)
02210 *headingLevel = 2;
02211 if (*headingLevel > outputFormat->maxHeadingLevel)
02212 *headingLevel = outputFormat->maxHeadingLevel;
02213 }
02214 *token = kNMETokenHeading;
02215 return TRUE;
02216 case '*':
02217 case '#':
02218 if (verbatim)
02219 break;
02220 switch (state)
02221 {
02222 case kNMEStatePar:
02223 case kNMEStateHeading:
02224 if (*i + 1 >= srcLen || src[*i + 1] != src[*i])
02225 break;
02226 if (options & (src[*i] == '*'
02227 ? kNMEProcessOptNoBold : kNMEProcessOptNoMonospace))
02228 break;
02229 *token = kNMETokenStyle;
02230 *style = src[*i] == '*' ? kNMEStyleBold : kNMEStyleMonospace;
02231 *i += 2;
02232 return TRUE;
02233 case kNMEStateBetweenPar:
02234 case kNMEStateParAfterEol:
02235 if (nesting == 0
02236 || src[*i] == (listNum[0] == kNMEListNumUL ? '*' : '#')
02237 && (nesting == 1 || *i + 1 >= srcLen || src[*i] != src[*i + 1]
02238 || (src[*i] == '*'
02239 ? options & kNMEProcessOptNoBold || listNum[1] == kNMEListNumUL
02240 : src[*i] == '#'
02241 ? options & kNMEProcessOptNoMonospace || listNum[1] > 0
02242 : TRUE)))
02243 {
02244
02245 if (*i + 1 >= srcLen
02246 || src[*i + 1] != src[*i]
02247 || nesting > 0 && *i + 2 < srcLen
02248 || options & (src[*i] == '*'
02249 ? kNMEProcessOptNoBold
02250 : kNMEProcessOptNoMonospace))
02251 goto tokenLI;
02252 }
02253
02254 if (*i + 1 < srcLen && src[*i + 1] == src[*i])
02255 {
02256 *token = kNMETokenStyle;
02257 *style = src[*i] == '*' ? kNMEStyleBold : kNMEStyleMonospace;
02258 *i += 2;
02259 return TRUE;
02260 }
02261
02262 default:
02263
02264 break;
02265 }
02266 break;
02267 case '/':
02268 if (*i >= 2 && src[*i - 1] == ':'
02269 && (isAlphaNum(src[*i - 2])
02270 || src[*i - 2] == '+' || src[*i - 2] == '-' || src[*i - 2] == '.')
02271 && *i + 2 < srcLen
02272 && !isBlank(src[*i + 2]) && !isEol(src[*i + 2]))
02273 break;
02274
02275 case '_':
02276 case '^':
02277 case ',':
02278 if (verbatim
02279 || options & kNMEProcessOptNoItalic && src[*i] == '/'
02280 || options & kNMEProcessOptNoUnderline && src[*i] == '_'
02281 || options & kNMEProcessOptNoSubSuperscript && src[*i] == '^'
02282 || options & kNMEProcessOptNoSubSuperscript && src[*i] == ',')
02283 break;
02284 switch (state)
02285 {
02286 case kNMEStatePar:
02287 case kNMEStateHeading:
02288 case kNMEStateBetweenPar:
02289 case kNMEStateParAfterEol:
02290 if (*i + 1 >= srcLen || src[*i + 1] != src[*i])
02291 break;
02292 *token = kNMETokenStyle;
02293 *style = src[*i] == '/' ? kNMEStyleItalic
02294 : src[*i] == '^' ? kNMEStyleSuperscript
02295 : src[*i] == ',' ? kNMEStyleSubscript
02296 : kNMEStyleUnderline;
02297 *i += 2;
02298 return TRUE;
02299 default:
02300
02301 break;
02302 }
02303 break;
02304 case ';':
02305 if (verbatim
02306 || options & kNMEProcessOptNoDL
02307 || state != kNMEStateBetweenPar && state != kNMEStateParAfterEol)
02308 break;
02309
02310 if (nesting == 0 || listNum[0] == kNMEListNumDT || listNum[0] == kNMEListNumDD)
02311 goto tokenLI;
02312
02313 break;
02314 case ':':
02315 switch (state)
02316 {
02317 case kNMEStatePar:
02318 if (verbatim || nesting == 0 || listNum[nesting - 1] != kNMEListNumDT)
02319 break;
02320 *token = kNMETokenDD;
02321 (*i)++;
02322 skipBlanks(src, srcLen, i);
02323 return TRUE;
02324 case kNMEStateParAfterEol:
02325 if (verbatim || nesting > 0
02326 && listNum[0] != kNMEListNumDT && listNum[0] != kNMEListNumDD
02327 && listNum[0] != kNMEListIndented)
02328 break;
02329 if (nesting > 0 && listNum[0] != kNMEListIndented)
02330 goto tokenLI;
02331
02332 case kNMEStateBetweenPar:
02333 if (options & kNMEProcessOptNoIndentedPar)
02334 break;
02335
02336 for (*itemNesting = 0;
02337 *i < srcLen && src[*i] == ':';
02338 (*i)++, (*itemNesting)++)
02339 ;
02340
02341 if (*itemNesting > kMaxNesting)
02342 *itemNesting = kMaxNesting;
02343 *token = kNMETokenLI;
02344 return TRUE;
02345 default:
02346
02347 break;
02348 }
02349 break;
02350 case '|':
02351 if (verbatim
02352 || options & kNMEProcessOptNoTable)
02353 break;
02354 switch (state)
02355 {
02356 case kNMEStatePar:
02357 if (nesting == 0
02358 || listNum[nesting - 1] != kNMEListNumTableCell
02359 && listNum[nesting - 1] != kNMEListNumTableHCell)
02360 break;
02361
02362 case kNMEStateParAfterEol:
02363 case kNMEStateBetweenPar:
02364 if (*i + 1 < srcLen && src[*i + 1] == '=')
02365 {
02366 *token = kNMETokenTableHCell;
02367 *i += 2;
02368 }
02369 else
02370 {
02371 *token = kNMETokenTableCell;
02372 (*i)++;
02373 }
02374 skipBlanks(src, srcLen, i);
02375 if (state == kNMEStatePar)
02376 if (*i >= srcLen)
02377 return FALSE;
02378 else if (isEol(src[*i]))
02379 {
02380
02381 (*i)++;
02382 if (src[*i - 1] == '\r' && *i < srcLen && src[*i] == '\n')
02383 (*i)++;
02384 *token = kNMETokenEOL;
02385 return TRUE;
02386 }
02387 return TRUE;
02388 default:
02389
02390 break;
02391 }
02392 break;
02393 case '}':
02394 if (!(options & kNMEProcessOptNoImage)
02395 && !verbatim && *i + 1 < srcLen && src[*i + 1] == '}'
02396 && findStyleInStyleStack(styleStack, styleNesting,
02397 kNMEStyleImage, NULL)
02398 && state != kNMEStatePre && state != kNMEStatePreAfterEol)
02399 {
02400 *token = kNMETokenImageEnd;
02401 *i += 2;
02402 return TRUE;
02403 }
02404
02405 case '{':
02406
02407 if (*i + 2 >= srcLen || src[*i + 1] != src[*i]
02408 || src[*i + 2] != src[*i])
02409 {
02410 if (!(options & kNMEProcessOptNoImage)
02411 && !verbatim && *i + 1 < srcLen && src[*i + 1] == '{'
02412 && !findStyleInStyleStack(styleStack, styleNesting,
02413 kNMEStyleImage, NULL)
02414 && state != kNMEStatePre && state != kNMEStatePreAfterEol)
02415 {
02416 *token = kNMETokenImageBegin;
02417 *i += 2;
02418 return TRUE;
02419 }
02420 break;
02421 }
02422 if (src[*i] == '}' && *i + 3 < srcLen && src[*i + 3] == '}')
02423 break;
02424 switch (state)
02425 {
02426 case kNMEStatePar:
02427 case kNMEStateHeading:
02428 if (verbatim ? src[*i] == '{' : src[*i] == '}')
02429 break;
02430 *token = kNMETokenStyle;
02431 *style = kNMEStyleVerbatim;
02432 *i += 3;
02433 return TRUE;
02434 case kNMEStateBetweenPar:
02435 case kNMEStateParAfterEol:
02436
02437 k = *i + 3;
02438 skipBlanks(src, srcLen, &k);
02439 if (k < srcLen && !isEol(src[k]))
02440 {
02441 *token = kNMETokenStyle;
02442 *style = kNMEStyleVerbatim;
02443 }
02444 else
02445 *token = kNMETokenPre;
02446 *i += 3;
02447 return TRUE;
02448 case kNMEStatePreAfterEol:
02449 if (src[*i] == '}')
02450 {
02451 *token = kNMETokenPre;
02452 *i += 3;
02453 return TRUE;
02454 }
02455 break;
02456 default:
02457
02458 break;
02459 }
02460 break;
02461 case ']':
02462 if (!findStyleInStyleStack(styleStack, styleNesting,
02463 kNMEStyleLink, NULL))
02464 break;
02465
02466 case '[':
02467
02468 if (verbatim || options & kNMEProcessOptNoLink)
02469 break;
02470 switch (state)
02471 {
02472 case kNMEStatePar:
02473 case kNMEStateHeading:
02474 case kNMEStateBetweenPar:
02475 case kNMEStateParAfterEol:
02476 if (*i + 1 >= srcLen || src[*i + 1] != src[*i])
02477 break;
02478 *token = src[*i] == '[' ? kNMETokenLinkBegin : kNMETokenLinkEnd;
02479 *i += 2;
02480 return TRUE;
02481 default:
02482
02483 break;
02484 }
02485 break;
02486 case '<':
02487
02488 if (verbatim
02489 || options & kNMEProcessOptNoPlugin
02490 || state == kNMEStatePre || state == kNMEStatePreAfterEol
02491 || *i + 2 >= srcLen
02492 || src[*i + 1] != '<')
02493 break;
02494 if (*i + 2 < srcLen && src[*i + 2] == '<')
02495 {
02496 *token = kNMETokenPlaceholder;
02497 *i += 3;
02498 }
02499 else
02500 {
02501 *token = kNMETokenPlugin;
02502 *i += 2;
02503 }
02504 if (state == kNMEStateBetweenPar || state == kNMEStateParAfterEol)
02505 {
02506
02507 k = *i;
02508 skipBlanks(src, srcLen, &k);
02509 if (k >= srcLen || isEol(src[k]))
02510 if (*token == kNMETokenPlaceholder)
02511 *token = kNMETokenPlaceholderBlock;
02512 else
02513 *token = kNMETokenPluginBlock;
02514 }
02515 return TRUE;
02516 case '-':
02517
02518 if (options & kNMEProcessOptNoHRule
02519 || state != kNMEStateBetweenPar && state != kNMEStateParAfterEol
02520 || *i + 3 >= srcLen
02521 || src[*i + 1] != '-' || src[*i + 2] != '-'
02522 || src[*i + 3] != '-')
02523 break;
02524
02525 while (*i < srcLen && src[*i] == '-')
02526 (*i)++;
02527 *token = kNMETokenHR;
02528 return TRUE;
02529 case '~':
02530
02531 if (verbatim
02532 || options & kNMEProcessOptNoEscape
02533 || state == kNMEStatePre || state == kNMEStatePreAfterEol
02534 || *i + 1 >= srcLen
02535 || isEol(src[*i + 1]) || isBlank(src[*i + 1]))
02536 break;
02537 *i += 2;
02538 *token = kNMETokenChar;
02539 return TRUE;
02540 }
02541
02542 *token = kNMETokenChar;
02543 (*i)++;
02544 return TRUE;
02545
02546 tokenLI:
02547
02548 for (*itemNesting = 0;
02549 *i < srcLen
02550 && (src[*i] == '*' || src[*i] == '#' || src[*i] == ';'
02551 || src[*i] == ':' && *itemNesting < nesting)
02552 && (*itemNesting >= nesting
02553 || (listNum[*itemNesting] == kNMEListNumUL ? src[*i] == '*'
02554 : listNum[*itemNesting] == kNMEListNumDT
02555 || listNum[*itemNesting] == kNMEListNumDD
02556 ? src[*i] == ';' || src[*i] == ':'
02557 : src[*i] == '#'));
02558 (*i)++, (*itemNesting)++)
02559 ;
02560
02561 if (*itemNesting > kMaxNesting)
02562 *itemNesting = kMaxNesting;
02563 *token = src[*i - 1] == ':' ? kNMETokenDD : kNMETokenLI;
02564 return TRUE;
02565 }
02566
02577 static NMEErr swapBuffers(NMEText *src, NMEInt *srcLen,
02578 NMEContext *context,
02579 NMEInt *commonLen,
02580 NMEInt destLen0)
02581 {
02582 NMEInt k;
02583 NMEText tmp;
02584
02585
02586 if (*srcLen + context->destLen - context->srcIndex > context->bufSize
02587 || destLen0 > context->bufSize)
02588 return kNMEErrNotEnoughMemory;
02589
02590
02591 for (k = 0; k < *srcLen - context->srcIndex; k++)
02592 context->dest[context->destLen + k] = (*src)[context->srcIndex + k];
02593 for (k = 0; k < destLen0 - *commonLen; k++)
02594 (*src)[*commonLen + k] = context->dest[*commonLen + k];
02595 *commonLen = destLen0;
02596 *srcLen += context->destLen - context->srcIndex;
02597 context->srcIndexOffset -= context->destLen - context->srcIndex;
02598 context->srcIndex = context->destLen = destLen0;
02599 tmp = *src; *src = context->dest; context->dest = tmp;
02600
02601 return kNMEErrOk;
02602 }
02603
02604 NMEErr NMEProcess(NMEConstText nmeText, NMEInt nmeTextLen,
02605 NMEText buf, NMEInt bufSize,
02606 NMEInt options,
02607 NMEConstText eol,
02608 NMEOutputFormat const *outputFormat,
02609 NMEInt fontSize,
02610 NMEText *output,
02611 NMEInt *outputLen,
02612 NMEInt *outputUCS16Len)
02613 {
02614
02615
02616
02617
02618
02619
02620
02621
02622
02623
02624
02625
02626
02627
02628
02629
02630
02631 NMEInt destLenTmp;
02632 NMEInt commonLen;
02633 NMEInt i0;
02634 NMEInt noAutoOrPluginLen;
02635 NMEBoolean reparseOutput;
02636 NMEState state;
02637 NMEToken token;
02638 NMEInt headingNum[kMaxNumberedHeadingLevels];
02639 NMEInt headingFlags;
02640 NMEInt currentIndent;
02641 NMEStyle styleStack[kNMEStylesCount];
02642 NMEInt styleNesting;
02643 NMEStyle newStyle = (NMEStyle)0;
02644 NMEInt itemNesting = 0;
02645 NMEInt headingLevel = 0;
02646 NMEInt headingLevel0 = 0;
02647 NMEContext context;
02648 NMEErr err;
02649
02650 #define HOOK(cb, l, it, e, m) \
02651 do { \
02652 if (outputFormat->cb) \
02653 { \
02654 err = outputFormat->cb(l, it, e, m, i0 + context.srcIndexOffset, \
02655 &context, \
02656 outputFormat->hookData); \
02657 if (err != kNMEErrOk) \
02658 return err; \
02659 } \
02660 } while (0)
02661
02662
02663 if (!outputFormat)
02664 outputFormat = &NMEOutputFormatText;
02665 context.fontSize = fontSize > 0 ? fontSize : outputFormat->defFontSize;
02666 context.options = options;
02667 context.eol = eol;
02668 context.ctrlChar = outputFormat->ctrlChar;
02669 context.xref = (options & kNMEProcessOptXRef) != 0;
02670 setContext(context, 0, 0);
02671
02672
02673 if (nmeTextLen > bufSize / 2)
02674 return kNMEErrNotEnoughMemory;
02675 context.src = buf;
02676 context.srcLen = nmeTextLen;
02677 for (i0 = 0; i0 < nmeTextLen; i0++)
02678 buf[i0] = nmeText[i0];
02679 context.dest = buf + bufSize / 2;
02680 context.bufSize = bufSize / 2;
02681
02682
02683 context.outputFormat = outputFormat;
02684 context.destLen = context.col = 0;
02685 context.destLenUCS16 = 0;
02686 commonLen = noAutoOrPluginLen = 0;
02687 context.currentIndent = 0;
02688 state = kNMEStateBetweenPar;
02689 context.nesting = 0;
02690 styleNesting = 0;
02691 headingNum[0] = -1;
02692 nextHeading(&headingFlags, headingNum, 1);
02693 headingFlags = 0;
02694
02695
02696 if (!(options & kNMEProcessOptNoPreAndPost)
02697 && !NMEAddString(outputFormat->beginDoc, -1, context.ctrlChar, &context))
02698 return kNMEErrNotEnoughMemory;
02699
02700
02701 for (context.srcIndex = context.srcIndexOffset = 0; context.srcIndex < context.srcLen; )
02702 {
02703
02704 if (context.destLen + kNMETokenTab >= context.bufSize)
02705 return kNMEErrNotEnoughMemory;
02706
02707
02708 if (state != kNMEStatePre && state != kNMEStatePreAfterEol
02709 && context.srcIndex >= noAutoOrPluginLen
02710 && !(options & kNMEProcessOptNoPlugin)
02711 && outputFormat->autoconverts)
02712 {
02713 NMEInt k;
02714
02715 for (k = 0; outputFormat->autoconverts[k].cb; k++)
02716 {
02717 destLenTmp = context.destLen;
02718 if (outputFormat->autoconverts[k].cb(context.src, context.srcLen, &context.srcIndex,
02719 &context,
02720 outputFormat->autoconverts[k].userData))
02721 {
02722 noAutoOrPluginLen = context.destLen;
02723 CheckError(swapBuffers(&context.src, &context.srcLen,
02724 &context,
02725 &commonLen,
02726 destLenTmp));
02727 break;
02728 }
02729 }
02730 }
02731
02732
02733 i0 = context.srcIndex;
02734 headingLevel0 = headingLevel;
02735 if (!parseNextToken(context.src, context.srcLen, &context.srcIndex,
02736 state,
02737 styleNesting > 0 && styleStack[styleNesting - 1] == kNMEStyleVerbatim,
02738 context.nesting, context.listNum,
02739 styleStack, styleNesting,
02740 outputFormat,
02741 &token,
02742 &headingLevel,
02743 &itemNesting,
02744 &newStyle,
02745 options))
02746 break;
02747
02748
02749 switch (state)
02750 {
02751 case kNMEStateBetweenPar:
02752 switch (token)
02753 {
02754 case kNMETokenChar:
02755 HOOK(parHookFun, kNMEHookLevelPar, 0, TRUE, "p");
02756 if (!NMEAddString(outputFormat->beginPar, -1,
02757 context.ctrlChar, &context))
02758 return kNMEErrNotEnoughMemory;
02759 if (outputFormat->charHookFun)
02760 CheckError(outputFormat->charHookFun(i0 + context.srcIndexOffset,
02761 &context,
02762 outputFormat->charHookData));
02763 if (outputFormat->encodeCharFun)
02764 {
02765 context.srcIndex--;
02766 CheckError(outputFormat->encodeCharFun(context.src,
02767 context.srcLen, &context.srcIndex,
02768 &context,
02769 outputFormat->encodeCharData));
02770 }
02771 else
02772 {
02773 context.dest[context.destLen++] = context.src[context.srcIndex - 1];
02774 if (isFirstUTF8Byte(context.src[context.srcIndex - 1]))
02775 context.destLenUCS16++;
02776 context.col++;
02777 }
02778 CheckError(checkWordwrap(&context, outputFormat));
02779 state = kNMEStatePar;
02780 break;
02781 case kNMETokenSpace:
02782 case kNMETokenTab:
02783
02784 break;
02785 case kNMETokenEOL:
02786
02787 break;
02788 case kNMETokenHeading:
02789 for (; headingLevel0 > headingLevel; headingLevel0--)
02790 if ((headingFlags >> headingLevel0 - 1) & 1)
02791 HOOK(divHookFun, headingLevel0, 0, FALSE, "=");
02792 nextHeading(&headingFlags, headingNum, headingLevel);
02793 context.level = headingLevel;
02794 context.item = headingLevel <= kMaxNumberedHeadingLevels
02795 && options & (headingLevel == 1
02796 ? kNMEProcessOptH1Num : kNMEProcessOptH2Num)
02797 ? headingNum[headingLevel - 1]
02798 : 0;
02799 HOOK(divHookFun, context.level, context.item, TRUE, "=");
02800 HOOK(parHookFun, context.level, context.item, TRUE, "=");
02801 if (!NMEAddString(outputFormat->beginHeading, -1,
02802 context.ctrlChar, &context))
02803 return kNMEErrNotEnoughMemory;
02804 context.level = 0;
02805 state = kNMEStateHeading;
02806 skipBlanks(context.src, context.srcLen, &context.srcIndex);
02807 break;
02808 case kNMETokenLineBreak:
02809 HOOK(parHookFun, kNMEHookLevelPar, 0, TRUE, "p");
02810 if (!NMEAddString(outputFormat->beginPar, -1,
02811 context.ctrlChar, &context)
02812 || !NMEAddString(outputFormat->lineBreak, -1,
02813 context.ctrlChar, &context))
02814 return kNMEErrNotEnoughMemory;
02815 state = kNMEStatePar;
02816 break;
02817 case kNMETokenPre:
02818 HOOK(parHookFun, kNMEHookLevelPar, 0, TRUE, "{{{");
02819 if (!NMEAddString(outputFormat->beginPre, -1,
02820 context.ctrlChar, &context)
02821 || !NMEAddString(outputFormat->beginPreLine, -1,
02822 context.ctrlChar, &context))
02823 return kNMEErrNotEnoughMemory;
02824 state = kNMEStatePreAfterEol;
02825
02826 if (context.srcIndex < context.srcLen && context.src[context.srcIndex] == '\r')
02827 context.srcIndex++;
02828 if (context.srcIndex < context.srcLen && context.src[context.srcIndex] == '\n')
02829 context.srcIndex++;
02830 break;
02831 case kNMETokenLI:
02832
02833 for (context.nesting = 0; context.nesting < itemNesting; context.nesting++)
02834 {
02835 context.listNum[context.nesting]
02836 = context.src[context.srcIndex - itemNesting + context.nesting] == '*'
02837 ? kNMEListNumUL
02838 : context.src[context.srcIndex - itemNesting + context.nesting] == ';'
02839 ? kNMEListNumDT
02840 : context.src[context.srcIndex - itemNesting + context.nesting] == ':'
02841 ? kNMEListIndented
02842 : 1;
02843 context.level = context.nesting + 1;
02844 HOOK(divHookFun, context.level, 0, TRUE,
02845 context.listNum[context.nesting] == kNMEListNumUL ? "*"
02846 : context.listNum[context.nesting] == kNMEListNumDT ? ";"
02847 : context.listNum[context.nesting] == kNMEListIndented ? ":"
02848 : "#");
02849 if (!NMEAddString(context.listNum[context.nesting] == kNMEListNumUL
02850 ? outputFormat->beginUL
02851 : context.listNum[context.nesting] == kNMEListNumDT
02852 ? outputFormat->beginDL
02853 : context.listNum[context.nesting] == kNMEListIndented
02854 ? outputFormat->beginIndented
02855 : outputFormat->beginOL,
02856 -1,
02857 context.ctrlChar, &context))
02858 return kNMEErrNotEnoughMemory;
02859 context.level = 0;
02860 }
02861
02862 skipBlanks(context.src, context.srcLen, &context.srcIndex);
02863
02864 currentIndent = context.nesting * outputFormat->indentSpaces;
02865 setContext(context, context.nesting, context.listNum[context.nesting - 1]);
02866 HOOK(parHookFun, context.level, context.item, TRUE,
02867 context.listNum[context.nesting - 1] == kNMEListNumUL ? "*"
02868 : context.listNum[context.nesting - 1] == kNMEListNumDT ? ";"
02869 : context.listNum[context.nesting - 1] == kNMEListIndented ? ":"
02870 : "#");
02871 if (!NMEAddString(context.listNum[context.nesting - 1] == kNMEListNumUL
02872 ? outputFormat->beginULItem
02873 : context.listNum[context.nesting - 1] == kNMEListNumDT
02874 ? outputFormat->beginDT
02875 : context.listNum[context.nesting - 1] == kNMEListIndented
02876 ? outputFormat->beginIndentedPar
02877 : outputFormat->beginOLItem,
02878 -1,
02879 context.ctrlChar, &context))
02880 return kNMEErrNotEnoughMemory;
02881 setContext(context, 0, 0);
02882 state = kNMEStatePar;
02883 break;
02884 case kNMETokenTableCell:
02885 case kNMETokenTableHCell:
02886
02887 context.listNum[context.nesting++]
02888 = token == kNMETokenTableCell
02889 ? kNMEListNumTableCell
02890 : kNMEListNumTableHCell;
02891 currentIndent = context.nesting * outputFormat->indentSpaces;
02892 state = kNMEStatePar;
02893 context.level = context.nesting - 1;
02894 HOOK(divHookFun, kNMEHookLevelPar, 0, TRUE, "|");
02895 if (!NMEAddString(outputFormat->beginTable, -1,
02896 context.ctrlChar, &context)
02897 || !NMEAddString(outputFormat->beginTableRow, -1,
02898 context.ctrlChar, &context))
02899 return kNMEErrNotEnoughMemory;
02900 HOOK(parHookFun, kNMEHookLevelPar, 0, TRUE,
02901 token == kNMETokenTableCell ? "|" : "|=");
02902 if (!NMEAddString(token == kNMETokenTableCell
02903 ? outputFormat->beginTableCell
02904 : outputFormat->beginTableHCell,
02905 -1,
02906 context.ctrlChar, &context))
02907 return kNMEErrNotEnoughMemory;
02908 context.level = 0;
02909 break;
02910 case kNMETokenHR:
02911 HOOK(parHookFun, kNMEHookLevelPar, 0, TRUE, "----");
02912 if (!NMEAddString(outputFormat->horRule, -1,
02913 context.ctrlChar, &context))
02914 return kNMEErrNotEnoughMemory;
02915 HOOK(parHookFun, kNMEHookLevelPar, 0, FALSE, "----");
02916 break;
02917 case kNMETokenStyle:
02918 HOOK(parHookFun, kNMEHookLevelPar, 0, TRUE, "p");
02919 if (!NMEAddString(outputFormat->beginPar, -1,
02920 context.ctrlChar, &context))
02921 return kNMEErrNotEnoughMemory;
02922 CheckError(processStyleTag(styleStack, &styleNesting,
02923 newStyle,
02924 i0,
02925 outputFormat, &context));
02926 state = kNMEStatePar;
02927 break;
02928 case kNMETokenLinkBegin:
02929 case kNMETokenImageBegin:
02930 HOOK(parHookFun, kNMEHookLevelPar, 0, TRUE, "p");
02931 if (!NMEAddString(outputFormat->beginPar, -1,
02932 context.ctrlChar, &context))
02933 return kNMEErrNotEnoughMemory;
02934 CheckError(addLinkBegin(token == kNMETokenImageBegin,
02935 styleStack, &styleNesting,
02936 i0, outputFormat, &context));
02937 state = kNMEStatePar;
02938 break;
02939 case kNMETokenPlugin:
02940 case kNMETokenPluginBlock:
02941 case kNMETokenPlaceholder:
02942 case kNMETokenPlaceholderBlock:
02943 {
02944 NMEInt pluginIndex;
02945
02946 pluginIndex = findPlugin(context.src, context.srcLen, context.srcIndex,
02947 token == kNMETokenPlaceholder
02948 || token == kNMETokenPlaceholderBlock,
02949 outputFormat);
02950 if (pluginIndex >= 0
02951 && !(outputFormat->plugins[pluginIndex].options
02952 & kNMEPluginOptBetweenPar))
02953 {
02954
02955 HOOK(parHookFun, kNMEHookLevelPar, 0, TRUE, "p");
02956 if (!NMEAddString(outputFormat->beginPar, -1,
02957 context.ctrlChar, &context))
02958 return kNMEErrNotEnoughMemory;
02959 state = kNMEStatePar;
02960 }
02961 destLenTmp = context.destLen;
02962 CheckError(addPlugin(token == kNMETokenPluginBlock
02963 || token == kNMETokenPlaceholderBlock,
02964 token == kNMETokenPlaceholder
02965 || token == kNMETokenPlaceholderBlock,
02966 options, outputFormat, &context,
02967 &reparseOutput));
02968 if (reparseOutput)
02969 {
02970 CheckError(swapBuffers(&context.src, &context.srcLen,
02971 &context,
02972 &commonLen,
02973 destLenTmp));
02974
02975 }
02976 }
02977 break;
02978 case kNMETokenDD:
02979 case kNMETokenLinkEnd:
02980 case kNMETokenImageEnd:
02981
02982 return kNMEErrInternal;
02983 }
02984 break;
02985 case kNMEStatePar:
02986 switch (token)
02987 {
02988 case kNMETokenChar:
02989 if (outputFormat->charHookFun)
02990 CheckError(outputFormat->charHookFun(i0 + context.srcIndexOffset,
02991 &context,
02992 outputFormat->charHookData));
02993 if (outputFormat->encodeCharFun)
02994 {
02995 context.srcIndex--;
02996 CheckError(outputFormat->encodeCharFun(context.src, context.srcLen, &context.srcIndex,
02997 &context,
02998 outputFormat->encodeCharData));
02999 }
03000 else
03001 {
03002 context.dest[context.destLen++] = context.src[context.srcIndex - 1];
03003 if (isFirstUTF8Byte(context.src[context.srcIndex - 1]))
03004 context.destLenUCS16++;
03005 context.col++;
03006 }
03007 CheckError(checkWordwrap(&context, outputFormat));
03008 break;
03009 case kNMETokenSpace:
03010 case kNMETokenTab:
03011 skipBlanks(context.src, context.srcLen, &context.srcIndex);
03012
03013 if (context.srcIndex < context.srcLen && !isEol(context.src[context.srcIndex]))
03014 {
03015 if (!NMEAddString(outputFormat->space, -1,
03016 context.ctrlChar, &context))
03017 return kNMEErrNotEnoughMemory;
03018 CheckError(checkWordwrap(&context, outputFormat));
03019 }
03020 break;
03021 case kNMETokenLineBreak:
03022 if (!NMEAddString(outputFormat->lineBreak, -1,
03023 context.ctrlChar, &context))
03024 return kNMEErrNotEnoughMemory;
03025 CheckError(checkWordwrap(&context, outputFormat));
03026 break;
03027 case kNMETokenEOL:
03028 state = kNMEStateParAfterEol;
03029 break;
03030 case kNMETokenDD:
03031 context.level = context.nesting;
03032 CheckError(flushStyleTags(styleStack, &styleNesting,
03033 i0,
03034 outputFormat, &context));
03035 CheckError(addEndPar(FALSE, outputFormat, &context));
03036 HOOK(parHookFun, context.level, context.item, TRUE, ";:");
03037 if (!NMEAddString(outputFormat->beginDD, -1,
03038 context.ctrlChar, &context))
03039 return kNMEErrNotEnoughMemory;
03040 CheckError(checkWordwrap(&context, outputFormat));
03041 context.level = 0;
03042 context.listNum[context.nesting - 1] = kNMEListNumDD;
03043 break;
03044 case kNMETokenTableCell:
03045 case kNMETokenTableHCell:
03046
03047 while (context.destLen > 0 && context.dest[context.destLen - 1] == ' ')
03048 {
03049 context.destLen--;
03050 context.destLenUCS16--;
03051 }
03052
03053 context.level = context.nesting;
03054 CheckError(flushStyleTags(styleStack, &styleNesting,
03055 i0,
03056 outputFormat, &context));
03057 if (!NMEAddString(context.listNum[context.nesting - 1] == kNMEListNumTableCell
03058 ? outputFormat->endTableCell
03059 : outputFormat->endTableHCell,
03060 -1,
03061 context.ctrlChar, &context))
03062 return kNMEErrNotEnoughMemory;
03063 CheckError(checkWordwrap(&context, outputFormat));
03064 HOOK(parHookFun, kNMEHookLevelPar, 0, FALSE,
03065 context.listNum[context.nesting - 1] == kNMEListNumTableCell
03066 ? "|" : "|=");
03067 CheckError(checkWordwrap(&context, outputFormat));
03068 HOOK(parHookFun, kNMEHookLevelPar, 0, TRUE,
03069 token == kNMETokenTableCell ? "|" : "|=");
03070 if (!NMEAddString(token == kNMETokenTableCell
03071 ? outputFormat->beginTableCell
03072 : outputFormat->beginTableHCell,
03073 -1,
03074 context.ctrlChar, &context))
03075 return kNMEErrNotEnoughMemory;
03076 CheckError(checkWordwrap(&context, outputFormat));
03077 context.level = 0;
03078 context.listNum[context.nesting - 1] = token == kNMETokenTableCell
03079 ? kNMEListNumTableCell
03080 : kNMEListNumTableHCell;
03081 break;
03082 case kNMETokenStyle:
03083 case kNMETokenLinkEnd:
03084 case kNMETokenImageEnd:
03085 CheckError(processStyleTag(styleStack, &styleNesting,
03086 token == kNMETokenLinkEnd ? kNMEStyleLink
03087 : token == kNMETokenImageEnd ? kNMEStyleImage : newStyle,
03088 i0,
03089 outputFormat, &context));
03090 break;
03091 case kNMETokenLinkBegin:
03092 case kNMETokenImageBegin:
03093 CheckError(addLinkBegin(token == kNMETokenImageBegin,
03094 styleStack, &styleNesting,
03095 i0, outputFormat, &context));
03096 break;
03097 case kNMETokenPlugin:
03098 case kNMETokenPluginBlock:
03099 case kNMETokenPlaceholder:
03100 case kNMETokenPlaceholderBlock:
03101 {
03102 NMEInt pluginIndex;
03103
03104 pluginIndex = findPlugin(context.src, context.srcLen, context.srcIndex,
03105 token == kNMETokenPlaceholder
03106 || token == kNMETokenPlaceholderBlock,
03107 outputFormat);
03108 if (pluginIndex >= 0
03109 && outputFormat->plugins[pluginIndex].options
03110 & kNMEPluginOptBetweenPar)
03111 {
03112
03113 CheckError(flushStyleTags(styleStack, &styleNesting,
03114 i0,
03115 outputFormat, &context));
03116 CheckError(addEndPar(TRUE, outputFormat, &context));
03117 state = kNMEStateBetweenPar;
03118 }
03119 destLenTmp = context.destLen;
03120 CheckError(addPlugin(token == kNMETokenPluginBlock
03121 || token == kNMETokenPlaceholderBlock,
03122 token == kNMETokenPlaceholder
03123 || token == kNMETokenPlaceholderBlock,
03124 options, outputFormat, &context,
03125 &reparseOutput));
03126 if (reparseOutput)
03127 {
03128 CheckError(swapBuffers(&context.src, &context.srcLen,
03129 &context,
03130 &commonLen,
03131 destLenTmp));
03132
03133 }
03134 }
03135 break;
03136 case kNMETokenHeading:
03137 case kNMETokenLI:
03138 case kNMETokenHR:
03139 case kNMETokenPre:
03140
03141 return kNMEErrInternal;
03142 }
03143 break;
03144 case kNMEStateParAfterEol:
03145 switch (token)
03146 {
03147 case kNMETokenChar:
03148 if (options & kNMEProcessOptNoMultilinePar
03149 || context.nesting > 0
03150 && (context.listNum[context.nesting - 1] == kNMEListNumTableCell
03151 || context.listNum[context.nesting - 1] == kNMEListNumTableHCell))
03152 {
03153
03154 CheckError(flushStyleTags(styleStack, &styleNesting,
03155 i0,
03156 outputFormat, &context));
03157 CheckError(addEndPar(TRUE, outputFormat, &context));
03158 if (!NMEAddString(outputFormat->beginPar, -1,
03159 context.ctrlChar, &context))
03160 return kNMEErrNotEnoughMemory;
03161 currentIndent = 0;
03162 }
03163 else
03164 if (!NMEAddString(outputFormat->space, -1,
03165 context.ctrlChar, &context))
03166 return kNMEErrNotEnoughMemory;
03167 CheckError(checkWordwrap(&context, outputFormat));
03168 if (outputFormat->charHookFun)
03169 CheckError(outputFormat->charHookFun(i0 + context.srcIndexOffset,
03170 &context,
03171 outputFormat->charHookData));
03172 if (outputFormat->encodeCharFun)
03173 {
03174 context.srcIndex--;
03175 CheckError(outputFormat->encodeCharFun(context.src, context.srcLen, &context.srcIndex,
03176 &context,
03177 outputFormat->encodeCharData));
03178 }
03179 else
03180 {
03181 context.dest[context.destLen++] = context.src[context.srcIndex - 1];
03182 if (isFirstUTF8Byte(context.src[context.srcIndex - 1]))
03183 context.destLenUCS16++;
03184 context.col++;
03185 }
03186 state = kNMEStatePar;
03187 break;
03188 case kNMETokenSpace:
03189 case kNMETokenTab:
03190
03191 break;
03192 case kNMETokenEOL:
03193 CheckError(flushStyleTags(styleStack, &styleNesting,
03194 i0,
03195 outputFormat, &context));
03196 CheckError(addEndPar(TRUE, outputFormat, &context));
03197 state = kNMEStateBetweenPar;
03198 currentIndent = context.nesting * outputFormat->indentSpaces;
03199 break;
03200 case kNMETokenDD:
03201 context.level = context.nesting;
03202 CheckError(flushStyleTags(styleStack, &styleNesting,
03203 i0,
03204 outputFormat, &context));
03205 CheckError(addEndPar(FALSE, outputFormat, &context));
03206 if (context.listNum[context.nesting - 1] != kNMEListNumDT
03207 && outputFormat->emptyDT)
03208 {
03209 if (!NMEAddString(outputFormat->emptyDT, -1,
03210 context.ctrlChar, &context))
03211 return kNMEErrNotEnoughMemory;
03212 CheckError(checkWordwrap(&context, outputFormat));
03213 }
03214
03215 skipBlanks(context.src, context.srcLen, &context.srcIndex);
03216
03217 HOOK(parHookFun, context.level, context.item, TRUE, ";:");
03218 if (!NMEAddString(outputFormat->beginDD, -1, context.ctrlChar, &context))
03219 return kNMEErrNotEnoughMemory;
03220 CheckError(checkWordwrap(&context, outputFormat));
03221 context.level = 0;
03222 context.listNum[context.nesting - 1] = kNMEListNumDD;
03223 state = kNMEStatePar;
03224 break;
03225 case kNMETokenLineBreak:
03226 if (!NMEAddString(outputFormat->lineBreak, -1,
03227 context.ctrlChar, &context))
03228 return kNMEErrNotEnoughMemory;
03229 CheckError(checkWordwrap(&context, outputFormat));
03230 break;
03231 case kNMETokenPre:
03232 CheckError(flushStyleTags(styleStack, &styleNesting,
03233 i0,
03234 outputFormat, &context));
03235 CheckError(addEndPar(TRUE, outputFormat, &context));
03236 HOOK(parHookFun, kNMEHookLevelPar, 0, TRUE, "{{{");
03237 if (!NMEAddString(outputFormat->beginPre, -1,
03238 context.ctrlChar, &context)
03239 || !NMEAddString(outputFormat->beginPreLine, -1,
03240 context.ctrlChar, &context))
03241 return kNMEErrNotEnoughMemory;
03242 CheckError(checkWordwrap(&context, outputFormat));
03243 state = kNMEStatePreAfterEol;
03244 currentIndent = 0;
03245
03246 if (context.srcIndex < context.srcLen && context.src[context.srcIndex] == '\r')
03247 context.srcIndex++;
03248 if (context.srcIndex < context.srcLen && context.src[context.srcIndex] == '\n')
03249 context.srcIndex++;
03250 break;
03251 case kNMETokenHeading:
03252 CheckError(flushStyleTags(styleStack, &styleNesting,
03253 i0,
03254 outputFormat, &context));
03255 CheckError(addEndPar(TRUE, outputFormat, &context));
03256 for (; headingLevel0 > headingLevel; headingLevel0--)
03257 if ((headingFlags >> headingLevel0 - 1) & 1)
03258 HOOK(divHookFun, headingLevel0, 0, FALSE, "=");
03259 nextHeading(&headingFlags, headingNum, headingLevel);
03260 context.level = headingLevel;
03261 context.item = headingLevel <= kMaxNumberedHeadingLevels
03262 && options & (headingLevel == 1
03263 ? kNMEProcessOptH1Num : kNMEProcessOptH2Num)
03264 ? headingNum[headingLevel - 1]
03265 : 0;
03266 HOOK(divHookFun, context.level, context.item, TRUE, "=");
03267 HOOK(parHookFun, context.level, context.item, TRUE, "=");
03268 if (!NMEAddString(outputFormat->beginHeading, -1,
03269 context.ctrlChar, &context))
03270 return kNMEErrNotEnoughMemory;
03271 currentIndent = 0;
03272 context.level = 0;
03273 state = kNMEStateHeading;
03274 skipBlanks(context.src, context.srcLen, &context.srcIndex);
03275 break;
03276 case kNMETokenLI:
03277
03278 CheckError(flushStyleTags(styleStack, &styleNesting,
03279 i0,
03280 outputFormat, &context));
03281 CheckError(addEndPar(FALSE, outputFormat, &context));
03282
03283 while (context.nesting > itemNesting)
03284 {
03285 setContext(context, context.nesting, context.listNum[context.nesting - 1]);
03286 context.nesting--;
03287 if (!NMEAddString(context.listNum[context.nesting] == kNMEListNumUL
03288 ? outputFormat->endUL
03289 : context.listNum[context.nesting] == kNMEListNumDT
03290 ? outputFormat->endDL
03291 : context.listNum[context.nesting] == kNMEListIndented
03292 ? outputFormat->endIndented
03293 : outputFormat->endOL,
03294 -1,
03295 context.ctrlChar, &context))
03296 return kNMEErrNotEnoughMemory;
03297 HOOK(divHookFun, context.level, context.item, FALSE,
03298 context.listNum[context.nesting] == kNMEListNumUL ? "*"
03299 : context.listNum[context.nesting] == kNMEListNumDT ? ";"
03300 : context.listNum[context.nesting] == kNMEListIndented ? ":"
03301 : "#");
03302 }
03303 setContext(context, 0, 0);
03304
03305 for (; context.nesting < itemNesting; context.nesting++)
03306 {
03307 context.listNum[context.nesting]
03308 = context.src[context.srcIndex - itemNesting + context.nesting] == '*'
03309 ? kNMEListNumUL
03310 : context.src[context.srcIndex - itemNesting + context.nesting] == ';'
03311 ? kNMEListNumDT
03312 : context.src[context.srcIndex - itemNesting + context.nesting] == ':'
03313 ? kNMEListIndented
03314 : 1;
03315 context.level = context.nesting + 1;
03316 HOOK(divHookFun, context.level, context.item, TRUE,
03317 context.listNum[context.nesting] == kNMEListNumUL ? "*"
03318 : context.listNum[context.nesting] == kNMEListNumDT ? ";"
03319 : context.listNum[context.nesting] == kNMEListIndented ? ":"
03320 : "#");
03321 if (!NMEAddString(context.listNum[context.nesting] == kNMEListNumUL
03322 ? outputFormat->beginUL
03323 : context.listNum[context.nesting] == kNMEListNumDT
03324 ? outputFormat->beginDL
03325 : context.listNum[context.nesting] == kNMEListIndented
03326 ? outputFormat->beginIndented
03327 : outputFormat->beginOL,
03328 -1,
03329 context.ctrlChar, &context))
03330 return kNMEErrNotEnoughMemory;
03331 }
03332 currentIndent = context.nesting * outputFormat->indentSpaces;
03333
03334 skipBlanks(context.src, context.srcLen, &context.srcIndex);
03335
03336 if (context.listNum[context.nesting - 1] == kNMEListNumDD)
03337 context.listNum[context.nesting - 1] = kNMEListNumDT;
03338
03339 setContext(context, context.nesting, context.listNum[context.nesting - 1]);
03340 HOOK(parHookFun, context.level, context.item, TRUE,
03341 context.listNum[context.nesting - 1] == kNMEListNumUL ? "*"
03342 : context.listNum[context.nesting - 1] == kNMEListNumDT ? ";"
03343 : context.listNum[context.nesting - 1] == kNMEListIndented ? ":"
03344 : "#");
03345 if (!NMEAddString(context.listNum[context.nesting - 1] == kNMEListNumUL
03346 ? outputFormat->beginULItem
03347 : context.listNum[context.nesting - 1] == kNMEListNumDT
03348 ? outputFormat->beginDT
03349 : context.listNum[context.nesting - 1] == kNMEListIndented
03350 ? outputFormat->beginIndentedPar
03351 : outputFormat->beginOLItem,
03352 -1,
03353 context.ctrlChar, &context))
03354 return kNMEErrNotEnoughMemory;
03355 setContext(context, 0, 0);
03356 state = kNMEStatePar;
03357 break;
03358 case kNMETokenTableCell:
03359 case kNMETokenTableHCell:
03360
03361 CheckError(flushStyleTags(styleStack, &styleNesting,
03362 i0,
03363 outputFormat, &context));
03364 CheckError(addEndPar(FALSE, outputFormat, &context));
03365 if (context.nesting == 0
03366 || context.listNum[context.nesting - 1] != kNMEListNumTableCell
03367 && context.listNum[context.nesting - 1] != kNMEListNumTableHCell)
03368 {
03369
03370 context.nesting++;
03371 context.level = context.nesting - 1;
03372 HOOK(divHookFun, kNMEHookLevelPar, 0, TRUE, "|");
03373 if (!NMEAddString(outputFormat->beginTable, -1,
03374 context.ctrlChar, &context))
03375 return kNMEErrNotEnoughMemory;
03376 }
03377 currentIndent = context.nesting * outputFormat->indentSpaces;
03378
03379 context.listNum[context.nesting - 1] = token == kNMETokenTableCell
03380 ? kNMEListNumTableCell
03381 : kNMEListNumTableHCell;
03382
03383 context.level = context.nesting - 1;
03384 if (!NMEAddString(outputFormat->beginTableRow, -1,
03385 context.ctrlChar, &context))
03386 return kNMEErrNotEnoughMemory;
03387 HOOK(parHookFun, kNMEHookLevelPar, 0, TRUE,
03388 token == kNMETokenTableCell ? "|" : "|=");
03389 if (!NMEAddString(token == kNMETokenTableCell
03390 ? outputFormat->beginTableCell
03391 : outputFormat->beginTableHCell,
03392 -1,
03393 context.ctrlChar, &context))
03394 return kNMEErrNotEnoughMemory;
03395 CheckError(checkWordwrap(&context, outputFormat));
03396 context.level = 0;
03397 state = kNMEStatePar;
03398 break;
03399 case kNMETokenHR:
03400 CheckError(flushStyleTags(styleStack, &styleNesting,
03401 i0,
03402 outputFormat, &context));
03403 CheckError(addEndPar(TRUE, outputFormat, &context));
03404 HOOK(parHookFun, kNMEHookLevelPar, 0, TRUE, "----");
03405 if (!NMEAddString(outputFormat->horRule, -1,
03406 context.ctrlChar, &context))
03407 return kNMEErrNotEnoughMemory;
03408 CheckError(checkWordwrap(&context, outputFormat));
03409 HOOK(parHookFun, kNMEHookLevelPar, 0, FALSE, "----");
03410 currentIndent = 0;
03411 state = kNMEStateBetweenPar;
03412 break;
03413 case kNMETokenStyle:
03414 case kNMETokenLinkEnd:
03415 case kNMETokenImageEnd:
03416 if (!NMEAddString(outputFormat->space, -1,
03417 context.ctrlChar, &context))
03418 return kNMEErrNotEnoughMemory;
03419 CheckError(checkWordwrap(&context, outputFormat));
03420 CheckError(processStyleTag(styleStack, &styleNesting,
03421 token == kNMETokenLinkEnd
03422 ? kNMEStyleLink
03423 : token == kNMETokenImageEnd
03424 ? kNMEStyleImage
03425 : newStyle,
03426 i0,
03427 outputFormat, &context));
03428 state = kNMEStatePar;
03429 break;
03430 case kNMETokenLinkBegin:
03431 case kNMETokenImageBegin:
03432 if (!NMEAddString(outputFormat->space, -1,
03433 context.ctrlChar, &context))
03434 return kNMEErrNotEnoughMemory;
03435 CheckError(addLinkBegin(token == kNMETokenImageBegin,
03436 styleStack, &styleNesting,
03437 i0, outputFormat, &context));
03438 state = kNMEStatePar;
03439 break;
03440 case kNMETokenPlugin:
03441 case kNMETokenPluginBlock:
03442 case kNMETokenPlaceholder:
03443 case kNMETokenPlaceholderBlock:
03444 {
03445 NMEInt pluginIndex;
03446
03447 pluginIndex = findPlugin(context.src, context.srcLen, context.srcIndex,
03448 token == kNMETokenPlaceholder
03449 || token == kNMETokenPlaceholderBlock,
03450 outputFormat);
03451 if (pluginIndex >= 0
03452 && outputFormat->plugins[pluginIndex].options
03453 & kNMEPluginOptBetweenPar)
03454 {
03455
03456 CheckError(flushStyleTags(styleStack, &styleNesting,
03457 i0,
03458 outputFormat, &context));
03459 CheckError(addEndPar(TRUE, outputFormat, &context));
03460 state = kNMEStateBetweenPar;
03461 }
03462 else
03463 {
03464
03465 if (!NMEAddString(outputFormat->space, -1,
03466 context.ctrlChar, &context))
03467 return kNMEErrNotEnoughMemory;
03468 state = kNMEStatePar;
03469 }
03470 destLenTmp = context.destLen;
03471 CheckError(addPlugin(token == kNMETokenPluginBlock
03472 || token == kNMETokenPlaceholderBlock,
03473 token == kNMETokenPlaceholder
03474 || token == kNMETokenPlaceholderBlock,
03475 options, outputFormat, &context,
03476 &reparseOutput));
03477 if (reparseOutput)
03478 {
03479 CheckError(swapBuffers(&context.src, &context.srcLen,
03480 &context,
03481 &commonLen,
03482 destLenTmp));
03483
03484 }
03485 }
03486 break;
03487 }
03488 break;
03489 case kNMEStatePreAfterEol:
03490 if (token == kNMETokenPre)
03491 {
03492 if (!NMEAddString(outputFormat->endPre, -1,
03493 context.ctrlChar, &context))
03494 return kNMEErrNotEnoughMemory;
03495 HOOK(parHookFun, kNMEHookLevelPar, 0, FALSE, "{{{");
03496 state = kNMEStateBetweenPar;
03497 break;
03498 }
03499
03500 if (!NMEAddString(outputFormat->beginPreLine, -1,
03501 context.ctrlChar, &context))
03502 return kNMEErrNotEnoughMemory;
03503 state = kNMEStatePre;
03504
03505 if (token == kNMETokenSpace)
03506 {
03507
03508 NMEInt k;
03509
03510 for (k = context.srcIndex; k < context.srcLen && context.src[k] == ' '; k++)
03511 ;
03512 if (k + 3 <= context.srcLen && context.src[k] == '}'
03513 && context.src[k + 1] == '}' && context.src[k + 2] == '}')
03514 break;
03515 }
03516
03517 case kNMEStatePre:
03518 switch (token)
03519 {
03520 case kNMETokenChar:
03521 if (outputFormat->encodeCharPreFun)
03522 {
03523 context.srcIndex--;
03524 CheckError(outputFormat->encodeCharPreFun(context.src, context.srcLen, &context.srcIndex,
03525 &context,
03526 outputFormat->encodeCharPreData));
03527 }
03528 else
03529 {
03530 context.dest[context.destLen++] = context.src[context.srcIndex - 1];
03531 if (isFirstUTF8Byte(context.src[context.srcIndex - 1]))
03532 context.destLenUCS16++;
03533 context.col++;
03534 }
03535 break;
03536 case kNMETokenSpace:
03537 if (outputFormat->encodeCharPreFun)
03538 {
03539 NMEInt tmp = 0;
03540
03541 CheckError(outputFormat->encodeCharPreFun(" ", 1, &tmp,
03542 &context,
03543 outputFormat->encodeCharPreData));
03544 }
03545 else
03546 {
03547 context.dest[context.destLen++] = ' ';
03548 context.destLenUCS16++;
03549 context.col++;
03550 }
03551 break;
03552 case kNMETokenTab:
03553 do
03554 {
03555 if (outputFormat->encodeCharPreFun)
03556 {
03557 NMEInt tmp = 0;
03558
03559 CheckError(outputFormat->encodeCharPreFun(" ", 1, &tmp,
03560 &context,
03561 outputFormat->encodeCharPreData));
03562 }
03563 else
03564 {
03565 context.dest[context.destLen++] = ' ';
03566 context.destLenUCS16++;
03567 context.col++;
03568 }
03569 } while (context.col % kTabWidth != 0);
03570 break;
03571 case kNMETokenEOL:
03572 if (!NMEAddString(outputFormat->endPreLine, -1,
03573 context.ctrlChar, &context))
03574 return kNMEErrNotEnoughMemory;
03575 state = kNMEStatePreAfterEol;
03576 break;
03577 default:
03578
03579 return kNMEErrInternal;
03580 }
03581 break;
03582 case kNMEStateHeading:
03583 switch (token)
03584 {
03585 case kNMETokenChar:
03586 if (outputFormat->charHookFun)
03587 CheckError(outputFormat->charHookFun(i0 + context.srcIndexOffset,
03588 &context,
03589 outputFormat->charHookData));
03590 if (outputFormat->encodeCharFun)
03591 {
03592 context.srcIndex--;
03593 CheckError(outputFormat->encodeCharFun(context.src, context.srcLen, &context.srcIndex,
03594 &context,
03595 outputFormat->encodeCharData));
03596 }
03597 else
03598 {
03599 context.dest[context.destLen++] = context.src[context.srcIndex - 1];
03600 if (isFirstUTF8Byte(context.src[context.srcIndex - 1]))
03601 context.destLenUCS16++;
03602 context.col++;
03603 }
03604 CheckError(checkWordwrap(&context, outputFormat));
03605 break;
03606 case kNMETokenSpace:
03607 case kNMETokenTab:
03608 if (state == kNMEStatePar)
03609 skipBlanks(context.src, context.srcLen, &context.srcIndex);
03610
03611 if (context.srcIndex < context.srcLen && !isEol(context.src[context.srcIndex]))
03612 {
03613 if (!NMEAddString(outputFormat->space, -1,
03614 context.ctrlChar, &context))
03615 return kNMEErrNotEnoughMemory;
03616 CheckError(checkWordwrap(&context, outputFormat));
03617 }
03618 break;
03619 case kNMETokenHeading:
03620
03621 skipBlanks(context.src, context.srcLen, &context.srcIndex);
03622 case kNMETokenEOL:
03623 context.level = headingLevel;
03624 CheckError(flushStyleTags(styleStack, &styleNesting,
03625 i0,
03626 outputFormat, &context));
03627 if (!NMEAddString(outputFormat->endHeading, -1,
03628 context.ctrlChar, &context))
03629 return kNMEErrNotEnoughMemory;
03630 CheckError(checkWordwrap(&context, outputFormat));
03631 HOOK(parHookFun, context.level, 0, FALSE, "=");
03632 context.level = 0;
03633 state = kNMEStateBetweenPar;
03634 break;
03635 case kNMETokenLineBreak:
03636 if (!NMEAddString(outputFormat->lineBreak, -1,
03637 context.ctrlChar, &context))
03638 return kNMEErrNotEnoughMemory;
03639 CheckError(checkWordwrap(&context, outputFormat));
03640 break;
03641 case kNMETokenStyle:
03642 case kNMETokenLinkEnd:
03643 case kNMETokenImageEnd:
03644 CheckError(processStyleTag(styleStack, &styleNesting,
03645 token == kNMETokenLinkEnd
03646 ? kNMEStyleLink
03647 : token == kNMETokenImageEnd
03648 ? kNMEStyleImage : newStyle,
03649 i0,
03650 outputFormat, &context));
03651 break;
03652 case kNMETokenLinkBegin:
03653 case kNMETokenImageBegin:
03654 CheckError(addLinkBegin(token == kNMETokenImageBegin,
03655 styleStack, &styleNesting,
03656 i0, outputFormat, &context));
03657 break;
03658 case kNMETokenPlugin:
03659 case kNMETokenPluginBlock:
03660 case kNMETokenPlaceholder:
03661 case kNMETokenPlaceholderBlock:
03662 destLenTmp = context.destLen;
03663 CheckError(addPlugin(token == kNMETokenPluginBlock
03664 || token == kNMETokenPlaceholderBlock,
03665 token == kNMETokenPlaceholder
03666 || token == kNMETokenPlaceholderBlock,
03667