00001
00008
00009
00010 #include "NME.h"
00011
00012 #define kMaxNesting 8 ///< maximum nesting of lists
00013
00014
00015
00017 enum
00018 {
00019 kNMEListNumUL = -100,
00020 kNMEListNumDT,
00021 kNMEListNumDD,
00022 kNMEListIndented,
00023 kNMEListNumTableCell,
00024 kNMEListNumTableHCell
00025 };
00026
00028 #define isBlank(c) ((c) == ' ' || (c) == '\t')
00029
00031 #define isEol(c) ((c) == '\r' || (c) == '\n')
00032
00034 #define isDigit(c) ((c) >= '0' && (c) <= '9')
00035
00037 #define isAlphaNum(c) \
00038 (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z') || isDigit(c))
00039
00041 #define isFirstUTF8Byte(c) \
00042 (((c) & 0x80) == 0 || ((c) & 0xe0) == 0xc0 || ((c) & 0xf0) == 0xe0)
00043
00045 #define kMaxNumberedHeadingLevels 2
00046
00048 #define kMaxSectionLevels 4
00049
00051 #define kTabWidth 4
00052
00054 #define CheckError(c) \
00055 do { err = (c); if (err != kNMEErrOk) return err; } while (0)
00056
00060 typedef enum NMEState
00061 {
00062 kNMEStatePar,
00063 kNMEStatePre,
00064 kNMEStateHeading,
00065 kNMEStateParAfterEol,
00066 kNMEStatePreAfterEol,
00067 kNMEStateBetweenPar
00068 } NMEState;
00069
00071 typedef enum NMEToken
00072 {
00073 kNMETokenChar,
00074 kNMETokenSpace,
00075 kNMETokenTab,
00076 kNMETokenEOL,
00077 kNMETokenHeading,
00078 kNMETokenLineBreak,
00079 kNMETokenLI,
00080 kNMETokenDD,
00081 kNMETokenTableCell,
00082 kNMETokenTableHCell,
00083 kNMETokenHR,
00084 kNMETokenPre,
00085 kNMETokenStyle,
00086 kNMETokenLinkBegin,
00087 kNMETokenLinkEnd,
00088 kNMETokenImageBegin,
00089 kNMETokenImageEnd,
00090 kNMETokenPlugin,
00091 kNMETokenPluginBlock,
00092 kNMETokenPlaceholder,
00093 kNMETokenPlaceholderBlock
00094 } NMEToken;
00095
00097 typedef enum NMEStyle
00098 {
00099 kNMEStyleBold = 0,
00100
00101 kNMEStyleItalic,
00102 kNMEStyleUnderline,
00103 kNMEStyleSuperscript,
00104 kNMEStyleSubscript,
00105 kNMEStyleMonospace,
00106 kNMEStyleVerbatim,
00107 kNMEStyleLink,
00108 kNMEStyleImage,
00109 kNMEStylesCount
00110 } NMEStyle;
00111
00113 struct NMEContextStruct
00114 {
00115 NMEText dest;
00116 NMEInt destLen;
00117
00118 NMEInt destLenUCS16;
00119
00120 NMEText src;
00121 NMEInt srcIndex;
00122 NMEInt srcIndexOffset;
00123 NMEInt srcLen;
00124 NMEInt srcLineNum;
00125 NMEInt srcIndexForLineNum;
00126
00127 NMEInt bufSize;
00128
00129 NMEInt currentIndent;
00130 NMEInt col;
00131
00132 NMEInt listNum[kMaxNesting];
00133 NMEInt nesting;
00134
00135 NMEOutputFormat const *outputFormat;
00136 NMEConstText eol;
00137 NMEChar ctrlChar;
00138 NMEInt options;
00139
00140 NMEInt fontSize;
00141
00142 NMEInt level;
00143 NMEInt item;
00144 NMEInt linkOffset;
00145 NMEInt linkLength;
00146
00147 NMEBoolean xref;
00148 };
00149
00151 #define setContext(c, l, i) do { (c).level = l; (c).item = (i) < 0 ? 0 : (i); } while (0)
00152
00158 static void skipBlanks(NMEConstText src, NMEInt srcLen, NMEInt *i)
00159 {
00160 while (*i < srcLen && isBlank(src[*i]))
00161 (*i)++;
00162 }
00163
00169 static void execOperator(NMEInt stack[], NMEInt *stackDepth, NMEChar op)
00170 {
00171 switch (op)
00172 {
00173 case '+':
00174 stack[*stackDepth-2] += stack[*stackDepth-1];
00175 break;
00176 case '-':
00177 stack[*stackDepth-2] -= stack[*stackDepth-1];
00178 break;
00179 case '*':
00180 stack[*stackDepth-2] *= stack[*stackDepth-1];
00181 break;
00182 case '/':
00183 stack[*stackDepth-2] /= stack[*stackDepth-1];
00184 break;
00185 case '=':
00186 stack[*stackDepth-2] = stack[*stackDepth-2] == stack[*stackDepth-1];
00187 break;
00188 case '!':
00189 stack[*stackDepth-2] = stack[*stackDepth-2] != stack[*stackDepth-1];
00190 break;
00191 case '<':
00192 stack[*stackDepth-2] = stack[*stackDepth-2] < stack[*stackDepth-1];
00193 break;
00194 case '>':
00195 stack[*stackDepth-2] = stack[*stackDepth-2] > stack[*stackDepth-1];
00196 break;
00197 case '&':
00198 case '?':
00199 if (stack[*stackDepth-2] != 0)
00200 stack[*stackDepth-2] = stack[*stackDepth-1];
00201 break;
00202 case '|':
00203 case ':':
00204 if (stack[*stackDepth-2] == 0)
00205 stack[*stackDepth-2] = stack[*stackDepth-1];
00206 break;
00207 }
00208 (*stackDepth)--;
00209 }
00210
00215 static void updateLineNum(NMEContext *context)
00216 {
00217 for ( ;
00218 context->srcIndexForLineNum < context->srcIndex;
00219 context->srcIndexForLineNum++)
00220 if (context->src[context->srcIndexForLineNum] == '\n'
00221 || (context->src[context->srcIndexForLineNum] == '\r'
00222 && (context->srcIndexForLineNum + 1 == context->srcIndex
00223 || context->src[context->srcIndexForLineNum + 1] != '\n')))
00224 context->srcLineNum++;
00225 }
00226
00234 static NMEInt evalExpression(NMEConstText src, NMEInt srcLen,
00235 NMEContext *context)
00236 {
00237 #define kExprStackSize 16 ///< size of operand and operator stacks
00238 #define kExprErrorValue 1 ///< default value if error
00239 static struct
00240 {
00241 NMEChar op;
00242 NMEInt priority;
00243 } const opList[] =
00244 {
00245 {'?', 1}, {':', 1},
00246 {'|', 2},
00247 {'&', 3},
00248 {'=', 4}, {'!', 4}, {'<', 4}, {'>', 4},
00249 {'+', 5}, {'-', 5},
00250 {'*', 6}, {'/', 6},
00251 {'\0', 0}
00252 };
00253 NMEInt stack[kExprStackSize];
00254 NMEInt stackDepth;
00255 NMEInt opStack[kExprStackSize];
00256
00257 NMEInt opStackDepth;
00258 NMEInt i, j;
00259
00260 for (i = stackDepth = opStackDepth = 0; ; )
00261 {
00262 skipBlanks(src, srcLen, &i);
00263
00264 if (i >= srcLen)
00265 return 1;
00266
00267
00268 while (i < srcLen && src[i] == '(' && opStackDepth < kExprStackSize)
00269 {
00270 opStack[opStackDepth++] = -1;
00271 i++;
00272 skipBlanks(src, srcLen, &i);
00273 }
00274
00275
00276 if (isDigit(src[i]))
00277 for (stack[stackDepth] = 0; i < srcLen && isDigit(src[i]); i++)
00278 stack[stackDepth] = 10 * stack[stackDepth] + src[i] - '0';
00279 else
00280 switch (src[i++])
00281 {
00282 case 'l':
00283 stack[stackDepth] = context->level;
00284 break;
00285 case 'i':
00286 stack[stackDepth] = context->item;
00287 break;
00288 case 's':
00289 stack[stackDepth] = context->fontSize;
00290 break;
00291 case 'o':
00292 stack[stackDepth] = context->srcIndex;
00293 break;
00294 case 'L':
00295 updateLineNum(context);
00296 stack[stackDepth] = context->srcLineNum;
00297 break;
00298 case 'p':
00299 stack[stackDepth] = context->destLen;
00300 break;
00301 case 'x':
00302 stack[stackDepth] = context->xref;
00303 break;
00304 default:
00305 if (src[i - 1] >= 'A' && src[i - 1] <= 'Z')
00306 {
00307
00308 if (context->outputFormat->getVarFun)
00309 stack[stackDepth]
00310 = context->outputFormat->getVarFun(src[i - 1],
00311 context->outputFormat->getVarData);
00312 else
00313 stack[stackDepth] = 0;
00314 }
00315 else
00316 return kExprErrorValue;
00317 }
00318 stackDepth++;
00319
00320 skipBlanks(src, srcLen, &i);
00321
00322
00323 if (i >= srcLen)
00324 {
00325
00326 for ( ; opStackDepth > 0; opStackDepth--)
00327 if (opStack[opStackDepth - 1] >= 0)
00328 execOperator(stack, &stackDepth,
00329 opList[opStack[opStackDepth - 1]].op);
00330 return stack[0];
00331 }
00332
00333
00334 while (i < srcLen && src[i] == ')')
00335 {
00336
00337 for ( ; opStackDepth > 0 && opStack[opStackDepth - 1] >= 0; opStackDepth--)
00338 execOperator(stack, &stackDepth,
00339 opList[opStack[opStackDepth - 1]].op);
00340 if (opStackDepth > 0)
00341 opStackDepth--;
00342
00343
00344 i++;
00345 skipBlanks(src, srcLen, &i);
00346 }
00347
00348
00349 for (j = 0; opList[j].op && src[i] != opList[j].op; j++)
00350 ;
00351 if (!opList[j].op)
00352 return kExprErrorValue;
00353
00354
00355 for ( ; opStackDepth > 0
00356 && opStack[opStackDepth - 1] >= 0
00357 && opList[j].priority <= opList[opStack[opStackDepth - 1]].priority;
00358 opStackDepth--)
00359 execOperator(stack, &stackDepth, opList[opStack[opStackDepth - 1]].op);
00360
00361
00362 if (opStackDepth >= kExprStackSize)
00363 return kExprErrorValue;
00364
00365
00366 opStack[opStackDepth++] = j;
00367
00368
00369 i++;
00370 }
00371 }
00372
00373 NMEBoolean NMEAddString(NMEConstText str,
00374 NMEInt strLen,
00375 NMEChar ctrlChar,
00376 NMEContext *context)
00377 {
00378 NMEInt k;
00379
00380 if (!str)
00381 return TRUE;
00382
00383 if (strLen < 0)
00384 for (strLen = 0; str[strLen]; strLen++)
00385 ;
00386
00387 for (k = 0; k < strLen; )
00388 if (context->destLen
00389 + (str[k] == '\n' ? (context->eol[1] ? 1 : 0)
00390 + context->currentIndent : 0)
00391 >= context->bufSize)
00392 return FALSE;
00393 else if (str[k] == '\n')
00394 {
00395 context->dest[context->destLen++] = context->eol[0];
00396 context->destLenUCS16++;
00397 if (context->eol[1])
00398 {
00399 context->dest[context->destLen++] = context->eol[1];
00400 context->destLenUCS16++;
00401 }
00402 k++;
00403 context->col = context->currentIndent;
00404 }
00405 else if (k + 2 < strLen
00406 && str[k] == ctrlChar
00407 && (str[k + 1] == '{' || (str[k + 1] == ctrlChar && str[k + 2] == '{')))
00408 {
00409 NMEBoolean replicate;
00410 NMEText repStr;
00411 NMEInt len, result, i, repStrLen, col0, destLenUCS160;
00412
00413 replicate = str[k + 1] == ctrlChar;
00414 if (replicate)
00415 k++;
00416 for (k += 2, len = 0; k + len < strLen && str[k + len] != '}'; len++)
00417 ;
00418 if (k + len >= strLen)
00419 return TRUE;
00420 result = evalExpression(str + k, len, context);
00421 k += len + 1;
00422 if (replicate)
00423 {
00424
00425 for (len = 0;
00426 k + len + 1 < strLen
00427 && (str[k + len] != ctrlChar
00428 || str[k + len + 1] != ctrlChar);
00429 len++)
00430 ;
00431
00432
00433
00434 repStr = context->dest + context->destLen;
00435 destLenUCS160 = context->destLenUCS16;
00436 col0 = context->col;
00437 if (!NMEAddString(str + k, len, context->ctrlChar, context))
00438 return FALSE;
00439 repStrLen = context->dest + context->destLen - repStr;
00440 context->destLen = repStr - context->dest;
00441 context->destLenUCS16 = destLenUCS160;
00442 context->col = col0;
00443
00444
00445 if (result > 100)
00446 result = 100;
00447 if (result > 0 && context->destLen + result * repStrLen > context->bufSize)
00448 return FALSE;
00449 for (; result > 0; result--)
00450 {
00451 for (i = 0; i < repStrLen; i++)
00452 {
00453 context->dest[context->destLen++] = repStr[i];
00454 if (isFirstUTF8Byte(repStr[i]))
00455 context->destLenUCS16++;
00456 }
00457 context->col += repStrLen;
00458 }
00459
00460 k += len + 2;
00461 }
00462 else
00463 {
00464
00465 if (context->destLen + 12 > context->bufSize)
00466 return FALSE;
00467 if (result < 0)
00468 {
00469 context->dest[context->destLen++] = '-';
00470 context->destLenUCS16++;
00471 result = -result;
00472 context->col++;
00473 }
00474 for (i = 1000000000; i >= 1; i /= 10)
00475 if (result >= i || i == 1)
00476 {
00477 context->dest[context->destLen++] = '0' + (result / i) % 10;
00478 context->destLenUCS16++;
00479 context->col++;
00480 }
00481 }
00482 }
00483 else if (k + 2 < strLen && str[k] == ctrlChar && str[k + 1] == 'L')
00484 {
00485 NMEConstText str = NMECurrentListNesting(context);
00486 NMEInt i;
00487
00488 if (context->destLen + kMaxNesting > context->bufSize)
00489 return FALSE;
00490 for (i = 0; str[i]; i++)
00491 {
00492 context->dest[context->destLen++] = str[i];
00493 context->destLenUCS16++;
00494 context->col++;
00495 }
00496 k += 2;
00497 }
00498 else
00499 {
00500 if (isFirstUTF8Byte(str[k]))
00501 context->destLenUCS16++;
00502 context->dest[context->destLen++] = str[k++];
00503 context->col++;
00504 }
00505
00506 return TRUE;
00507 }
00508
00509 NMEErr NMEAddRawString(NMEConstText str,
00510 NMEInt strLen,
00511 NMEContext *context)
00512 {
00513 NMEInt i;
00514 NMEText d = context->dest + context->destLen;
00515
00516 if (!str)
00517 return kNMEErrOk;
00518
00519 if (strLen < 0)
00520 for (strLen = 0; str[strLen]; strLen++)
00521 ;
00522
00523 if (context->destLen + strLen > context->bufSize)
00524 return kNMEErrNotEnoughMemory;
00525
00526 for (i = 0; i < strLen; i++)
00527 {
00528 d[i] = str[i];
00529 if (isFirstUTF8Byte(str[i]))
00530 context->destLenUCS16++;
00531 }
00532 context->destLen += strLen;
00533 context->col = 0;
00534
00535 return kNMEErrOk;
00536 }
00537
00538 NMEErr NMECopySource(NMEInt length,
00539 NMEBoolean copy,
00540 NMEBoolean encodeChar,
00541 NMEContext *context)
00542 {
00543 if (context->srcIndexOffset + context->srcIndex + length > context->srcLen)
00544 length = context->srcLen - (context->srcIndexOffset + context->srcIndex);
00545 if (copy)
00546 {
00547 NMEInt i;
00548 NMEErr err;
00549
00550 if (encodeChar && context->outputFormat->encodeCharFun)
00551 {
00552 NMEEncodeCharFun fun = context->outputFormat->encodeCharFun;
00553 void *data = context->outputFormat->encodeCharData;
00554
00555 for (i = context->srcIndex; i < context->srcIndex + length; )
00556 CheckError(fun(context->src, context->srcLen, &i, context, data));
00557 }
00558 else
00559 {
00560 NMEConstText s = context->src + context->srcIndex;
00561 NMEText d = context->dest + context->destLen;
00562
00563 if (context->destLen + length > context->bufSize)
00564 return kNMEErrNotEnoughMemory;
00565
00566 for (i = 0; i < length; i++)
00567 {
00568 d[i] = s[i];
00569 if (isFirstUTF8Byte(s[i]))
00570 context->destLenUCS16++;
00571 }
00572 context->srcIndex += length;
00573 context->destLen += length;
00574 }
00575 }
00576
00577 context->srcIndex += length;
00578 context->col = 0;
00579 return kNMEErrOk;
00580 }
00581
00582 void NMEResetOutput(NMEContext *context)
00583 {
00584 context->destLen = 0;
00585 }
00586
00593 static NMEErr checkWordwrap(NMEContext *context,
00594 NMEOutputFormat const *outputFormat)
00595 {
00596 if (outputFormat && outputFormat->textWidth > 0
00597 && context->col >= outputFormat->textWidth)
00598 {
00599
00600
00601 NMEInt i, j, dist;
00602 NMEWordwrapPermission perm;
00603
00604 perm = kNMEWordwrapNo;
00605 if (outputFormat->wordwrapPermFun)
00606 {
00607
00608 for (i = context->destLen - 1;
00609 i >= 0 && !isEol(context->dest[i]);
00610 i--)
00611 {
00612 perm = outputFormat->wordwrapPermFun(context->dest, context->destLen, i,
00613 context, outputFormat->wordwrapPermData);
00614 if (perm != kNMEWordwrapNo)
00615 break;
00616 }
00617 }
00618 else
00619 {
00620
00621 for (i = context->destLen - 1;
00622 i >= 0 && !isEol(context->dest[i]);
00623 i--)
00624 if (isBlank(context->dest[i]))
00625 {
00626 perm = kNMEWordwrapReplaceChar;
00627 break;
00628 }
00629 }
00630
00631
00632 if (perm == kNMEWordwrapNo)
00633 return kNMEErrOk;
00634
00635
00636 dist = (context->eol[1] ? 2 : 1)
00637 + (perm == kNMEWordwrapReplaceChar ? -1 : 0)
00638 + context->currentIndent;
00639 if (dist > 0)
00640 {
00641 if (context->destLen + dist > context->bufSize)
00642 return kNMEErrNotEnoughMemory;
00643 for (j = context->destLen - 1; j > i; j--)
00644 context->dest[j + dist] = context->dest[j];
00645 context->destLen += dist;
00646 context->destLenUCS16 += dist;
00647 }
00648
00649
00650 if (perm == kNMEWordwrapInsert)
00651 i++;
00652 context->dest[i++] = context->eol[0];
00653 if (context->eol[1])
00654 context->dest[i++] = context->eol[1];
00655 for (j = 0; j < context->currentIndent; j++)
00656 context->dest[i++] = ' ';
00657 context->col = context->destLen - i + context->currentIndent;
00658 }
00659
00660 return kNMEErrOk;
00661 }
00662
00664 NMEEncodeCharDict const NMEXMLCharDict[] =
00665 {
00666 {'<', "<"},
00667 {'>', ">"},
00668 {'"', """},
00669 {'&', "&"},
00670 {0, NULL}
00671 };
00672
00674 static NMEEncodeCharDict const latexCharDict[] =
00675 {
00676 {'#', "\\#"},
00677 {'^', "$\\,\\hat{}\\,$"},
00678 {'~', "$\\,\\tilde{}\\,$"},
00679 {'\\', "$\\backslash$"},
00680 {'|', "$|$"},
00681 {'\'', "\'{}"},
00682 {'`', "`{}"},
00683 {'<', "$<$"},
00684 {'>', "$>$"},
00685 {'{', "\\{"},
00686 {'}', "\\}"},
00687 {0, NULL}
00688 };
00689
00690 NMEErr NMEEncodeCharFunDict(NMEConstText src, NMEInt srcLen, NMEInt *srcIx,
00691 NMEContext *context, void *data)
00692 {
00693 NMEInt i;
00694 (void)srcLen;
00695
00696 for (i = 0; ((NMEEncodeCharDict const *)data)[i].str; i++)
00697 if (src[*srcIx] == ((NMEEncodeCharDict const *)data)[i].ch)
00698 {
00699 if (!NMEAddString(((NMEEncodeCharDict const *)data)[i].str, -1,
00700 context->ctrlChar, context))
00701 return kNMEErrNotEnoughMemory;
00702 (*srcIx)++;
00703 return kNMEErrOk;
00704 }
00705 if (!NMEAddString(&src[(*srcIx)++], 1, context->ctrlChar, context))
00706 return kNMEErrNotEnoughMemory;
00707 return kNMEErrOk;
00708 }
00709
00720 static NMEErr encodeCharFunNME(NMEConstText src, NMEInt srcLen, NMEInt *srcIx,
00721 NMEContext *context, void *data)
00722 {
00723 NMEInt i;
00724 NMEConstText output;
00725 NMEInt outputLength;
00726 NMEChar prev, str[2];
00727 static const struct
00728 {
00729 NMEChar ch;
00730 NMEChar prev;
00732 } dict[] =
00733 {
00734 {'*', '\n'},
00735 {'#', '\n'},
00736 {';', '\n'},
00737 {':', '\n'},
00738 {'=', '\n'},
00739 {'-', '\n'},
00740 {'*', '*'},
00741 {'/', '/'},
00742 {'#', '#'},
00743 {'_', '_'},
00744 {'^', '^'},
00745 {',', ','},
00746 {'[', '['},
00747 {']', ']'},
00748 {'{', '{'},
00749 {'}', '}'},
00750 {'<', '<'},
00751 {'>', '>'},
00752 {'\\', '\\'},
00753 {'~', '\0'},
00754 {'|', '\0'},
00755 {0, 0}
00756 };
00757 (void)srcLen;
00758 (void)data;
00759
00760
00761 NMECurrentOutput(context, &output, &outputLength);
00762 prev = outputLength > 0 ? output[outputLength - 1] : '\n';
00763 for (i = outputLength - 1; i >= 0 && isBlank(output[i] == ' '); i--)
00764 ;
00765 if (i < 0 || isEol(output[i]))
00766 prev = '\n';
00767
00768
00769 for (i = 0; dict[i].ch; i++)
00770 if (src[*srcIx] == dict[i].ch && (!dict[i].prev || prev == dict[i].prev))
00771 {
00772 str[0] = '~';
00773 str[1] = dict[i].ch;
00774 if (!NMEAddString(str, 2, '\0', context))
00775 return kNMEErrNotEnoughMemory;
00776 (*srcIx)++;
00777 return kNMEErrOk;
00778 }
00779 if (!NMEAddString(&src[(*srcIx)++], 1, '\0', context))
00780 return kNMEErrNotEnoughMemory;
00781 return kNMEErrOk;
00782 }
00783
00784 NMEOutputFormat const NMEOutputFormatText =
00785 {
00786 " ",
00787 3,
00788 10,
00789 '%',
00790 "", "",
00791 4,
00792 "%%{4-l} %%%%{i>0}%{i}. %%", "\n\n",
00793 "", "\n\n",
00794 "\n",
00795 "", "\n",
00796 "", "\n",
00797 FALSE,
00798 "", "%%{l=1}\n%%",
00799 "%%{3*l-2} %%- ", "\n",
00800 "", "%%{l=1}\n%%",
00801 "%%{3*l-3} %%%{i}. ", "\n",
00802 "", "%%{l=1}\n%%",
00803 "%%{3*l-3} %%", "\n",
00804 NULL,
00805 "%%{3*l-1} %%", "\n",
00806 "", "%%{l=1}\n%%",
00807 "%%{3*l} %%", "\n",
00808 "", "\n",
00809 "", "\n",
00810 "", "\t",
00811 "", "\t",
00812 "%%{10}-%%\n\n",
00813 "", "",
00814 "", "",
00815 "", "",
00816 "", "",
00817 "", "",
00818 "", "",
00819 "", "", NULL, FALSE,
00820 "", "", NULL, FALSE, FALSE,
00821 NULL,
00822 NULL, NULL,
00823 NULL, NULL,
00824 NULL, NULL,
00825 70, NULL, NULL,
00826 NULL, NULL,
00827 NULL, NULL, NULL, NULL,
00828 NULL,
00829 NULL,
00830 NULL, NULL
00831 };
00832
00833 NMEOutputFormat const NMEOutputFormatTextCompact =
00834 {
00835 " ",
00836 3,
00837 10,
00838 '%',
00839 "", "",
00840 4,
00841 "%%{p>0}\n%%%%{4-l} %%%%{i>0}%{i}. %%", "\n",
00842 "", "\n",
00843 "\n",
00844 "", "",
00845 "", "\n",
00846 FALSE,
00847 "", "%%{l=1}%%",
00848 "%%{3*l-2} %%- ", "\n",
00849 "", "%%{l=1}%%",
00850 "%%{3*l-3} %%%{i}. ", "\n",
00851 "", "%%{l=1}%%",
00852 "%%{3*l-3} %%", "\n",
00853 NULL,
00854 "%%{3*l-1} %%", "\n",
00855 "", "%%{l=1}%%",
00856 "%%{3*l} %%", "\n",
00857 "", "",
00858 "", "\n",
00859 "", "\t",
00860 "", "\t",
00861 "%%{10}-%%\n",
00862 "", "",
00863 "", "",
00864 "", "",
00865 "", "",
00866 "", "",
00867 "", "",
00868 "", "", NULL, FALSE,
00869 "", "", NULL, FALSE, FALSE,
00870 NULL,
00871 NULL, NULL,
00872 NULL, NULL,
00873 NULL, NULL,
00874 70, NULL, NULL,
00875 NULL, NULL,
00876 NULL, NULL, NULL, NULL,
00877 NULL,
00878 NULL,
00879 NULL, NULL
00880 };
00881
00882 NMEOutputFormat const NMEOutputFormatDebug =
00883 {
00884 "[s]",
00885 3,
00886 10,
00887 '%',
00888 "<doc>\n", "</doc>\n",
00889 4,
00890 "<h l=\"%{l}\" i=\"%{i}\">", "</h>\n",
00891 "<p>", "</p>\n",
00892 "<br/>\n",
00893 "<pre>", "</pre>\n",
00894 "<preline>", "</preline>\n",
00895 FALSE,
00896 "%%{l-1} %%<ul l=\"%{l}\">\n", "%%{l-1} %%</ul l=\"%{l}\">\n",
00897 "%%{l} %%<uli l=\"%{l}\" i=\"%{i}\">", "</uli l=\"%{l}\" i=\"%{i}\">\n",
00898 "%%{l-1} %%<ol l=\"%{l}\">\n", "%%{l-1} %%</ol l=\"%{l}\">\n",
00899 "%%{l} %%<oli l=\"%{l}\" i=\"%{i}\">", "</oli l=\"%{l}\" i=\"%{i}\">\n",
00900 "%%{l-1} %%<dl l=\"%{l}\">\n", "%%{l-1} %%</dl l=\"%{l}\">\n",
00901 "%%{l} %%<dlt l=\"%{l}\" i=\"%{i}>", "%%{l} %%</dlt l=\"%{l}\" i=\"%{i}>\n",
00902 "<dlt/>",
00903 "%%{l} %%<dld l=\"%{l}\" i=\"%{i}>", "%%{l} %%</dld l=\"%{l}\" i=\"%{i}>\n",
00904 "%%{l-1} %%<indentsec l=\"%{l}\">\n", "%%{l-1} %%</indentsec l=\"%{l}\">\n",
00905 "%%{l-1} %%<indentpar l=\"%{l}\">", "%%{l-1} %%</indentpar l=\"%{l}\">\n",
00906 "<table>\n", "</table>\n",
00907 " <tr>\n", " </tr>\n",
00908 " <th>", "</th>\t",
00909 " <td>", "</td>\t",
00910 "<hr/>\n",
00911 "<b>", "</b>",
00912 "<i>", "</i>",
00913 "<u>", "</u>",
00914 "<sub>", "</sub>",
00915 "<super>", "</super>",
00916 "<code>", "</code>",
00917 "<a href=\"", "</a>", "\">", FALSE,
00918 "<img src=\"", "\" />", "\" alt=\"", FALSE, TRUE,
00919 NULL,
00920 NULL, NULL,
00921 NULL, NULL,
00922 NULL, NULL,
00923 70, NULL, NULL,
00924 NULL, NULL,
00925 NULL, NULL, NULL, NULL,
00926 NULL,
00927 NULL,
00928 NULL, NULL
00929 };
00930
00939 static NMEErr encodeURLFunNull(NMEConstText link, NMEInt linkLen,
00940 NMEContext *context, void *data)
00941 {
00942 return kNMEErrOk;
00943 }
00944
00955 static NMEErr encodeCharFunNull(NMEConstText src, NMEInt srcLen, NMEInt *srcIx,
00956 NMEContext *context,
00957 void *data)
00958 {
00959 (*srcIx)++;
00960 return kNMEErrOk;
00961 }
00962
00963 NMEOutputFormat const NMEOutputFormatNull =
00964 {
00965 "",
00966 0,
00967 10,
00968 '%',
00969 "", "",
00970 4,
00971 "", "",
00972 "", "",
00973 "",
00974 "", "",
00975 "", "",
00976 FALSE,
00977 "", "",
00978 "", "",
00979 "", "",
00980 "", "",
00981 "", "",
00982 "", "",
00983 NULL,
00984 "", "",
00985 "", "",
00986 "", "",
00987 "", "",
00988 "", "",
00989 "", "",
00990 "", "",
00991 "",
00992 "", "",
00993 "", "",
00994 "", "",
00995 "", "",
00996 "", "",
00997 "", "",
00998 "", "", NULL, FALSE,
00999 "", "", NULL, FALSE, FALSE,
01000 NULL,
01001 encodeURLFunNull, NULL,
01002 encodeCharFunNull, NULL,
01003 encodeCharFunNull, NULL,
01004 -1, NULL, NULL,
01005 NULL, NULL,
01006 NULL, NULL, NULL, NULL,
01007 NULL,
01008 NULL,
01009 NULL, NULL
01010 };
01011
01021 static NMEWordwrapPermission wordwrapCheckNMEFun(NMEConstText txt,
01022 NMEInt len, NMEInt i,
01023 NMEContext *context,
01024 void *data)
01025 {
01026 NMEConstText listNesting;
01027 NMEInt j;
01028 (void)data;
01029
01030
01031 listNesting = NMECurrentListNesting(context);
01032 for (j = 0; listNesting[j]; j++)
01033 if (listNesting[j] == '|')
01034 return kNMEWordwrapNo;
01035
01036
01037 return txt[i] == ' ' && i + 1 < len
01038 && txt[i + 1] != '*'
01039 && txt[i + 1] != '#'
01040 && txt[i + 1] != '|'
01041 && txt[i + 1] != '='
01042 ? kNMEWordwrapReplaceChar
01043 : kNMEWordwrapNo;
01044 }
01045
01046 NMEOutputFormat const NMEOutputFormatNME =
01047 {
01048 " ",
01049 0,
01050 10,
01051 '%',
01052 "", "",
01053 6,
01054 "%%{l}=%%", "%%{l}=%%\n",
01055 "", "\n\n",
01056 "\\\\",
01057 "{{{\n", "}}}\n\n",
01058 "", "\n",
01059 FALSE,
01060 "", "%%{l=1}\n%%",
01061 "%L ", "\n",
01062 "", "%%{l=1}\n%%",
01063 "%L ", "\n",
01064 "", "%%{l=1}\n%%",
01065 "%L ", "\n",
01066 NULL,
01067 "%L ", "\n",
01068 "", "%%{l=1}\n%%",
01069 "%%{l}:%% ", "\n",
01070 "", "\n",
01071 "", "\n",
01072 "|=", "",
01073 "|", "",
01074 "----\n\n",
01075 "**", "**",
01076 "//", "//",
01077 "__", "__",
01078 "^^", "^^",
01079 ",,", ",,",
01080 "##", "##",
01081 "[[", "]]", "|", FALSE,
01082 "{{", "}}", "|", FALSE, FALSE,
01083 NULL,
01084 NULL, NULL,
01085 encodeCharFunNME, NULL,
01086 NULL, NULL,
01087 70, wordwrapCheckNMEFun, NULL,
01088 NULL, NULL,
01089 NULL, NULL, NULL, NULL,
01090 NULL,
01091 NULL,
01092 NULL, NULL
01093 };
01094
01095 NMEOutputFormat const NMEOutputFormatHTML =
01096 {
01097 " ",
01098 2,
01099 0,
01100 '%',
01101 "<!-- Generated by Nyctergatis Markup Engine, "
01102 __DATE__ " " __TIME__ " -->\n"
01103 "<html>\n<body>\n", "</body>\n</html>\n",
01104 4,
01105 "<h%{l}"
01106 "%%{x} id=\"h%{o}\"%%"
01107 "%%{s>0} style=\"font-size:%{l=1?3*s:l=2?2*s:l=3?3*s/2|5*s/4}pt\"%%>"
01108 "%%{i>0}%{i}. %%",
01109 "</h%{l}>\n",
01110 "<p%%{s>0} style=\"font-size:%{s}pt\"%%>", "</p>\n",
01111 "<br />",
01112 "<pre%%{s>0} style=\"font-size:%{s}pt\"%%>\n", "</pre>\n",
01113 "", "\n",
01114 TRUE,
01115 "\n<ul>\n", "</ul>\n",
01116 "%%{2*l} %%<li%%{s>0} style=\"font-size:%{s}pt\"%%>", "</li>\n",
01117 "\n<ol>\n", "</ol>\n",
01118 "%%{2*l} %%<li%%{s>0} style=\"font-size:%{s}pt\"%%>", "</li>\n",
01119 "\n<dl>\n", "</dl>\n",
01120 "%%{2*l} %%<dt%%{s>0} style=\"font-size:%{s}pt\"%%>", "</dt>\n",
01121 NULL,
01122 "%%{2*l} %%<dd%%{s>0} style=\"font-size:%{s}pt\"%%>", "</dd>\n",
01123 "<div style=\"margin-left:2em%%{s>0}; font-size:%{s}pt%%\">\n",
01124 "</div>\n",
01125 "%%{2*l} %%<p%%{s>0} style=\"font-size:%{s}pt\"%%>", "</p>\n",
01126 "<table>\n", "</table>\n",
01127 "<tr>", "</tr>\n",
01128 "<th%%{s>0} style=\"font-size:%{s}pt\"%%>", "</th>\n",
01129 "<td%%{s>0} style=\"font-size:%{s}pt\"%%>", "</td>\n",
01130 "<hr />\n",
01131 #if defined(useHTMLEmphasisTags)
01132 "<strong>", "</strong>",
01133 "<em>", "</em>",
01134 #else
01135 "<b>", "</b>",
01136 "<i>", "</i>",
01137 #endif
01138 "<u>", "</u>",
01139 "<sup>", "</sup>",
01140 "<sub>", "</sub>",
01141 "<tt>", "</tt>",
01142 "<a href=\"", "</a>", "\">", FALSE,
01143 "<img src=\"", "\" />", "\" alt=\"", FALSE, TRUE,
01144 NULL,
01145 NULL, NULL,
01146 NMEEncodeCharFunDict, (void *)NMEXMLCharDict,
01147 NMEEncodeCharFunDict, (void *)NMEXMLCharDict,
01148 70, NULL, NULL,
01149 NULL, NULL,
01150 NULL, NULL, NULL, NULL,
01151 NULL,
01152 NULL,
01153 NULL, NULL
01154 };
01155
01169 static NMEErr encodeCharRTFFun(NMEConstText src, NMEInt srcLen, NMEInt *srcIx,
01170 NMEContext *context, void *data)
01171 {
01172 NMEInt ch, i;
01173 (void)data;
01174
01175 if ((src[*srcIx] & 0x80) == 0)
01176 {
01177 if (context->destLen + 1 >= context->bufSize)
01178 return kNMEErrNotEnoughMemory;
01179 if (src[*srcIx] == '\\' || src[*srcIx] == '{' || src[*srcIx] == '}')
01180 {
01181 context->dest[context->destLen++] = '\\';
01182 context->destLenUCS16++;
01183 }
01184 context->dest[context->destLen++] = src[(*srcIx)++];
01185 context->destLenUCS16++;
01186 return kNMEErrOk;
01187 }
01188 else if (*srcIx + 1 < srcLen && (src[*srcIx] & 0xe0) == 0xc0
01189 && (src[*srcIx + 1] & 0xc0) == 0x80)
01190 {
01191 ch = (((NMEInt)src[*srcIx] & 0x1f) << 6) | (src[*srcIx + 1] & 0x3f);
01192 *srcIx += 2;
01193 }
01194 else if (*srcIx + 2 < srcLen && (src[*srcIx] & 0xf0) == 0xe0
01195 && (src[*srcIx + 1] & 0xc0) == 0x80 && (src[*srcIx + 2] & 0xc0) == 0x80)
01196 {
01197 ch = ((NMEInt)src[*srcIx] << 12) | (((NMEInt)src[*srcIx + 1] & 0x3f) << 6)
01198 | (src[*srcIx + 2] & 0x3f);
01199 *srcIx += 3;
01200 }
01201 else
01202 {
01203 *srcIx += 1;
01204 return kNMEErrOk;
01205 }
01206
01207 if (context->destLen + 9 >= context->bufSize)
01208 return kNMEErrNotEnoughMemory;
01209
01210
01211 if (ch >= 32768)
01212 ch -= 65536;
01213
01214 context->dest[context->destLen++] = '\\';
01215 context->dest[context->destLen++] = 'u';
01216 if (ch < 0)
01217 {
01218 context->dest[context->destLen++] = '-';
01219 context->destLenUCS16++;
01220 ch = -ch;
01221 }
01222 for (i = 1; i < ch; i *= 10)
01223 ;
01224 for (i /= 10; i > 0; i /= 10)
01225 {
01226 context->dest[context->destLen++] = '0' + (ch / i) % 10;
01227 context->destLenUCS16++;
01228 }
01229 context->dest[context->destLen++] = '?';
01230 context->destLenUCS16 += 3;
01231
01232 return kNMEErrOk;
01233 }
01234
01242 static NMEErr encodeURLFunRTF(NMEConstText link, NMEInt linkLen,
01243 NMEContext *context, void *data)
01244 {
01245 NMEInt i;
01246 NMEErr err;
01247 (void)data;
01248
01249
01250 for (i = 0; i < linkLen; )
01251 CheckError(encodeCharRTFFun(link, linkLen, &i, context, NULL));
01252 return kNMEErrOk;
01253 }
01254
01264 static NMEWordwrapPermission wordwrapCheckRTFFun(NMEConstText txt,
01265 NMEInt len, NMEInt i,
01266 NMEContext *context,
01267 void *data)
01268 {
01269 (void)data;
01270
01271 return txt[i] == ' ' ? kNMEWordwrapInsert : kNMEWordwrapNo;
01272 }
01273
01274 NMEOutputFormat const NMEOutputFormatRTF =
01275 {
01276 #define SIZE "%{2*s}" ///< size of text
01277 #define SIZEH "%{l=1?3*s:l=2?5*s/2:l=3?2*s:3*s/2}" ///< size of heading
01278 " ",
01279 0,
01280 10,
01281 '%',
01282 "{\\rtf1\\ansi\\deff0"
01283 "{\\fonttbl"
01284 "{\\f0\\froman Times;}"
01285 "{\\f1\\fswiss Helvetica;}"
01286 "{\\f2\\fmodern Courier;}"
01287 "}\n",
01288 "\n}\n",
01289 4,
01290 "{\\pard\\sb%{500-100*l}\\li60\\sa40%%{l=1}\\qc%%\\f1"
01291 "\\fs" SIZEH "%%{l!2}\\b%% %%{i>0}%{i}. %%",
01292 "\\par}\n",
01293 "{\\pard\\sb80\\li60\\qj\\fi160\\f0\\fs" SIZE " ",
01294 "\\par}\n",
01295 "\\line ",
01296 "{\\pard\\sb80\\li160\\f2\\fs" SIZE " ",
01297 "}\n",
01298 "",
01299 "\\par\n",
01300 FALSE,
01301 "",
01302 "",
01303 "{\\pard\\sb80\\li%{60+100*l}\\qj\\fi160\\f0\\fs" SIZE " * ",
01304 "\\par}\n",
01305 "",
01306 "",
01307 "{\\pard\\sb80\\li%{60+100*l}\\qj\\fi160\\f0\\fs" SIZE " %{i}",
01308 "\\par}\n",
01309 "", "",
01310 "{\\pard\\sb80\\li%{60+100*l}\\qj\\f0\\fs" SIZE "\\i ",
01311 "\\par}\n",
01312 NULL,
01313 "{\\pard\\sb80\\qj\\fi160\\f0\\fs" SIZE "\\li320 ",
01314 "\\par}\n",
01315 "", "",
01316 "{\\pard\\sb80\\li%{60+100*l}\\qj\\fi160\\f0\\fs" SIZE " ",
01317 "\\par}\n",
01318 "{\\par\\li60 ", "\\pard}\n",
01319 "\\trowd\\trautofit1 ", "\\row\n",
01320 "\\pard\\intbl\\sb80\\qc\\fi160\\f0\\fs" SIZE " {\\b ",
01321 "}\\cell\n",
01322 "\\pard\\intbl\\sb80\\qj\\fi160\\f0\\fs" SIZE " ",
01323 "\\cell\n",
01324 "\\hrule\n",
01325 "{\\b ",
01326 "}",
01327 "{\\i ",
01328 "}",
01329 "{\\ul ",
01330 "}",
01331 "{\\super ",
01332 "}",
01333 "{\\sub ",
01334 "}",
01335 "{\\f2 ",
01336 "}",
01337 "{\\field{\\*\\fldinst{HYPERLINK \"", "}}", "\"}}{\\fldrslt ", FALSE,
01338 "", "", NULL, FALSE, FALSE,
01339 NULL,
01340 encodeURLFunRTF, NULL,
01341 encodeCharRTFFun, NULL,
01342 encodeCharRTFFun, NULL,
01343 70, wordwrapCheckRTFFun, NULL,
01344 NULL, NULL,
01345 NULL, NULL, NULL, NULL,
01346 NULL,
01347 NULL,
01348 NULL, NULL
01349 #undef SIZE
01350 #undef SIZEH
01351 };
01352
01353 NMEOutputFormat const NMEOutputFormatLaTeX =
01354 {
01355 " ",
01356 2,
01357 10,
01358 '%',
01359 "\\documentclass[%{s}pt]{article}\n"
01360 "\\usepackage{hyperref}\n"
01361 "\\begin{document}\n",
01362 "\n\\end{document}\n",
01363 4,
01364 "\n\\%%{l>3?2:l-1}sub%%section%%{l>3|i<1}*%%{",
01365 "}\n",
01366 "\n",
01367 "\n",
01368 "\\\\",
01369 "\n\\begin{verbatim}\n",
01370 "\\end{verbatim}\n",
01371 "",
01372 "\n",
01373 FALSE,
01374 "\\begin{itemize}\n",
01375 "\\end{itemize}\n",
01376 "%%{2*l} %%\\item ",
01377 "\n",
01378 "\\begin{enumerate}\n",
01379 "\\end{enumerate}\n",
01380 "%%{2*l} %%\\item ",
01381 "\n",
01382 "\\begin{description}\n",
01383 "\\end{description}\n",
01384 "%%{2*l} %%\\item[", "] ",
01385 NULL,
01386 "\n", "\n",
01387 "\\begin{itemize}\n", "\\end{itemize}\n",
01388 "\\item[] ", "\n",
01389 "\\begin{tabular}{llllllllllllllll}\n", "\\end{tabular}\n",
01390 "", "\\\\\n",
01391 "{\\bf ", "} & ",
01392 "", " & ",
01393 "",
01394 "{\\bfseries ",
01395 "}",
01396 "{\\itshape ",
01397 "}",
01398 "\\underline{",
01399 "}",
01400 "\\textsuperscript{",
01401 "}",
01402 "\\ensuremath{_{\\mbox{",
01403 "}}}",
01404 "{\\ttfamily ",
01405 "}",
01406 "\\href{", "}", "}{", FALSE,
01407 "", "", NULL, FALSE, FALSE,
01408 NULL,
01409 NULL, NULL,
01410 NMEEncodeCharFunDict, (void *)latexCharDict,
01411 NULL, NULL,
01412 70, NULL, NULL,
01413 NULL, NULL,
01414 NULL, NULL, NULL, NULL,
01415 NULL,
01416 NULL,
01417 NULL, NULL
01418 };
01419
01420 NMEOutputFormat const NMEOutputFormatMan =
01421 {
01422 " ",
01423 0,
01424 10,
01425 '%',
01426 ".TH title 1\n", "",
01427 2,
01428 "%%{l=1}.SH%%%%{l>1}.SS%% ", "\n",
01429 ".P\n", "\n",
01430 "",
01431 "", "",
01432 " ", "\n",
01433 FALSE,
01434 "", "",
01435 ".IP *\n", "\n",
01436 "", "",
01437 ".IP %{i}\n", "\n",
01438 "", "",
01439 ".IP ", "\n",
01440 NULL,
01441 "", "\n",
01442 "", "",
01443 "\n.P\n", "\n",
01444 "", "",
01445 "", "\n",
01446 "", " ",
01447 "", " ",
01448 "\n",
01449 "\n.B ", "\n",
01450 "\n.I ", "\n",
01451 "", "",
01452 "", "",
01453 "", "",
01454 "", "",
01455 "", "", NULL, FALSE,
01456 "", "", NULL, FALSE, FALSE,
01457 NULL,
01458 NULL, NULL,
01459 NULL, NULL,
01460 NULL, NULL,
01461 70, NULL, NULL,
01462 NULL, NULL,
01463 NULL, NULL, NULL, NULL,
01464 NULL,
01465 NULL,
01466 NULL, NULL
01467 };
01468
01474 static NMEErr addLink(NMEContext *context,
01475 NMEOutputFormat const *outputFormat)
01476 {
01477 NMEInt i;
01478 NMEConstText link = context->src + context->linkOffset;
01479 NMEInt linkLen = context->linkLength;
01480 NMEErr err;
01481
01482 if (outputFormat->interwikis)
01483 {
01484 NMEInt iw;
01485
01486
01487 for (iw = 0; outputFormat->interwikis[iw].alias; iw++)
01488 {
01489 for (i = 0;
01490 i < linkLen
01491 && outputFormat->interwikis[iw].alias[i] != '\0'
01492 && link[i] == outputFormat->interwikis[iw].alias[i];
01493 i++)
01494 ;
01495 if (outputFormat->interwikis[iw].alias[i] == '\0')
01496 {
01497
01498 if (!NMEAddString(outputFormat->interwikis[iw].urlPrefix, -1,
01499 context->ctrlChar, context))
01500 return kNMEErrNotEnoughMemory;
01501 CheckError(checkWordwrap(context, outputFormat));
01502 link += i;
01503 linkLen -= i;
01504 break;
01505 }
01506 }
01507 }
01508
01509
01510 if (outputFormat->encodeURLFun)
01511 CheckError(outputFormat->encodeURLFun(link, linkLen, context,
01512 outputFormat->encodeURLData));
01513 else
01514 {
01515
01516 if (context->destLen + linkLen > context->bufSize)
01517 return kNMEErrNotEnoughMemory;
01518 for (i = 0; i < linkLen; i++)
01519 {
01520 context->dest[context->destLen++] = link[i];
01521 context->destLenUCS16++;
01522 }
01523 }
01524
01525 return kNMEErrOk;
01526 }
01527
01535 static NMEBoolean findStyleInStyleStack(
01536 NMEStyle const styleStack[],
01537 NMEInt styleNesting,
01538 NMEStyle style,
01539 NMEInt *i)
01540 {
01541 NMEInt j;
01542
01543 for (j = 0; j < styleNesting; j++)
01544 if (styleStack[j] == style)
01545 {
01546 if (i)
01547 *i = j;
01548 return TRUE;
01549 }
01550 return FALSE;
01551 }
01552
01557 static NMEConstText styleMarkerFromStyleID(NMEStyle style)
01558 {
01559 switch (style)
01560 {
01561 case kNMEStyleBold:
01562 return "**";
01563 case kNMEStyleItalic:
01564 return "//";
01565 case kNMEStyleUnderline:
01566 return "__";
01567 case kNMEStyleSuperscript:
01568 return "^^";
01569 case kNMEStyleSubscript:
01570 return ",,";
01571 case kNMEStyleMonospace:
01572 return "##";
01573 case kNMEStyleLink:
01574 return "[[";
01575 case kNMEStyleImage:
01576 return "{{";
01577 default:
01578 return NULL;
01579 }
01580 }
01581
01591 static NMEErr processStyleTag(
01592 NMEStyle styleStack[],
01593 NMEInt *styleNesting,
01594 NMEStyle style,
01595 NMEInt i0,
01596 NMEOutputFormat const *outputFormat,
01597 NMEContext *context)
01598 {
01599 NMEInt i, j;
01600 NMEErr err;
01601
01602 #define HOOK(e, st) \
01603 do { \
01604 if (outputFormat->spanHookFun) \
01605 { \
01606 NMEConstText styleStr = styleMarkerFromStyleID(st); \
01607 if (styleStr) \
01608 { \
01609 updateLineNum(context); \
01610 CheckError(outputFormat->spanHookFun(kNMEHookLevelSpan, 0, e, styleStr, \
01611 i0 + context->srcIndexOffset, \
01612 context->srcLineNum, \
01613 context, \
01614 outputFormat->hookData)); \
01615 } \
01616 } \
01617 } while (0)
01618
01619
01620 if (findStyleInStyleStack(styleStack, *styleNesting, style, &i))
01621 {
01622
01623 for (j = *styleNesting - 1; j >= i; j--)
01624 if (styleStack[j] != kNMEStyleVerbatim
01625 || (context->options & kNMEProcessOptVerbatimMono
01626 && !findStyleInStyleStack(styleStack, *styleNesting,
01627 kNMEStyleMonospace, NULL)))
01628 {
01629
01630 if (styleStack[j] == kNMEStyleLink
01631 && outputFormat->sepLink && outputFormat->linkAfterSep)
01632 {
01633 if (!NMEAddString(outputFormat->sepLink, -1,
01634 context->ctrlChar, context))
01635 return kNMEErrNotEnoughMemory;
01636 CheckError(addLink(context, outputFormat));
01637 CheckError(checkWordwrap(context, outputFormat));
01638 }
01639 else if (styleStack[j] == kNMEStyleImage
01640 && outputFormat->sepImage && outputFormat->imageAfterSep)
01641 {
01642 if (!NMEAddString(outputFormat->sepImage, -1,
01643 context->ctrlChar, context))
01644 return kNMEErrNotEnoughMemory;
01645 CheckError(addLink(context, outputFormat));
01646 CheckError(checkWordwrap(context, outputFormat));
01647 }
01648
01649
01650 if (!NMEAddString(styleStack[j] == kNMEStyleBold
01651 ? outputFormat->endBold
01652 : styleStack[j] == kNMEStyleItalic
01653 ? outputFormat->endItalic
01654 : styleStack[j] == kNMEStyleUnderline
01655 ? outputFormat->endUnderline
01656 : styleStack[j] == kNMEStyleSuperscript
01657 ? outputFormat->endSuperscript
01658 : styleStack[j] == kNMEStyleSubscript
01659 ? outputFormat->endSubscript
01660 : styleStack[j] == kNMEStyleLink
01661 ? outputFormat->endLink
01662 : styleStack[j] == kNMEStyleImage
01663 ? outputFormat->endImage
01664 : outputFormat->endCode,
01665 -1,
01666 context->ctrlChar, context))
01667 return kNMEErrNotEnoughMemory;
01668 CheckError(checkWordwrap(context, outputFormat));
01669
01670
01671 HOOK(FALSE, styleStack[j]);
01672 }
01673
01674 for (j = i + 1; j < *styleNesting; j++)
01675 if (styleStack[j] != kNMEStyleLink && styleStack[j] != kNMEStyleImage)
01676 {
01677 HOOK(TRUE, styleStack[j]);
01678
01679 styleStack[i] = styleStack[j];
01680 if (styleStack[i] != kNMEStyleVerbatim)
01681 {
01682 if (!NMEAddString(styleStack[i] == kNMEStyleBold
01683 ? outputFormat->beginBold
01684 : styleStack[i] == kNMEStyleItalic
01685 ? outputFormat->beginItalic
01686 : styleStack[i] == kNMEStyleUnderline
01687 ? outputFormat->beginUnderline
01688 : styleStack[i] == kNMEStyleSuperscript
01689 ? outputFormat->beginSuperscript
01690 : styleStack[i] == kNMEStyleSubscript
01691 ? outputFormat->beginSubscript
01692 : outputFormat->beginCode,
01693 -1,
01694 context->ctrlChar, context))
01695 return kNMEErrNotEnoughMemory;
01696 CheckError(checkWordwrap(context, outputFormat));
01697 }
01698 i++;
01699 }
01700 *styleNesting -= j - i;
01701 return kNMEErrOk;
01702 }
01703
01704
01705
01706 if (style == kNMEStyleLink || style == kNMEStyleImage
01707 || (outputFormat->noStyleInAlt
01708 && findStyleInStyleStack(styleStack, *styleNesting,
01709 kNMEStyleImage, NULL)))
01710 return kNMEErrOk;
01711 styleStack[(*styleNesting)++] = style;
01712
01713
01714 if (style == kNMEStyleVerbatim
01715 && (!(context->options & kNMEProcessOptVerbatimMono)
01716 || findStyleInStyleStack(styleStack, *styleNesting,
01717 kNMEStyleMonospace, NULL)))
01718 return kNMEErrOk;
01719 HOOK(TRUE, style);
01720 if (!NMEAddString(style == kNMEStyleBold ? outputFormat->beginBold
01721 : style == kNMEStyleItalic ? outputFormat->beginItalic
01722 : style == kNMEStyleUnderline ? outputFormat->beginUnderline
01723 : style == kNMEStyleSuperscript ? outputFormat->beginSuperscript
01724 : style == kNMEStyleSubscript ? outputFormat->beginSubscript
01725 : outputFormat->beginCode,
01726 -1,
01727 context->ctrlChar, context))
01728 return kNMEErrNotEnoughMemory;
01729 CheckError(checkWordwrap(context, outputFormat));
01730 return kNMEErrOk;
01731
01732 #undef HOOK
01733 }
01734
01743 static NMEErr flushStyleTags(
01744 NMEStyle styleStack[kNMEStylesCount],
01745 NMEInt *styleNesting,
01746 NMEInt i0,
01747 NMEOutputFormat const *outputFormat,
01748 NMEContext *context)
01749 {
01750 NMEInt i;
01751 NMEErr err;
01752
01753 for (i = *styleNesting - 1; i >= 0; i--)
01754 if (styleStack[i] != kNMEStyleVerbatim
01755 || (context->options & kNMEProcessOptVerbatimMono
01756 && !findStyleInStyleStack(styleStack, *styleNesting,
01757 kNMEStyleMonospace, NULL)))
01758 {
01759 if (styleStack[i] == kNMEStyleLink
01760 && outputFormat->sepLink && outputFormat->linkAfterSep)
01761 {
01762 if (!NMEAddString(outputFormat->sepLink, -1,
01763 context->ctrlChar, context))
01764 return kNMEErrNotEnoughMemory;
01765 CheckError(addLink(context, outputFormat));
01766 CheckError(checkWordwrap(context, outputFormat));
01767 }
01768 else if (styleStack[i] == kNMEStyleImage
01769 && outputFormat->sepImage && outputFormat->imageAfterSep)
01770 {
01771 if (!NMEAddString(outputFormat->sepImage, -1,
01772 context->ctrlChar, context))
01773 return kNMEErrNotEnoughMemory;
01774 CheckError(addLink(context, outputFormat));
01775 CheckError(checkWordwrap(context, outputFormat));
01776 }
01777
01778 if (!NMEAddString(styleStack[i] == kNMEStyleBold
01779 ? outputFormat->endBold
01780 : styleStack[i] == kNMEStyleItalic
01781 ? outputFormat->endItalic
01782 : styleStack[i] == kNMEStyleUnderline
01783 ? outputFormat->endUnderline
01784 : styleStack[i] == kNMEStyleSuperscript
01785 ? outputFormat->endSuperscript
01786 : styleStack[i] == kNMEStyleSubscript
01787 ? outputFormat->endSubscript
01788 : styleStack[i] == kNMEStyleLink
01789 ? outputFormat->endLink
01790 : styleStack[i] == kNMEStyleImage
01791 ? outputFormat->endImage
01792 : outputFormat->endCode,
01793 -1,
01794 context->ctrlChar, context))
01795 return kNMEErrNotEnoughMemory;
01796 CheckError(checkWordwrap(context, outputFormat));
01797
01798
01799 if (outputFormat->spanHookFun)
01800 {
01801 NMEConstText styleStr = styleMarkerFromStyleID(styleStack[i]);
01802 if (styleStr)
01803 {
01804 updateLineNum(context);
01805 CheckError(outputFormat->spanHookFun(kNMEHookLevelSpan, 0,
01806 FALSE, styleStr,
01807 i0 + context->srcIndexOffset,
01808 context->srcLineNum,
01809 context,
01810 outputFormat->hookData));
01811 }
01812 }
01813 }
01814 *styleNesting = 0;
01815 return kNMEErrOk;
01816 }
01817
01825 static NMEErr addEndPar(NMEBoolean forceEndOfList,
01826 NMEOutputFormat const *outputFormat,
01827 NMEContext *context,
01828 NMEInt srcIndexEndPar)
01829 {
01830 NMEErr err;
01831
01832 #define HOOK(cb, l, it, e, m) \
01833 do { \
01834 if (outputFormat->cb) \
01835 { \
01836 updateLineNum(context); \
01837 CheckError(outputFormat->cb(l, it, e, m, \
01838 context->srcIndexOffset + srcIndexEndPar, \
01839 context->srcLineNum, \
01840 context, \
01841 outputFormat->hookData)); \
01842 } \
01843 } while (0)
01844
01845 if (context->nesting > 0)
01846 {
01847 NMEInt level0, item0;
01848
01849 level0 = context->level;
01850 item0 = context->item;
01851 setContext(*context, context->nesting, context->listNum[context->nesting - 1]);
01852
01853
01854 if (context->listNum[context->nesting - 1] >= 0)
01855 {
01856 context->listNum[context->nesting - 1]++;
01857 if (!NMEAddString(outputFormat->endOLItem, -1,
01858 context->ctrlChar, context))
01859 return kNMEErrNotEnoughMemory;
01860 CheckError(checkWordwrap(context, outputFormat));
01861 HOOK(parHookFun, context->level, context->item, FALSE, "#");
01862 }
01863 else if (context->listNum[context->nesting - 1] == kNMEListNumTableCell
01864 || context->listNum[context->nesting - 1] == kNMEListNumTableHCell)
01865 {
01866 if (!NMEAddString(context->listNum[context->nesting - 1] == kNMEListNumTableCell
01867 ? outputFormat->endTableCell
01868 : outputFormat->endTableHCell,
01869 -1,
01870 context->ctrlChar, context))
01871 return kNMEErrNotEnoughMemory;
01872 CheckError(checkWordwrap(context, outputFormat));
01873 HOOK(parHookFun, kNMEHookLevelPar, 0, FALSE,
01874 context->listNum[context->nesting - 1] == kNMEListNumTableCell ? "|" : "|=");
01875 if (!NMEAddString(outputFormat->endTableRow, -1,
01876 context->ctrlChar, context))
01877 return kNMEErrNotEnoughMemory;
01878 CheckError(checkWordwrap(context, outputFormat));
01879 }
01880 else
01881 switch (context->listNum[context->nesting - 1])
01882 {
01883 case kNMEListNumUL:
01884 if (!NMEAddString(outputFormat->endULItem, -1, context->ctrlChar, context))
01885 return kNMEErrNotEnoughMemory;
01886 CheckError(checkWordwrap(context, outputFormat));
01887 HOOK(parHookFun, context->level, context->item, FALSE, "*");
01888 break;
01889 case kNMEListNumDT:
01890 if (!NMEAddString(outputFormat->endDT, -1, context->ctrlChar, context))
01891 return kNMEErrNotEnoughMemory;
01892 CheckError(checkWordwrap(context, outputFormat));
01893 HOOK(parHookFun, context->level, context->item, FALSE, ";");
01894 break;
01895 case kNMEListNumDD:
01896 if (!NMEAddString(outputFormat->endDD, -1, context->ctrlChar, context))
01897 return kNMEErrNotEnoughMemory;
01898 CheckError(checkWordwrap(context, outputFormat));
01899 HOOK(parHookFun, context->level, context->item, FALSE, ";:");
01900 break;
01901 case kNMEListIndented:
01902 if (!NMEAddString(outputFormat->endIndentedPar, -1, context->ctrlChar, context))
01903 return kNMEErrNotEnoughMemory;
01904 CheckError(checkWordwrap(context, outputFormat));
01905 HOOK(parHookFun, context->level, context->item, FALSE, ":");
01906 break;
01907
01908 }
01909
01910 if (forceEndOfList)
01911 while (context->nesting > 0)
01912 {
01913 setContext(*context, context->nesting, context->listNum[context->nesting - 1]);
01914 switch (context->listNum[context->nesting - 1])
01915 {
01916 case kNMEListNumUL:
01917 if (!NMEAddString(outputFormat->endUL, -1, context->ctrlChar, context))
01918 return kNMEErrNotEnoughMemory;
01919 CheckError(checkWordwrap(context, outputFormat));
01920 HOOK(divHookFun, context->level, 0, FALSE, "*");
01921 break;
01922 case kNMEListNumDT:
01923 case kNMEListNumDD:
01924 if (!NMEAddString(outputFormat->endDL, -1, context->ctrlChar, context))
01925 return kNMEErrNotEnoughMemory;
01926 CheckError(checkWordwrap(context, outputFormat));
01927 HOOK(divHookFun, context->level, 0, FALSE, ";");
01928 break;
01929 case kNMEListIndented:
01930 if (!NMEAddString(outputFormat->endIndented, -1, context->ctrlChar, context))
01931 return kNMEErrNotEnoughMemory;
01932 CheckError(checkWordwrap(context, outputFormat));
01933 HOOK(divHookFun, context->level, 0, FALSE, ":");
01934 break;
01935 case kNMEListNumTableCell:
01936 case kNMEListNumTableHCell:
01937 if (!NMEAddString(outputFormat->endTable, -1, context->ctrlChar, context))
01938 return kNMEErrNotEnoughMemory;
01939 CheckError(checkWordwrap(context, outputFormat));
01940 HOOK(divHookFun, kNMEHookLevelPar, 0, FALSE, "|");
01941 break;
01942 default:
01943 if (!NMEAddString(outputFormat->endOL, -1, context->ctrlChar, context))
01944 return kNMEErrNotEnoughMemory;
01945 CheckError(checkWordwrap(context, outputFormat));
01946 HOOK(divHookFun, context->level, 0, FALSE, "#");
01947 break;
01948 }
01949 context->nesting--;
01950 setContext(*context, context->nesting, context->listNum[context->nesting - 1]);
01951 if (outputFormat->sublistInListItem && context->nesting > 0)
01952 switch (context->listNum[context->nesting - 1])
01953 {
01954 case kNMEListNumUL:
01955 if (!NMEAddString(outputFormat->endULItem, -1, context->ctrlChar, context))
01956 return kNMEErrNotEnoughMemory;
01957 break;
01958 case kNMEListNumDT:
01959 case kNMEListNumDD:
01960 if (!NMEAddString(outputFormat->endDD, -1, context->ctrlChar, context))
01961 return kNMEErrNotEnoughMemory;
01962 break;
01963 case kNMEListIndented:
01964
01965 break;
01966 default:
01967 if (!NMEAddString(outputFormat->endOLItem, -1, context->ctrlChar, context))
01968 return kNMEErrNotEnoughMemory;
01969 break;
01970 }
01971 }
01972
01973 setContext(*context, level0, item0);
01974 return kNMEErrOk;
01975 }
01976 else
01977 {
01978 if (!NMEAddString(outputFormat->endPar, -1, context->ctrlChar, context))
01979 return kNMEErrNotEnoughMemory;
01980 CheckError(checkWordwrap(context, outputFormat));
01981 HOOK(parHookFun, kNMEHookLevelPar, 0, FALSE, "p");
01982 return kNMEErrOk;
01983 }
01984 #undef HOOK
01985 }
01986
01997 static NMEErr addLinkBegin(NMEBoolean isImage,
01998 NMEStyle styleStack[kNMEStylesCount],
01999 NMEInt *styleNesting,
02000 NMEInt i0,
02001 NMEOutputFormat const *outputFormat,
02002 NMEContext *context)
02003 {
02004 NMEInt j, k;
02005 NMEErr err;
02006
02007
02008 for (j = 0; j < *styleNesting; j++)
02009 if ((styleStack[j] == kNMEStyleLink && !isImage)
02010 || styleStack[j] == kNMEStyleImage)
02011 return kNMEErrOk;
02012
02013
02014 skipBlanks(context->src, context->srcLen, &context->srcIndex);
02015
02016
02017 for (j = context->srcIndex; j < context->srcLen
02018 && (!isEol(context->src[j])
02019 || (j + 1 < context->srcLen
02020 && (!isEol(context->src[j + 1])
02021 || (context->src[j] == '\r' && context->src[j + 1] =='\n'))))
02022 && (j + 1 >= context->srcLen
02023 || context->src[j] != (isImage ? '}' : ']')
02024 || context->src[j + 1] != context->src[j])
02025 && context->src[j] != '|';
02026 j++)
02027 ;
02028
02029
02030 for (k = j;
02031 k > context->srcIndex
02032 && (isBlank(context->src[k - 1]) || isEol(context->src[k - 1]));
02033 k--)
02034 ;
02035
02036
02037 if (k <= context->srcIndex)
02038 {
02039 context->srcIndex = j;
02040 return kNMEErrOk;
02041 }
02042
02043
02044 context->linkOffset = context->srcIndex;
02045 context->linkLength = k - context->srcIndex;
02046
02047
02048 if (outputFormat->spanHookFun)
02049 {
02050 updateLineNum(context);
02051 CheckError(outputFormat->spanHookFun(kNMEHookLevelSpan, 0, TRUE,
02052 isImage ? "{{" : "[[",
02053 i0 + context->srcIndexOffset,
02054 context->srcLineNum,
02055 context,
02056 outputFormat->hookData));
02057 }
02058
02059 if (isImage ? outputFormat->sepImage : outputFormat->sepLink)
02060 {
02061
02062 if (!NMEAddString(isImage ? outputFormat->beginImage : outputFormat->beginLink, -1,
02063 context->ctrlChar, context))
02064 return kNMEErrNotEnoughMemory;
02065 CheckError(checkWordwrap(context, outputFormat));
02066
02067 if (!(isImage ? outputFormat->imageAfterSep : outputFormat->linkAfterSep))
02068 {
02069 CheckError(addLink(context, outputFormat));
02070 if (!NMEAddString(isImage ? outputFormat->sepImage : outputFormat->sepLink, -1,
02071 context->ctrlChar, context))
02072 return kNMEErrNotEnoughMemory;
02073 CheckError(checkWordwrap(context, outputFormat));
02074 }
02075 }
02076
02077
02078 if (j < context->srcLen && context->src[j] == '|')
02079 {
02080 context->srcIndex = j + 1;
02081 skipBlanks(context->src, context->srcLen, &context->srcIndex);
02082 }
02083 else
02084 {
02085
02086 for (k = 0; k < context->linkLength; )
02087 {
02088 if (outputFormat->charHookFun)
02089 CheckError(outputFormat->charHookFun(context->linkOffset + k,
02090 context,
02091 outputFormat->charHookData));
02092 if (outputFormat->encodeCharFun)
02093 CheckError(outputFormat->encodeCharFun(context->src + context->linkOffset,
02094 context->linkLength, &k,
02095 context,
02096 outputFormat->encodeCharData));
02097 else
02098 {
02099 if (context->destLen + 1 > context->bufSize)
02100 return kNMEErrNotEnoughMemory;
02101 context->dest[context->destLen++] = context->src[context->linkOffset + k];
02102 if (isFirstUTF8Byte(context->src[context->linkOffset + k]))
02103 context->destLenUCS16++;
02104 k++;
02105 context->col++;
02106 }
02107 CheckError(checkWordwrap(context, outputFormat));
02108 }
02109
02110 context->srcIndex = j;
02111 }
02112
02113
02114
02115 styleStack[(*styleNesting)++] = isImage ? kNMEStyleImage : kNMEStyleLink;
02116
02117 return kNMEErrOk;
02118 }
02119
02128 static NMEInt findPlugin(NMEConstText src, NMEInt srcLen, NMEInt i,
02129 NMEBoolean isPlaceholder,
02130 NMEOutputFormat const *outputFormat)
02131 {
02132 NMEConstText name;
02133 NMEInt nameLen, j, k;
02134
02135
02136 skipBlanks(src, srcLen, &i);
02137 name = src + i;
02138 for (nameLen = 0;
02139 i + nameLen < srcLen
02140 && !isBlank(src[i + nameLen])
02141 && !isEol(src[i + nameLen])
02142 && src[i + nameLen] != '>';
02143 nameLen++)
02144 ;
02145
02146
02147 if (outputFormat->plugins && nameLen > 0)
02148 for (j = 0; outputFormat->plugins[j].name; j++)
02149 if (isPlaceholder
02150 ^ ((outputFormat->plugins[j].options & kNMEPluginOptTripleAngleBrackets) == 0))
02151 {
02152
02153 for (k = 0; k < nameLen && outputFormat->plugins[j].name[k]; k++)
02154 if (name[k] != outputFormat->plugins[j].name[k])
02155 goto continueMainLoop;
02156 if (outputFormat->plugins[j].name[k] != '\0'
02157 || (k < nameLen
02158 && !(outputFormat->plugins[j].options & kNMEPluginOptPartialName)))
02159 goto continueMainLoop;
02160
02161 return j;
02162 continueMainLoop:
02163 ;
02164 }
02165
02166
02167 return -1;
02168 }
02169
02179 static NMEErr addPlugin(NMEBoolean isBlock,
02180 NMEBoolean isPlaceholder,
02181 NMEInt options,
02182 NMEOutputFormat const *outputFormat,
02183 NMEContext *context,
02184 NMEBoolean *reparseOutput)
02185 {
02186 NMEConstText name, data;
02187 NMEInt nameLen, dataLen;
02188 NMEInt j, k;
02189 NMEErr err;
02190
02191
02192 skipBlanks(context->src, context->srcLen, &context->srcIndex);
02193 name = context->src + context->srcIndex;
02194 for (nameLen = 0;
02195 context->srcIndex + nameLen < context->srcLen
02196 && !isBlank(context->src[context->srcIndex + nameLen])
02197 && !isEol(context->src[context->srcIndex + nameLen])
02198 && context->src[context->srcIndex + nameLen] != '>';
02199 nameLen++)
02200 ;
02201 context->srcIndex += nameLen;
02202 skipBlanks(context->src, context->srcLen, &context->srcIndex);
02203 if (context->srcIndex < context->srcLen && context->src[context->srcIndex] == '\r')
02204 context->srcIndex++;
02205 if (context->srcIndex < context->srcLen && context->src[context->srcIndex] == '\n')
02206 context->srcIndex++;
02207
02208
02209 data = context->src + context->srcIndex;
02210 if (isBlock)
02211 for (dataLen = 0;
02212 context->srcIndex + dataLen + (isPlaceholder ? 2 : 1) < context->srcLen;
02213 dataLen++)
02214 {
02215 if (isEol(context->src[context->srcIndex + dataLen - 1])
02216 && context->src[context->srcIndex + dataLen] == '>'
02217 && context->src[context->srcIndex + dataLen + 1] == '>'
02218 && (!isPlaceholder
02219 || context->src[context->srcIndex + dataLen + 2] == '>'))
02220 {
02221
02222 j = context->srcIndex + dataLen + (isPlaceholder ? 3 : 2);
02223 skipBlanks(context->src, context->srcLen, &j);
02224 if (j >= context->srcLen || isEol(context->src[j]))
02225 break;
02226 }
02227 }
02228 else
02229 for (dataLen = 0;
02230 context->srcIndex + dataLen + (isPlaceholder ? 2 : 1) < context->srcLen
02231 && (context->src[context->srcIndex + dataLen] != '>'
02232 || context->src[context->srcIndex + dataLen + 1] != '>'
02233 || (isPlaceholder
02234 && context->src[context->srcIndex + dataLen + 2] != '>'));
02235 dataLen++)
02236 ;
02237 context->srcIndex += dataLen;
02238 if (context->srcIndex + (isPlaceholder ? 3 : 2) <= context->srcLen)
02239 context->srcIndex += isPlaceholder ? 3 : 2;
02240
02241
02242 if (dataLen > 0 && data[dataLen - 1] == '\n')
02243 dataLen--;
02244 if (dataLen > 0 && data[dataLen - 1] == '\r')
02245 dataLen--;
02246
02247
02248 if (outputFormat->plugins && nameLen > 0)
02249 for (j = 0; outputFormat->plugins[j].name; j++)
02250 if (isPlaceholder
02251 ^ ((outputFormat->plugins[j].options & kNMEPluginOptTripleAngleBrackets) == 0))
02252 {
02253
02254 for (k = 0; k < nameLen && outputFormat->plugins[j].name[k]; k++)
02255 if (name[k] != outputFormat->plugins[j].name[k])
02256 goto continueMainLoop;
02257 if (outputFormat->plugins[j].name[k] != '\0'
02258 || (k < nameLen
02259 && !(outputFormat->plugins[j].options & kNMEPluginOptPartialName)))
02260 goto continueMainLoop;
02261
02262
02263 CheckError(outputFormat->plugins[j].cb(name, nameLen,
02264 data, dataLen,
02265 context,
02266 outputFormat->plugins[j].userData));
02267
02268 *reparseOutput
02269 = (outputFormat->plugins[j].options & kNMEPluginOptReparseOutput) != 0;
02270
02271 return kNMEErrOk;
02272 continueMainLoop:
02273 ;
02274 }
02275
02276
02277 return kNMEErrOk;
02278 }
02279
02287 static void nextHeading(NMEInt *headingFlags,
02288 NMEInt headingNum[],
02289 NMEInt headingLevel)
02290 {
02291 NMEInt i;
02292
02293 if (headingLevel <= sizeof(*headingFlags))
02294 {
02295
02296 *headingFlags |= 1 << headingLevel - 1;
02297
02298 *headingFlags &= ~((~(NMEInt)0) << headingLevel);
02299 }
02300
02301 if (headingLevel <= kMaxNumberedHeadingLevels)
02302 {
02303 headingNum[headingLevel - 1]++;
02304 for (i = headingLevel; i < kMaxNumberedHeadingLevels; i++)
02305 headingNum[i] = 0;
02306 }
02307 }
02308
02328 static NMEBoolean parseNextToken(NMEConstText src, NMEInt srcLen,
02329 NMEInt *i,
02330 NMEState state,
02331 NMEBoolean verbatim,
02332 NMEInt nesting,
02333 NMEInt const listNum[],
02334 NMEStyle const styleStack[],
02335 NMEInt styleNesting,
02336 NMEOutputFormat const *outputFormat,
02337 NMEToken *token,
02338 NMEInt *headingLevel,
02339 NMEInt *itemNesting,
02340 NMEStyle *style,
02341 NMEInt options)
02342 {
02343 NMEInt k;
02344
02345
02346 if (state == kNMEStateHeading && isBlank(src[*i]))
02347 {
02348 k = *i;
02349 skipBlanks(src, srcLen, &k);
02350 if (k < srcLen && src[k] == '=')
02351 {
02352 NMEInt p;
02353
02354
02355 for (p = k + 1; p < srcLen && src[p] == '='; p++)
02356 ;
02357 skipBlanks(src, srcLen, &p);
02358 if (p >= srcLen || isEol(src[p]))
02359 *i = k;
02360 }
02361 }
02362
02363
02364 switch (src[*i])
02365 {
02366 case ' ':
02367 *token = kNMETokenSpace;
02368 (*i)++;
02369 return TRUE;
02370 case '\t':
02371 *token = kNMETokenTab;
02372 (*i)++;
02373 return TRUE;
02374 case '\r':
02375 *token = kNMETokenEOL;
02376 (*i)++;
02377 if (*i < srcLen && src[*i] == '\n')
02378 (*i)++;
02379 return TRUE;
02380 case '\n':
02381 *token = kNMETokenEOL;
02382 (*i)++;
02383 return TRUE;
02384 case '\\':
02385 if (verbatim)
02386 break;
02387 switch (state)
02388 {
02389 case kNMEStatePar:
02390 case kNMEStateHeading:
02391 case kNMEStateBetweenPar:
02392 case kNMEStateParAfterEol:
02393 if (*i + 1 >= srcLen || src[*i + 1] != '\\')
02394 break;
02395 *token = kNMETokenLineBreak;
02396 *i += 2;
02397 skipBlanks(src, srcLen, i);
02398 return TRUE;
02399 default:
02400
02401 break;
02402 }
02403 break;
02404 case '=':
02405 if (state == kNMEStatePar || state == kNMEStatePre
02406 || state == kNMEStatePreAfterEol || verbatim)
02407 break;
02408 if (state == kNMEStateHeading)
02409 {
02410
02411 for (k = *i; k < srcLen && src[k] == '='; k++)
02412 ;
02413 skipBlanks(src, srcLen, &k);
02414 if (k < srcLen && !isEol(src[k]))
02415 break;
02416 while (*i < srcLen && src[*i] == '=')
02417 (*i)++;
02418 }
02419 else
02420 {
02421 for (*headingLevel = 0;
02422 *i < srcLen && src[*i] == '=';
02423 (*i)++, (*headingLevel)++)
02424 ;
02425 if (options & kNMEProcessOptNoH1 && *headingLevel == 1)
02426 *headingLevel = 2;
02427 if (*headingLevel > outputFormat->maxHeadingLevel)
02428 *headingLevel = outputFormat->maxHeadingLevel;
02429 }
02430 *token = kNMETokenHeading;
02431 return TRUE;
02432 case '*':
02433 case '#':
02434 if (verbatim)
02435 break;
02436 switch (state)
02437 {
02438 case kNMEStatePar:
02439 case kNMEStateHeading:
02440 if (*i + 1 >= srcLen || src[*i + 1] != src[*i])
02441 break;
02442 if (options & (src[*i] == '*'
02443 ? kNMEProcessOptNoBold : kNMEProcessOptNoMonospace))
02444 break;
02445 *token = kNMETokenStyle;
02446 *style = src[*i] == '*' ? kNMEStyleBold : kNMEStyleMonospace;
02447 *i += 2;
02448 return TRUE;
02449 case kNMEStateBetweenPar:
02450 case kNMEStateParAfterEol:
02451 if (nesting == 0
02452 || (src[*i] == (listNum[0] == kNMEListNumUL ? '*' : listNum[0] > 0 ? '#' : 'x')
02453 && (nesting == 1 || *i + 1 >= srcLen || src[*i] != src[*i + 1]
02454 || (src[*i] == '*'
02455 ? options & kNMEProcessOptNoBold || listNum[1] == kNMEListNumUL
02456 : src[*i] == '#'
02457 ? options & kNMEProcessOptNoMonospace || listNum[1] > 0
02458 : TRUE))))
02459 {
02460
02461 if (*i + 1 >= srcLen
02462 || src[*i + 1] != src[*i]
02463 || (nesting > 0 && *i + 2 < srcLen)
02464 || options & (src[*i] == '*'
02465 ? kNMEProcessOptNoBold
02466 : kNMEProcessOptNoMonospace))
02467 goto tokenLI;
02468 }
02469
02470 if (*i + 1 < srcLen && src[*i + 1] == src[*i])
02471 {
02472 *token = kNMETokenStyle;
02473 *style = src[*i] == '*' ? kNMEStyleBold : kNMEStyleMonospace;
02474 *i += 2;
02475 return TRUE;
02476 }
02477
02478 default:
02479
02480 break;
02481 }
02482 break;
02483 case '/':
02484 if (*i >= 2 && src[*i - 1] == ':'
02485 && (isAlphaNum(src[*i - 2])
02486 || src[*i - 2] == '+' || src[*i - 2] == '-' || src[*i - 2] == '.')
02487 && *i + 2 < srcLen
02488 && !isBlank(src[*i + 2]) && !isEol(src[*i + 2]))
02489 break;
02490
02491 case '_':
02492 case '^':
02493 case ',':
02494 if (verbatim
02495 || (options & kNMEProcessOptNoItalic && src[*i] == '/')
02496 || (options & kNMEProcessOptNoUnderline && src[*i] == '_')
02497 || (options & kNMEProcessOptNoSubSuperscript && src[*i] == '^')
02498 || (options & kNMEProcessOptNoSubSuperscript && src[*i] == ','))
02499 break;
02500 switch (state)
02501 {
02502 case kNMEStatePar:
02503 case kNMEStateHeading:
02504 case kNMEStateBetweenPar:
02505 case kNMEStateParAfterEol:
02506 if (*i + 1 >= srcLen || src[*i + 1] != src[*i])
02507 break;
02508 *token = kNMETokenStyle;
02509 *style = src[*i] == '/' ? kNMEStyleItalic
02510 : src[*i] == '^' ? kNMEStyleSuperscript
02511 : src[*i] == ',' ? kNMEStyleSubscript
02512 : kNMEStyleUnderline;
02513 *i += 2;
02514 return TRUE;
02515 default:
02516
02517 break;
02518 }
02519 break;
02520 case ';':
02521 if (verbatim
02522 || options & kNMEProcessOptNoDL
02523 || (state != kNMEStateBetweenPar && state != kNMEStateParAfterEol))
02524 break;
02525
02526 if (nesting == 0 || listNum[0] == kNMEListNumDT || listNum[0] == kNMEListNumDD)
02527 goto tokenLI;
02528
02529 break;
02530 case ':':
02531 switch (state)
02532 {
02533 case kNMEStatePar:
02534 if (verbatim || nesting == 0 || listNum[nesting - 1] != kNMEListNumDT)
02535 break;
02536
02537 *token = kNMETokenDD;
02538 (*i)++;
02539 skipBlanks(src, srcLen, i);
02540 return TRUE;
02541 case kNMEStateParAfterEol:
02542 if (verbatim
02543 || (nesting > 0
02544 && listNum[nesting - 1] != kNMEListNumDT
02545 && listNum[nesting - 1] != kNMEListNumDD
02546 && listNum[0] != kNMEListIndented))
02547 break;
02548 if (nesting > 0)
02549 {
02550 if (listNum[nesting - 1] == kNMEListNumDT
02551 || listNum[nesting - 1] == kNMEListNumDD)
02552 {
02553
02554 *token = kNMETokenDD;
02555 (*i)++;
02556 skipBlanks(src, srcLen, i);
02557 return TRUE;
02558 }
02559 else if (listNum[0] != kNMEListIndented)
02560 goto tokenLI;
02561 }
02562
02563 case kNMEStateBetweenPar:
02564 if (options & kNMEProcessOptNoIndentedPar)
02565 break;
02566
02567 for (*itemNesting = 0;
02568 *i < srcLen && src[*i] == ':';
02569 (*i)++, (*itemNesting)++)
02570 ;
02571
02572 if (*itemNesting > kMaxNesting)
02573 *itemNesting = kMaxNesting;
02574 *token = kNMETokenLI;
02575 return TRUE;
02576 default:
02577
02578 break;
02579 }
02580 break;
02581 case '|':
02582 if (verbatim
02583 || options & kNMEProcessOptNoTable)
02584 break;
02585 switch (state)
02586 {
02587 case kNMEStatePar:
02588 if (nesting == 0
02589 || (listNum[nesting - 1] != kNMEListNumTableCell
02590 && listNum[nesting - 1] != kNMEListNumTableHCell))
02591 break;
02592
02593 case kNMEStateParAfterEol:
02594 case kNMEStateBetweenPar:
02595 if (*i + 1 < srcLen && src[*i + 1] == '=')
02596 {
02597 *token = kNMETokenTableHCell;
02598 *i += 2;
02599 }
02600 else
02601 {
02602 *token = kNMETokenTableCell;
02603 (*i)++;
02604 }
02605 skipBlanks(src, srcLen, i);
02606 if (state == kNMEStatePar)
02607 {
02608 if (*i >= srcLen)
02609 return FALSE;
02610 else if (isEol(src[*i]))
02611 {
02612
02613 (*i)++;
02614 if (src[*i - 1] == '\r' && *i < srcLen && src[*i] == '\n')
02615 (*i)++;
02616 *token = kNMETokenEOL;
02617 return TRUE;
02618 }
02619 }
02620 return TRUE;
02621 default:
02622
02623 break;
02624 }
02625 break;
02626 case '}':
02627 if (!(options & kNMEProcessOptNoImage)
02628 && !verbatim && *i + 1 < srcLen && src[*i + 1] == '}'
02629 && findStyleInStyleStack(styleStack, styleNesting,
02630 kNMEStyleImage, NULL)
02631 && state != kNMEStatePre && state != kNMEStatePreAfterEol)
02632 {
02633 *token = kNMETokenImageEnd;
02634 *i += 2;
02635 return TRUE;
02636 }
02637
02638 case '{':
02639
02640 if (*i + 2 >= srcLen || src[*i + 1] != src[*i]
02641 || src[*i + 2] != src[*i])
02642 {
02643 if (!(options & kNMEProcessOptNoImage)
02644 && !verbatim
02645 && *i + 1 < srcLen && src[*i] == '{' && src[*i + 1] == '{'
02646 && !findStyleInStyleStack(styleStack, styleNesting,
02647 kNMEStyleImage, NULL)
02648 && state != kNMEStatePre && state != kNMEStatePreAfterEol)
02649 {
02650 *token = kNMETokenImageBegin;
02651 *i += 2;
02652 return TRUE;
02653 }
02654 break;
02655 }
02656 if (src[*i] == '}' && *i + 3 < srcLen && src[*i + 3] == '}')
02657 break;
02658 switch (state)
02659 {
02660 case kNMEStatePar:
02661 case kNMEStateHeading:
02662 if (verbatim ? src[*i] == '{' : src[*i] == '}')
02663 break;
02664 *token = kNMETokenStyle;
02665 *style = kNMEStyleVerbatim;
02666 *i += 3;
02667 return TRUE;
02668 case kNMEStateBetweenPar:
02669 case kNMEStateParAfterEol:
02670 if (src[*i] == '}')
02671 break;
02672
02673 k = *i + 3;
02674 skipBlanks(src, srcLen, &k);
02675 if (k < srcLen && !isEol(src[k]))
02676 {
02677 *token = kNMETokenStyle;
02678 *style = kNMEStyleVerbatim;
02679 }
02680 else
02681 *token = kNMETokenPre;
02682 *i += 3;
02683 return TRUE;
02684 case kNMEStatePreAfterEol:
02685 if (src[*i] == '}')
02686 {
02687 *token = kNMETokenPre;
02688 *i += 3;
02689 return TRUE;
02690 }
02691 break;
02692 default:
02693
02694 break;
02695 }
02696 break;
02697 case ']':
02698 if (!findStyleInStyleStack(styleStack, styleNesting,
02699 kNMEStyleLink, NULL))
02700 break;
02701
02702 case '[':
02703
02704 if (verbatim || options & kNMEProcessOptNoLink)
02705 break;
02706 switch (state)
02707 {
02708 case kNMEStatePar:
02709 case kNMEStateHeading:
02710 case kNMEStateBetweenPar:
02711 case kNMEStateParAfterEol:
02712 if (*i + 1 >= srcLen || src[*i + 1] != src[*i])
02713 break;
02714 *token = src[*i] == '[' ? kNMETokenLinkBegin : kNMETokenLinkEnd;
02715 *i += 2;
02716 return TRUE;
02717 default:
02718
02719 break;
02720 }
02721 break;
02722 case '<':
02723
02724 if (verbatim
02725 || options & kNMEProcessOptNoPlugin
02726 || state == kNMEStatePre || state == kNMEStatePreAfterEol
02727 || *i + 2 >= srcLen
02728 || src[*i + 1] != '<')
02729 break;
02730 if (*i + 2 < srcLen && src[*i + 2] == '<')
02731 {
02732 *token = kNMETokenPlaceholder;
02733 *i += 3;
02734 }
02735 else
02736 {
02737 *token = kNMETokenPlugin;
02738 *i += 2;
02739 }
02740 if (state == kNMEStateBetweenPar || state == kNMEStateParAfterEol)
02741 {
02742
02743 k = *i;
02744 skipBlanks(src, srcLen, &k);
02745 if (k >= srcLen || isEol(src[k]))
02746 {
02747 if (*token == kNMETokenPlaceholder)
02748 *token = kNMETokenPlaceholderBlock;
02749 else
02750 *token = kNMETokenPluginBlock;
02751 }
02752 }
02753 return TRUE;
02754 case '-':
02755
02756 if (options & kNMEProcessOptNoHRule
02757 || (state != kNMEStateBetweenPar && state != kNMEStateParAfterEol)
02758 || *i + 3 >= srcLen
02759 || src[*i + 1] != '-' || src[*i + 2] != '-'
02760 || src[*i + 3] != '-')
02761 break;
02762
02763 while (*i < srcLen && src[*i] == '-')
02764 (*i)++;
02765 *token = kNMETokenHR;
02766 return TRUE;
02767 case '~':
02768
02769 if (verbatim
02770 || options & kNMEProcessOptNoEscape
02771 || state == kNMEStatePre || state == kNMEStatePreAfterEol
02772 || *i + 1 >= srcLen
02773 || isEol(src[*i + 1]) || isBlank(src[*i + 1]))
02774 break;
02775 *i += 2;
02776 *token = kNMETokenChar;
02777 return TRUE;
02778 }
02779
02780 *token = kNMETokenChar;
02781 (*i)++;
02782 return TRUE;
02783
02784 tokenLI:
02785
02786 for (*itemNesting = 0;
02787 *i < srcLen
02788 && (src[*i] == '*' || src[*i] == '#' || src[*i] == ';'
02789 || (src[*i] == ':' && *itemNesting < nesting))
02790 && (*itemNesting >= nesting
02791 || (listNum[*itemNesting] == kNMEListNumUL ? src[*i] == '*'
02792 : listNum[*itemNesting] == kNMEListNumDT
02793 || listNum[*itemNesting] == kNMEListNumDD
02794 ? src[*i] == ';' || src[*i] == ':'
02795 : src[*i] == '#'));
02796 (*i)++, (*itemNesting)++)
02797 ;
02798
02799 if (*itemNesting > kMaxNesting)
02800 *itemNesting = kMaxNesting;
02801 *token = src[*i - 1] == ':' ? kNMETokenDD : kNMETokenLI;
02802 return TRUE;
02803 }
02804
02815 static NMEErr swapBuffers(NMEText *src, NMEInt *srcLen,
02816 NMEContext *context,
02817 NMEInt *commonLen,
02818 NMEInt destLen0)
02819 {
02820 NMEInt k;
02821 NMEText tmp;
02822
02823
02824 if (*srcLen + context->destLen - context->srcIndex > context->bufSize
02825 || destLen0 > context->bufSize)
02826 return kNMEErrNotEnoughMemory;
02827
02828
02829 updateLineNum(context);
02830
02831
02832 for (k = 0; k < *srcLen - context->srcIndex; k++)
02833 context->dest[context->destLen + k] = (*src)[context->srcIndex + k];
02834 for (k = 0; k < destLen0 - *commonLen; k++)
02835 (*src)[*commonLen + k] = context->dest[*commonLen + k];
02836 *commonLen = destLen0;
02837 *srcLen += context->destLen - context->srcIndex;
02838 context->srcIndexOffset -= context->destLen - context->srcIndex;
02839 context->srcIndex = context->srcIndexForLineNum = context->destLen = destLen0;
02840 tmp = *src; *src = context->dest; context->dest = tmp;
02841
02842 return kNMEErrOk;
02843 }
02844
02845 NMEErr NMEProcess(NMEConstText nmeText, NMEInt nmeTextLen,
02846 NMEText buf, NMEInt bufSize,
02847 NMEInt options,
02848 NMEConstText eol,
02849 NMEOutputFormat const *outputFormat,
02850 NMEInt fontSize,
02851 NMEText *output,
02852 NMEInt *outputLen,
02853 NMEInt *outputUCS16Len)
02854 {
02855
02856
02857
02858
02859
02860
02861
02862
02863
02864
02865
02866
02867
02868
02869
02870
02871
02872 NMEInt destLenTmp;
02873 NMEInt commonLen;
02874 NMEInt i0;
02875 NMEInt noAutoOrPluginLen;
02876 NMEBoolean reparseOutput;
02877 NMEState state;
02878 NMEToken token;
02879 NMEInt headingNum[kMaxNumberedHeadingLevels];
02880 NMEInt headingFlags;
02881 NMEStyle styleStack[kNMEStylesCount];
02882 NMEInt styleNesting;
02883 NMEStyle newStyle = (NMEStyle)0;
02884 NMEInt itemNesting = 0;
02885 NMEInt headingLevel = 0;
02886 NMEInt headingLevel0 = 0;
02887 NMEBoolean firstIteration;
02888 NMEContext context;
02889 NMEErr err;
02890
02891 #define HOOK(cb, l, it, e, m) \
02892 do { \
02893 if (outputFormat->cb) \
02894 { \
02895 updateLineNum(&context); \
02896 err = outputFormat->cb(l, it, e, m, \
02897 i0 + context.srcIndexOffset, \
02898 context.srcLineNum, \
02899 &context, \
02900 outputFormat->hookData); \
02901 if (err != kNMEErrOk) \
02902 return err; \
02903 } \
02904 } while (0)
02905
02906
02907 if (!outputFormat)
02908 outputFormat = &NMEOutputFormatText;
02909 context.fontSize = fontSize > 0 ? fontSize : outputFormat->defFontSize;
02910 context.options = options;
02911 context.eol = eol;
02912 context.ctrlChar = outputFormat->ctrlChar;
02913 context.xref = (options & kNMEProcessOptXRef) != 0;
02914 setContext(context, 0, 0);
02915
02916
02917 if (nmeTextLen > bufSize / 2)
02918 return kNMEErrNotEnoughMemory;
02919 context.src = buf;
02920 context.srcLen = nmeTextLen;
02921 for (i0 = 0; i0 < nmeTextLen; i0++)
02922 buf[i0] = nmeText[i0];
02923 context.dest = buf + bufSize / 2;
02924 context.bufSize = bufSize / 2;
02925
02926
02927 context.outputFormat = outputFormat;
02928 context.destLen = context.col = 0;
02929 context.destLenUCS16 = 0;
02930 commonLen = noAutoOrPluginLen = 0;
02931 context.currentIndent = 0;
02932 state = kNMEStateBetweenPar;
02933 context.nesting = 0;
02934 styleNesting = 0;
02935 headingNum[0] = -1;
02936 nextHeading(&headingFlags, headingNum, 1);
02937 headingFlags = 0;
02938 context.srcIndex = 0;
02939 context.srcIndexOffset = 0;
02940 context.srcLineNum = 1;
02941 context.srcIndexForLineNum = 0;
02942
02943
02944 if (!(options & kNMEProcessOptNoPreAndPost)
02945 && !NMEAddString(outputFormat->beginDoc, -1, context.ctrlChar, &context))
02946 return kNMEErrNotEnoughMemory;
02947
02948
02949 while (context.srcIndex < context.srcLen)
02950 {
02951
02952 if (context.destLen + kNMETokenTab >= context.bufSize)
02953 return kNMEErrNotEnoughMemory;
02954
02955
02956 if (state != kNMEStatePre && state != kNMEStatePreAfterEol
02957 && context.srcIndex >= noAutoOrPluginLen
02958 && !(options & kNMEProcessOptNoPlugin)
02959 && outputFormat->autoconverts)
02960 {
02961 NMEInt k;
02962
02963 for (k = 0; outputFormat->autoconverts[k].cb; k++)
02964 {
02965 destLenTmp = context.destLen;
02966 if (outputFormat->autoconverts[k].cb(context.src, context.srcLen, &context.srcIndex,
02967 &context,
02968 outputFormat->autoconverts[k].userData))
02969 {
02970 noAutoOrPluginLen = context.destLen;
02971 CheckError(swapBuffers(&context.src, &context.srcLen,
02972 &context,
02973 &commonLen,
02974 destLenTmp));
02975 break;
02976 }
02977 }
02978 }
02979
02980
02981 i0 = context.srcIndex;
02982 headingLevel0 = headingLevel;
02983 if (!parseNextToken(context.src, context.srcLen, &context.srcIndex,
02984 state,
02985 styleNesting > 0 && styleStack[styleNesting - 1] == kNMEStyleVerbatim,
02986 context.nesting, context.listNum,
02987 styleStack, styleNesting,
02988 outputFormat,
02989 &token,
02990 &headingLevel,
02991 &itemNesting,
02992 &newStyle,
02993 options))
02994 break;
02995
02996
02997 switch (state)
02998 {
02999 case kNMEStateBetweenPar:
03000 switch (token)
03001 {
03002 case kNMETokenChar:
03003 HOOK(parHookFun, kNMEHookLevelPar, 0, TRUE, "p");
03004 if (!NMEAddString(outputFormat->beginPar, -1,
03005 context.ctrlChar, &context))
03006 return kNMEErrNotEnoughMemory;
03007 if (outputFormat->charHookFun)
03008 CheckError(outputFormat->charHookFun(i0 + context.srcIndexOffset,
03009 &context,
03010 outputFormat->charHookData));
03011 if (outputFormat->encodeCharFun)
03012 {
03013 context.srcIndex--;
03014 CheckError(outputFormat->encodeCharFun(context.src,
03015 context.srcLen, &context.srcIndex,
03016 &context,
03017 outputFormat->encodeCharData));
03018 }
03019 else
03020 {
03021 context.dest[context.destLen++] = context.src[context.srcIndex - 1];
03022 if (isFirstUTF8Byte(context.src[context.srcIndex - 1]))
03023 context.destLenUCS16++;
03024 context.col++;
03025 }
03026 CheckError(checkWordwrap(&context, outputFormat));
03027 state = kNMEStatePar;
03028 break;
03029 case kNMETokenSpace:
03030 case kNMETokenTab:
03031
03032 break;
03033 case kNMETokenEOL:
03034
03035 break;
03036 case kNMETokenHeading:
03037 for (; headingLevel0 >= headingLevel; headingLevel0--)
03038 if ((headingFlags >> headingLevel0 - 1) & 1)
03039 HOOK(divHookFun, headingLevel0, 0, FALSE, "=");
03040 nextHeading(&headingFlags, headingNum, headingLevel);
03041 context.level = headingLevel;
03042 context.item = headingLevel <= kMaxNumberedHeadingLevels
03043 && options & (headingLevel == 1
03044 ? kNMEProcessOptH1Num : kNMEProcessOptH2Num)
03045 ? headingNum[headingLevel - 1]
03046 : 0;
03047 HOOK(divHookFun, context.level, 0, TRUE, "=");
03048 HOOK(parHookFun, context.level, context.item, TRUE, "=");
03049 if (!NMEAddString(outputFormat->beginHeading, -1,
03050 context.ctrlChar, &context))
03051 return kNMEErrNotEnoughMemory;
03052 context.level = 0;
03053 state = kNMEStateHeading;
03054 skipBlanks(context.src, context.srcLen, &context.srcIndex);
03055 break;
03056 case kNMETokenLineBreak:
03057 HOOK(parHookFun, kNMEHookLevelPar, 0, TRUE, "p");
03058 if (!NMEAddString(outputFormat->beginPar, -1,
03059 context.ctrlChar, &context)
03060 || !NMEAddString(outputFormat->lineBreak, -1,
03061 context.ctrlChar, &context))
03062 return kNMEErrNotEnoughMemory;
03063 state = kNMEStatePar;
03064 break;
03065 case kNMETokenPre:
03066 HOOK(parHookFun, kNMEHookLevelPar, 0, TRUE, "{{{");
03067 if (!NMEAddString(outputFormat->beginPre, -1,
03068 context.ctrlChar, &context)
03069
03070 )
03071 return kNMEErrNotEnoughMemory;
03072 state = kNMEStatePreAfterEol;
03073
03074 if (context.srcIndex < context.srcLen && context.src[context.srcIndex] == '\r')
03075 context.srcIndex++;
03076 if (context.srcIndex < context.srcLen && context.src[context.srcIndex] == '\n')
03077 context.srcIndex++;
03078 break;
03079 case kNMETokenLI:
03080
03081 for (context.nesting = 0; context.nesting < itemNesting; context.nesting++)
03082 {
03083 context.listNum[context.nesting]
03084 = context.src[context.srcIndex - itemNesting + context.nesting] == '*'
03085 ? kNMEListNumUL
03086 : context.src[context.srcIndex - itemNesting + context.nesting] == ';'
03087 ? kNMEListNumDT
03088 : context.src[context.srcIndex - itemNesting + context.nesting] == ':'
03089 ? kNMEListIndented
03090 : 1;
03091 setContext(context, context.nesting + 1, context.listNum[context.nesting]);
03092 switch (context.listNum[context.nesting])
03093 {
03094 case kNMEListNumUL:
03095 HOOK(divHookFun, context.level, 0, TRUE, "*");
03096 if (!NMEAddString(outputFormat->beginUL, -1, context.ctrlChar, &context))
03097 return kNMEErrNotEnoughMemory;
03098 if (outputFormat->sublistInListItem && context.nesting + 1 < itemNesting)
03099 if (!NMEAddString(outputFormat->beginULItem, -1, context.ctrlChar, &context))
03100 return kNMEErrNotEnoughMemory;
03101 break;
03102 case kNMEListNumDT:
03103 case kNMEListNumDD:
03104 HOOK(divHookFun, context.level, 0, TRUE, ";");
03105 if (!NMEAddString(outputFormat->beginDL, -1, context.ctrlChar, &context))
03106 return kNMEErrNotEnoughMemory;
03107 if (outputFormat->sublistInListItem && context.nesting + 1 < itemNesting)
03108 if (!NMEAddString(outputFormat->beginDD, -1, context.ctrlChar, &context))
03109 return kNMEErrNotEnoughMemory;
03110 break;
03111 case kNMEListIndented:
03112 HOOK(divHookFun, context.level, 0, TRUE, ":");
03113 if (!NMEAddString(outputFormat->beginIndented, -1, context.ctrlChar, &context))
03114 return kNMEErrNotEnoughMemory;
03115
03116 break;
03117 default:
03118 HOOK(divHookFun, context.level, 0, TRUE, "#");
03119 if (!NMEAddString(outputFormat->beginOL, -1, context.ctrlChar, &context))
03120 return kNMEErrNotEnoughMemory;
03121 if (outputFormat->sublistInListItem && context.nesting + 1 < itemNesting)
03122 if (!NMEAddString(outputFormat->beginOLItem, -1, context.ctrlChar, &context))
03123 return kNMEErrNotEnoughMemory;
03124 break;
03125 }
03126 context.level = 0;
03127 }
03128
03129 skipBlanks(context.src, context.srcLen, &context.srcIndex);
03130
03131 context.currentIndent = context.nesting * outputFormat->indentSpaces;
03132 setContext(context, context.nesting, context.listNum[context.nesting - 1]);
03133 HOOK(parHookFun, context.level, context.item, TRUE,
03134 context.listNum[context.nesting - 1] == kNMEListNumUL ? "*"
03135 : context.listNum[context.nesting - 1] == kNMEListNumDT ? ";"
03136 : context.listNum[context.nesting - 1] == kNMEListIndented ? ":"
03137 : "#");
03138 if (!NMEAddString(context.listNum[context.nesting - 1] == kNMEListNumUL
03139 ? outputFormat->beginULItem
03140 : context.listNum[context.nesting - 1] == kNMEListNumDT
03141 ? outputFormat->beginDT
03142 : context.listNum[context.nesting - 1] == kNMEListIndented
03143 ? outputFormat->beginIndentedPar
03144 : outputFormat->beginOLItem,
03145 -1,
03146 context.ctrlChar, &context))
03147 return kNMEErrNotEnoughMemory;
03148 setContext(context, 0, 0);
03149 state = kNMEStatePar;
03150 break;
03151 case kNMETokenTableCell:
03152 case kNMETokenTableHCell:
03153
03154 if (context.nesting > 0)
03155 switch (context.listNum[context.nesting - 1])
03156 {
03157 case kNMEListNumUL:
03158 if (!NMEAddString(outputFormat->beginULItem, -1, context.ctrlChar, &context))
03159 return kNMEErrNotEnoughMemory;
03160 break;
03161 case kNMEListNumDT:
03162 case kNMEListNumDD:
03163 if (!NMEAddString(outputFormat->beginDD, -1, context.ctrlChar, &context))
03164 return kNMEErrNotEnoughMemory;
03165 break;
03166 case kNMEListIndented:
03167 if (!NMEAddString(outputFormat->beginIndentedPar, -1, context.ctrlChar, &context))
03168 return kNMEErrNotEnoughMemory;
03169 break;
03170 default:
03171 if (!NMEAddString(outputFormat->beginOLItem, -1, context.ctrlChar, &context))
03172 return kNMEErrNotEnoughMemory;
03173 break;
03174 }
03175 context.listNum[context.nesting++]
03176 = token == kNMETokenTableCell
03177 ? kNMEListNumTableCell
03178 : kNMEListNumTableHCell;
03179 context.currentIndent = context.nesting * outputFormat->indentSpaces;
03180 state = kNMEStatePar;
03181 context.level = context.nesting - 1;
03182 HOOK(divHookFun, kNMEHookLevelPar, 0, TRUE, "|");
03183 if (!NMEAddString(outputFormat->beginTable, -1,
03184 context.ctrlChar, &context)
03185 || !NMEAddString(outputFormat->beginTableRow, -1,
03186 context.ctrlChar, &context))
03187 return kNMEErrNotEnoughMemory;
03188 HOOK(parHookFun, kNMEHookLevelPar, 0, TRUE,
03189 token == kNMETokenTableCell ? "|" : "|=");
03190 if (!NMEAddString(token == kNMETokenTableCell
03191 ? outputFormat->beginTableCell
03192 : outputFormat->beginTableHCell,
03193 -1,
03194 context.ctrlChar, &context))
03195 return kNMEErrNotEnoughMemory;
03196 context.level = 0;
03197 break;
03198 case kNMETokenHR:
03199 HOOK(parHookFun, kNMEHookLevelPar, 0, TRUE, "----");
03200 if (!NMEAddString(outputFormat->horRule, -1,
03201 context.ctrlChar, &context))
03202 return kNMEErrNotEnoughMemory;
03203 HOOK(parHookFun, kNMEHookLevelPar, 0, FALSE, "----");
03204 break;
03205 case kNMETokenStyle:
03206 HOOK(parHookFun, kNMEHookLevelPar, 0, TRUE, "p");
03207 if (!NMEAddString(outputFormat->beginPar, -1,
03208 context.ctrlChar, &context))
03209 return kNMEErrNotEnoughMemory;
03210 CheckError(processStyleTag(styleStack, &styleNesting,
03211 newStyle,
03212 i0,
03213 outputFormat, &context));
03214 state = kNMEStatePar;
03215 break;
03216 case kNMETokenLinkBegin:
03217 case kNMETokenImageBegin:
03218 HOOK(parHookFun, kNMEHookLevelPar, 0, TRUE, "p");
03219 if (!NMEAddString(outputFormat->beginPar, -1,
03220 context.ctrlChar, &context))
03221 return kNMEErrNotEnoughMemory;
03222 CheckError(addLinkBegin(token == kNMETokenImageBegin,
03223 styleStack, &styleNesting,
03224 i0, outputFormat, &context));
03225 state = kNMEStatePar;
03226 break;
03227 case kNMETokenPlugin:
03228 case kNMETokenPluginBlock:
03229 case kNMETokenPlaceholder:
03230 case kNMETokenPlaceholderBlock:
03231 {
03232 NMEInt pluginIndex;
03233
03234 pluginIndex = findPlugin(context.src, context.srcLen, context.srcIndex,
03235 token == kNMETokenPlaceholder
03236 || token == kNMETokenPlaceholderBlock,
03237 outputFormat);
03238 if (pluginIndex >= 0
03239 && !(outputFormat->plugins[pluginIndex].options
03240 & kNMEPluginOptBetweenPar))
03241 {
03242
03243 HOOK(parHookFun, kNMEHookLevelPar, 0, TRUE, "p");
03244 if (!NMEAddString(outputFormat->beginPar, -1,
03245 context.ctrlChar, &context))
03246 return kNMEErrNotEnoughMemory;
03247 state = kNMEStatePar;
03248 }
03249 destLenTmp = context.destLen;
03250 CheckError(addPlugin(token == kNMETokenPluginBlock
03251 || token == kNMETokenPlaceholderBlock,
03252 token == kNMETokenPlaceholder
03253 || token == kNMETokenPlaceholderBlock,
03254 options, outputFormat, &context,
03255 &reparseOutput));
03256 if (reparseOutput)
03257 {
03258 CheckError(swapBuffers(&context.src, &context.srcLen,
03259 &context,
03260 &commonLen,
03261 destLenTmp));
03262
03263 }
03264 }
03265 break;
03266 case kNMETokenDD:
03267 case kNMETokenLinkEnd:
03268 case kNMETokenImageEnd:
03269
03270 return kNMEErrInternal;
03271 }
03272 break;
03273 case kNMEStatePar:
03274 switch (token)
03275 {
03276 case kNMETokenChar:
03277 if (outputFormat->charHookFun)
03278 CheckError(outputFormat->charHookFun(i0 + context.srcIndexOffset,
03279 &context,
03280 outputFormat->charHookData));
03281 if (outputFormat->encodeCharFun)
03282 {
03283 context.srcIndex--;
03284 CheckError(outputFormat->encodeCharFun(context.src, context.srcLen, &context.srcIndex,
03285 &context,
03286 outputFormat->encodeCharData));
03287 }
03288 else
03289 {
03290 context.dest[context.destLen++] = context.src[context.srcIndex - 1];
03291 if (isFirstUTF8Byte(context.src[context.srcIndex - 1]))
03292 context.destLenUCS16++;
03293 context.col++;
03294 }
03295 CheckError(checkWordwrap(&context, outputFormat));
03296 break;
03297 case kNMETokenSpace:
03298 case kNMETokenTab:
03299 skipBlanks(context.src, context.srcLen, &context.srcIndex);
03300
03301 if (context.srcIndex < context.srcLen && !isEol(context.src[context.srcIndex]))
03302 {
03303 if (!NMEAddString(outputFormat->space, -1,
03304 context.ctrlChar, &context))
03305 return kNMEErrNotEnoughMemory;
03306 CheckError(checkWordwrap(&context, outputFormat));
03307 }
03308 break;
03309 case kNMETokenLineBreak:
03310 if (!NMEAddString(outputFormat->lineBreak, -1,
03311 context.ctrlChar, &context))
03312 return kNMEErrNotEnoughMemory;
03313 CheckError(checkWordwrap(&context, outputFormat));
03314 break;
03315 case kNMETokenEOL:
03316 state = kNMEStateParAfterEol;
03317 break;
03318 case kNMETokenDD:
03319 context.level = context.nesting;
03320 CheckError(flushStyleTags(styleStack, &styleNesting,
03321 i0,
03322 outputFormat, &context));
03323 CheckError(addEndPar(FALSE, outputFormat, &context, i0));
03324 context.listNum[context.nesting - 1] = kNMEListNumDD;
03325 HOOK(parHookFun, context.level, context.item, TRUE, ";:");
03326 if (!NMEAddString(outputFormat->beginDD, -1,
03327 context.ctrlChar, &context))
03328 return kNMEErrNotEnoughMemory;
03329 CheckError(checkWordwrap(&context, outputFormat));
03330 context.level = 0;
03331 break;
03332 case kNMETokenTableCell:
03333 case kNMETokenTableHCell:
03334
03335 while (context.destLen > 0 && context.dest[context.destLen - 1] == ' ')
03336 {
03337 context.destLen--;
03338 context.destLenUCS16--;
03339 }
03340
03341 context.level = context.nesting;
03342 CheckError(flushStyleTags(styleStack, &styleNesting,
03343 i0,
03344 outputFormat, &context));
03345 if (!NMEAddString(context.listNum[context.nesting - 1] == kNMEListNumTableCell
03346 ? outputFormat->endTableCell
03347 : outputFormat->endTableHCell,
03348 -1,
03349 context.ctrlChar, &context))
03350 return kNMEErrNotEnoughMemory;
03351 CheckError(checkWordwrap(&context, outputFormat));
03352 HOOK(parHookFun, kNMEHookLevelPar, 0, FALSE,
03353 context.listNum[context.nesting - 1] == kNMEListNumTableCell
03354 ? "|" : "|=");
03355 CheckError(checkWordwrap(&context, outputFormat));
03356 HOOK(parHookFun, kNMEHookLevelPar, 0, TRUE,
03357 token == kNMETokenTableCell ? "|" : "|=");
03358 if (!NMEAddString(token == kNMETokenTableCell
03359 ? outputFormat->beginTableCell
03360 : outputFormat->beginTableHCell,
03361 -1,
03362 context.ctrlChar, &context))
03363 return kNMEErrNotEnoughMemory;
03364 CheckError(checkWordwrap(&context, outputFormat));
03365 context.level = 0;
03366 context.listNum[context.nesting - 1] = token == kNMETokenTableCell
03367 ? kNMEListNumTableCell
03368 : kNMEListNumTableHCell;
03369 break;
03370 case kNMETokenStyle:
03371 case kNMETokenLinkEnd:
03372 case kNMETokenImageEnd:
03373 CheckError(processStyleTag(styleStack, &styleNesting,
03374 token == kNMETokenLinkEnd ? kNMEStyleLink
03375 : token == kNMETokenImageEnd ? kNMEStyleImage : newStyle,
03376 i0,
03377 outputFormat, &context));
03378 break;
03379 case kNMETokenLinkBegin:
03380 case kNMETokenImageBegin:
03381 CheckError(addLinkBegin(token == kNMETokenImageBegin,
03382 styleStack, &styleNesting,
03383 i0, outputFormat, &context));
03384 break;
03385 case kNMETokenPlugin:
03386 case kNMETokenPluginBlock:
03387 case kNMETokenPlaceholder:
03388 case kNMETokenPlaceholderBlock:
03389 {
03390 NMEInt pluginIndex;
03391
03392 pluginIndex = findPlugin(context.src, context.srcLen, context.srcIndex,
03393 token == kNMETokenPlaceholder
03394 || token == kNMETokenPlaceholderBlock,
03395 outputFormat);
03396 if (pluginIndex >= 0
03397 && outputFormat->plugins[pluginIndex].options
03398 & kNMEPluginOptBetweenPar)
03399 {
03400
03401 CheckError(flushStyleTags(styleStack, &styleNesting,
03402 i0,
03403 outputFormat, &context));
03404 CheckError(addEndPar(TRUE, outputFormat, &context, i0));
03405 state = kNMEStateBetweenPar;
03406 }
03407 destLenTmp = context.destLen;
03408 CheckError(addPlugin(token == kNMETokenPluginBlock
03409 || token == kNMETokenPlaceholderBlock,
03410 token == kNMETokenPlaceholder
03411 || token == kNMETokenPlaceholderBlock,
03412 options, outputFormat, &context,
03413 &reparseOutput));
03414 if (reparseOutput)
03415 {
03416 CheckError(swapBuffers(&context.src, &context.srcLen,
03417 &context,
03418 &commonLen,
03419 destLenTmp));
03420
03421 }
03422 }
03423 break;
03424 case kNMETokenHeading:
03425 case kNMETokenLI:
03426 case kNMETokenHR:
03427 case kNMETokenPre:
03428
03429 return kNMEErrInternal;
03430 }
03431 break;
03432 case kNMEStateParAfterEol:
03433 switch (token)
03434 {
03435 case kNMETokenChar:
03436 if (options & kNMEProcessOptNoMultilinePar
03437 || (context.nesting > 0
03438 && (context.listNum[context.nesting - 1] == kNMEListNumTableCell
03439 || context.listNum[context.nesting - 1] == kNMEListNumTableHCell)))
03440 {
03441
03442 CheckError(flushStyleTags(styleStack, &styleNesting,
03443 i0,
03444 outputFormat, &context));
03445 CheckError(addEndPar(TRUE, outputFormat, &context, i0));
03446 HOOK(parHookFun, kNMEHookLevelPar, 0, TRUE, "p");
03447 if (!NMEAddString(outputFormat->beginPar, -1,
03448 context.ctrlChar, &context))
03449 return kNMEErrNotEnoughMemory;
03450 context.currentIndent = 0;
03451 }
03452 else
03453 if (!NMEAddString(outputFormat->space, -1,
03454 context.ctrlChar, &context))
03455 return kNMEErrNotEnoughMemory;
03456 CheckError(checkWordwrap(&context, outputFormat));
03457 if (outputFormat->charHookFun)
03458 CheckError(outputFormat->charHookFun(i0 + context.srcIndexOffset,
03459 &context,
03460 outputFormat->charHookData));
03461 if (outputFormat->encodeCharFun)
03462 {
03463 context.srcIndex--;
03464 CheckError(outputFormat->encodeCharFun(context.src, context.srcLen, &context.srcIndex,
03465 &context,
03466 outputFormat->encodeCharData));
03467 }
03468 else
03469 {
03470 context.dest[context.destLen++] = context.src[context.srcIndex - 1];
03471 if (isFirstUTF8Byte(context.src[context.srcIndex - 1]))
03472 context.destLenUCS16++;
03473 context.col++;
03474 }
03475 state = kNMEStatePar;
03476 break;
03477 case kNMETokenSpace:
03478 case kNMETokenTab:
03479
03480 break;
03481 case kNMETokenEOL:
03482 CheckError(flushStyleTags(styleStack, &styleNesting,
03483 i0,
03484 outputFormat, &context));
03485 CheckError(addEndPar(TRUE, outputFormat, &context, i0));
03486 state = kNMEStateBetweenPar;
03487 context.currentIndent = context.nesting * outputFormat->indentSpaces;
03488 break;
03489 case kNMETokenDD:
03490 context.level = context.nesting;
03491 CheckError(flushStyleTags(styleStack, &styleNesting,
03492 i0,
03493 outputFormat, &context));
03494 CheckError(addEndPar(FALSE, outputFormat, &context, i0));
03495
03496 while (context.nesting > itemNesting)
03497 {
03498 setContext(context, context.nesting, context.listNum[context.nesting - 1]);
03499 context.nesting--;
03500 switch (context.listNum[context.nesting])
03501 {
03502 case kNMEListNumUL:
03503 if (!NMEAddString(outputFormat->endUL, -1, context.ctrlChar, &context))
03504 return kNMEErrNotEnoughMemory;
03505 HOOK(divHookFun, context.level, 0, FALSE, "*");
03506 break;
03507 case kNMEListNumDT:
03508 case kNMEListNumDD:
03509 if (!NMEAddString(outputFormat->endDL, -1, context.ctrlChar, &context))
03510 return kNMEErrNotEnoughMemory;
03511 HOOK(divHookFun, context.level, 0, FALSE, ";");
03512 break;
03513 case kNMEListIndented:
03514 if (!NMEAddString(outputFormat->endIndented, -1, context.ctrlChar, &context))
03515 return kNMEErrNotEnoughMemory;
03516 HOOK(divHookFun, context.level, 0, FALSE, ":");
03517 break;
03518 default:
03519 if (!NMEAddString(outputFormat->endOL, -1, context.ctrlChar, &context))
03520 return kNMEErrNotEnoughMemory;
03521 HOOK(divHookFun, context.level, 0, FALSE, "#");
03522 break;
03523 }
03524 if (outputFormat->sublistInListItem && context.nesting > 0)
03525 {
03526 setContext(context, context.nesting, context.listNum[context.nesting - 1]);
03527 switch (context.listNum[context.nesting - 1])
03528 {
03529 case kNMEListNumUL:
03530 if (!NMEAddString(outputFormat->endULItem, -1, context.ctrlChar, &context))
03531 return kNMEErrNotEnoughMemory;
03532 break;
03533 case kNMEListNumDT:
03534 case kNMEListNumDD:
03535 if (!NMEAddString(outputFormat->endDD, -1, context.ctrlChar, &context))
03536 return kNMEErrNotEnoughMemory;
03537 break;
03538 case kNMEListIndented:
03539
03540 break;
03541 default:
03542 if (!NMEAddString(outputFormat->endOLItem, -1, context.ctrlChar, &context))
03543 return kNMEErrNotEnoughMemory;
03544 break;
03545 }
03546 }
03547 }
03548 setContext(context, context.nesting, 0);
03549 if (context.listNum[context.nesting - 1] != kNMEListNumDT
03550 && outputFormat->emptyDT)
03551 {
03552 if (!NMEAddString(outputFormat->emptyDT, -1,
03553 context.ctrlChar, &context))
03554 return kNMEErrNotEnoughMemory;
03555 CheckError(checkWordwrap(&context, outputFormat));
03556 }
03557
03558 skipBlanks(context.src, context.srcLen, &context.srcIndex);
03559
03560 context.listNum[context.nesting - 1] = kNMEListNumDD;
03561 HOOK(parHookFun, context.level, context.item, TRUE, ";:");
03562 if (!NMEAddString(outputFormat->beginDD, -1, context.ctrlChar, &context))
03563 return kNMEErrNotEnoughMemory;
03564 CheckError(checkWordwrap(&context, outputFormat));
03565 context.level = 0;
03566 state = kNMEStatePar;
03567 break;
03568 case kNMETokenLineBreak:
03569 if (!NMEAddString(outputFormat->lineBreak, -1,
03570 context.ctrlChar, &context))
03571 return kNMEErrNotEnoughMemory;
03572 CheckError(checkWordwrap(&context, outputFormat));
03573 break;
03574 case kNMETokenPre:
03575 CheckError(flushStyleTags(styleStack, &styleNesting,
03576 i0,
03577 outputFormat, &context));
03578 CheckError(addEndPar(TRUE, outputFormat, &context, i0));
03579 HOOK(parHookFun, kNMEHookLevelPar, 0, TRUE, "{{{");
03580 if (!NMEAddString(outputFormat->beginPre, -1,
03581 context.ctrlChar, &context)
03582 || !NMEAddString(outputFormat->beginPreLine, -1,
03583 context.ctrlChar, &context))
03584 return kNMEErrNotEnoughMemory;
03585 CheckError(checkWordwrap(&context, outputFormat));
03586 state = kNMEStatePreAfterEol;
03587 context.currentIndent = 0;
03588
03589 if (context.srcIndex < context.srcLen && context.src[context.srcIndex] == '\r')
03590 context.srcIndex++;
03591 if (context.srcIndex < context.srcLen && context.src[context.srcIndex] == '\n')
03592 context.srcIndex++;
03593 break;
03594 case kNMETokenHeading:
03595 CheckError(flushStyleTags(styleStack, &styleNesting,
03596 i0,
03597 outputFormat, &context));
03598 CheckError(addEndPar(TRUE, outputFormat, &context, i0));
03599 for (; headingLevel0 >= headingLevel; headingLevel0--)
03600 if ((headingFlags >> headingLevel0 - 1) & 1)
03601 HOOK(divHookFun, headingLevel0, 0, FALSE, "=");
03602 nextHeading(&headingFlags, headingNum, headingLevel);
03603 context.level = headingLevel;
03604 context.item = headingLevel <= kMaxNumberedHeadingLevels
03605 && options & (headingLevel == 1
03606 ? kNMEProcessOptH1Num : kNMEProcessOptH2Num)
03607 ? headingNum[headingLevel - 1]
03608 : 0;
03609 HOOK(divHookFun, context.level, 0, TRUE, "=");
03610 HOOK(parHookFun, context.level, context.item, TRUE, "=");
03611 if (!NMEAddString(outputFormat->beginHeading, -1,
03612 context.ctrlChar, &context))
03613 return kNMEErrNotEnoughMemory;
03614 context.currentIndent = 0;
03615 context.level = 0;
03616 state = kNMEStateHeading;
03617 skipBlanks(context.src, context.srcLen, &context.srcIndex);
03618 break;
03619 case kNMETokenLI:
03620
03621 CheckError(flushStyleTags(styleStack, &styleNesting,
03622 i0,
03623 outputFormat, &context));
03624 if (!outputFormat->sublistInListItem
03625 || (context.nesting > 0
03626 && context.listNum[context.nesting - 1] == kNMEListIndented)
03627 || itemNesting <= context.nesting
03628 || context.nesting == 0)
03629 CheckError(addEndPar(FALSE, outputFormat, &context, i0));
03630
03631 while (context.nesting > itemNesting)
03632 {
03633 setContext(context, context.nesting, context.listNum[context.nesting - 1]);
03634 context.nesting--;
03635 switch (context.listNum[context.nesting])
03636 {
03637 case kNMEListNumUL:
03638 if (!NMEAddString(outputFormat->endUL, -1, context.ctrlChar, &context))
03639 return kNMEErrNotEnoughMemory;
03640 HOOK(divHookFun, context.level, 0, FALSE, "*");
03641 break;
03642 case kNMEListNumDT:
03643 case kNMEListNumDD:
03644 if (!NMEAddString(outputFormat->endDL, -1, context.ctrlChar, &context))
03645 return kNMEErrNotEnoughMemory;
03646 HOOK(divHookFun, context.level, 0, FALSE, ";");
03647 break;
03648 case kNMEListIndented:
03649 if (!NMEAddString(outputFormat->endIndented, -1, context.ctrlChar, &context))
03650 return kNMEErrNotEnoughMemory;
03651 HOOK(divHookFun, context.level, 0, FALSE, ":");
03652 break;
03653 default:
03654 if (!NMEAddString(outputFormat->endOL, -1, context.ctrlChar, &context))
03655 return kNMEErrNotEnoughMemory;
03656 HOOK(divHookFun, context.level, 0, FALSE, "#");
03657 break;
03658 }
03659 if (outputFormat->sublistInListItem && context.nesting > 0)
03660 {
03661 setContext(context, context.nesting, context.listNum[context.nesting - 1]);
03662 switch (context.listNum[context.nesting - 1])
03663 {
03664 case kNMEListNumUL:
03665 if (!NMEAddString(outputFormat->endULItem, -1, context.ctrlChar, &context))
03666 return kNMEErrNotEnoughMemory;
03667 break;
03668 case kNMEListNumDT:
03669 case kNMEListNumDD:
03670 if (!NMEAddString(outputFormat->endDD, -1, context.ctrlChar, &context))
03671 return kNMEErrNotEnoughMemory;
03672 break;
03673 case kNMEListIndented:
03674
03675 break;
03676 default:
03677 if (!NMEAddString(outputFormat->endOLItem, -1, context.ctrlChar, &context))
03678 return kNMEErrNotEnoughMemory;
03679 break;
03680 }
03681 }
03682 }
03683 setContext(context, 0, 0);
03684
03685 for (firstIteration = TRUE;
03686 context.nesting < itemNesting;
03687 context.nesting++, firstIteration = FALSE)
03688 {
03689 context.listNum[context.nesting]
03690 = context.src[context.srcIndex - itemNesting + context.nesting] == '*'
03691 ? kNMEListNumUL
03692 : context.src[context.srcIndex - itemNesting + context.nesting] == ';'
03693 ? kNMEListNumDT
03694 : context.src[context.srcIndex - itemNesting + context.nesting] == ':'
03695 ? kNMEListIndented
03696 : 1;
03697 context.level = context.nesting + 1;
03698 HOOK(divHookFun, context.level, 0, TRUE,
03699 context.listNum[context.nesting] == kNMEListNumUL ? "*"
03700 : context.listNum[context.nesting] == kNMEListNumDT ? ";"
03701 : context.listNum[context.nesting] == kNMEListIndented ? ":"
03702 : "#");
03703 if (outputFormat->sublistInListItem && context.nesting > 0 && !firstIteration)
03704 {
03705 setContext(context, context.nesting, context.listNum[context.nesting - 1]);
03706 switch (context.listNum[context.nesting - 1])
03707 {
03708 case kNMEListNumUL:
03709 if (!NMEAddString(outputFormat->beginULItem, -1, context.ctrlChar, &context))
03710 return kNMEErrNotEnoughMemory;
03711 break;
03712 case kNMEListNumDT:
03713 context.listNum[context.nesting - 1] = kNMEListNumDD;
03714
03715 case kNMEListNumDD:
03716 if (!NMEAddString(outputFormat->beginDD, -1, context.ctrlChar, &context))
03717 return kNMEErrNotEnoughMemory;
03718 break;
03719 case kNMEListIndented:
03720
03721 break;
03722 default:
03723 if (!NMEAddString(outputFormat->beginOLItem, -1, context.ctrlChar, &context))
03724 return kNMEErrNotEnoughMemory;
03725 break;
03726 }
03727 context.level = context.nesting + 1;
03728 }
03729 if (outputFormat->sublistInListItem
03730 && context.listNum[context.nesting - 1] == kNMEListNumDT)
03731 {
03732
03733 context.level--;
03734 if (!NMEAddString(outputFormat->endDT, -1, context.ctrlChar, &context)
03735 || !NMEAddString(outputFormat->beginDD, -1, context.ctrlChar, &context))
03736 return kNMEErrNotEnoughMemory;
03737 context.level++;
03738 context.listNum[context.nesting - 1] = kNMEListNumDD;
03739 }
03740 if (!NMEAddString(context.listNum[context.nesting] == kNMEListNumUL
03741 ? outputFormat->beginUL
03742 : context.listNum[context.nesting] == kNMEListNumDT
03743 ? outputFormat->beginDL
03744 : context.listNum[context.nesting] == kNMEListIndented
03745 ? outputFormat->beginIndented
03746 : outputFormat->beginOL,
03747 -1,
03748 context.ctrlChar, &context))
03749 return kNMEErrNotEnoughMemory;
03750 }
03751 context.currentIndent = context.nesting * outputFormat->indentSpaces;
03752
03753 skipBlanks(context.src, context.srcLen, &context.srcIndex);
03754
03755 if (context.listNum[context.nesting - 1] == kNMEListNumDD)
03756 context.listNum[context.nesting - 1] = kNMEListNumDT;
03757
03758 setContext(context, context.nesting, context.listNum[context.nesting - 1]);
03759 HOOK(parHookFun, context.level, context.item, TRUE,
03760 context.listNum[context.nesting - 1] == kNMEListNumUL ? "*"
03761 : context.listNum[context.nesting - 1] == kNMEListNumDT ? ";"
03762 : context.listNum[context.nesting - 1] == kNMEListIndented ? ":"
03763 : "#");
03764 if (!NMEAddString(context.listNum[context.nesting - 1] == kNMEListNumUL
03765 ? outputFormat->beginULItem
03766 : context.listNum[context.nesting - 1] == kNMEListNumDT
03767 ? outputFormat->beginDT
03768 : context.listNum[context.nesting - 1] == kNMEListIndented
03769 ? outputFormat->beginIndentedPar
03770 : outputFormat->beginOLItem,
03771 -1,
03772 context.ctrlChar, &context))
03773 return kNMEErrNotEnoughMemory;
03774 setContext(context, 0, 0);
03775 state = kNMEStatePar;
03776 break;
03777 case kNMETokenTableCell:
03778 case kNMETokenTableHCell:
03779
03780 CheckError(flushStyleTags(styleStack, &styleNesting,
03781 i0,
03782 outputFormat, &context));
03783 if (context.nesting == 0
03784 || (context.listNum[context.nesting - 1] != kNMEListNumTableCell
03785 && context.listNum[context.nesting - 1] != kNMEListNumTableHCell))
03786 {
03787
03788 CheckError(addEndPar(TRUE, outputFormat, &context, i0));
03789
03790 if (context.nesting > 0)
03791 switch (context.listNum[context.nesting - 1])
03792 {
03793 case kNMEListNumUL:
03794 if (!NMEAddString(outputFormat->beginULItem, -1, context.ctrlChar, &context))
03795 return kNMEErrNotEnoughMemory;
03796 break;
03797 case kNMEListNumDT:
03798 case kNMEListNumDD:
03799 if (!NMEAddString(outputFormat->beginDD, -1, context.ctrlChar, &context))
03800 return kNMEErrNotEnoughMemory;
03801 break;
03802 case kNMEListIndented:
03803 if (!NMEAddString(outputFormat->beginIndentedPar, -1, context.ctrlChar, &context))
03804 return kNMEErrNotEnoughMemory;
03805 break;
03806 default:
03807 if (!NMEAddString(outputFormat->beginOLItem, -1, context.ctrlChar, &context))
03808 return kNMEErrNotEnoughMemory;
03809 break;
03810 }
03811 context.nesting++;
03812 context.level = context.nesting - 1;
03813 HOOK(divHookFun, kNMEHookLevelPar, 0, TRUE, "|");
03814 if (!NMEAddString(outputFormat->beginTable, -1,
03815 context.ctrlChar, &context))
03816 return kNMEErrNotEnoughMemory;
03817 }
03818 else
03819 CheckError(addEndPar(FALSE, outputFormat, &context, i0));
03820 context.currentIndent = context.nesting * outputFormat->indentSpaces;
03821
03822 context.listNum[context.nesting - 1] = token == kNMETokenTableCell
03823 ? kNMEListNumTableCell
03824 : kNMEListNumTableHCell;
03825
03826 context.level = context.nesting - 1;
03827 if (!NMEAddString(outputFormat->beginTableRow, -1,
03828 context.ctrlChar, &context))
03829 return kNMEErrNotEnoughMemory;
03830 HOOK(parHookFun, kNMEHookLevelPar, 0, TRUE,
03831 token == kNMETokenTableCell ? "|" : "|=");
03832 if (!NMEAddString(token == kNMETokenTableCell
03833 ? outputFormat->beginTableCell
03834 : outputFormat->beginTableHCell,
03835 -1,
03836 context.ctrlChar, &context))
03837 return kNMEErrNotEnoughMemory;
03838 CheckError(checkWordwrap(&context, outputFormat));
03839 context.level = 0;
03840 state = kNMEStatePar;
03841 break;
03842 case kNMETokenHR:
03843 CheckError(flushStyleTags(styleStack, &styleNesting,
03844 i0,
03845 outputFormat, &context));
03846 CheckError(addEndPar(TRUE, outputFormat, &context, i0));
03847 HOOK(parHookFun, kNMEHookLevelPar, 0, TRUE, "----");
03848 if (!NMEAddString(outputFormat->horRule, -1,
03849 context.ctrlChar, &context))
03850 return kNMEErrNotEnoughMemory;
03851 CheckError(checkWordwrap(&context, outputFormat));
03852 HOOK(parHookFun, kNMEHookLevelPar, 0, FALSE, "----");
03853 context.currentIndent = 0;
03854 state = kNMEStateBetweenPar;
03855 break;
03856 case kNMETokenStyle:
03857 case kNMETokenLinkEnd:
03858 case kNMETokenImageEnd:
03859 if (!NMEAddString(outputFormat->space, -1,
03860 context.ctrlChar, &context))
03861 return kNMEErrNotEnoughMemory;
03862 CheckError(checkWordwrap(&context, outputFormat));
03863 CheckError(processStyleTag(styleStack, &styleNesting,
03864 token == kNMETokenLinkEnd
03865 ? kNMEStyleLink
03866 : token == kNMETokenImageEnd
03867 ? kNMEStyleImage
03868 : newStyle,
03869 i0,
03870 outputFormat, &context));
03871 state = kNMEStatePar;
03872 break;
03873 case kNMETokenLinkBegin:
03874 case kNMETokenImageBegin:
03875 if (!NMEAddString(outputFormat->space, -1,
03876 context.ctrlChar, &context))
03877 return kNMEErrNotEnoughMemory;
03878 CheckError(addLinkBegin(token == kNMETokenImageBegin,
03879 styleStack, &styleNesting,
03880 i0, outputFormat, &context));
03881 state = kNMEStatePar;
03882 break;
03883 case kNMETokenPlugin:
03884 case kNMETokenPluginBlock:
03885 case kNMETokenPlaceholder:
03886 case kNMETokenPlaceholderBlock:
03887 {
03888 NMEInt pluginIndex;
03889
03890 pluginIndex = findPlugin(context.src, context.srcLen, context.srcIndex,
03891 token == kNMETokenPlaceholder
03892 || token == kNMETokenPlaceholderBlock,
03893 outputFormat);
03894 if (pluginIndex >= 0
03895 && outputFormat->plugins[pluginIndex].options
03896 & kNMEPluginOptBetweenPar)
03897 {
03898
03899 CheckError(flushStyleTags(styleStack, &styleNesting,
03900 i0,
03901 outputFormat, &context));
03902 CheckError(addEndPar(TRUE, outputFormat, &context, i0));
03903 state = kNMEStateBetweenPar;
03904 }
03905 else
03906 {
03907
03908 if (!NMEAddString(outputFormat->space, -1,
03909 context.ctrlChar, &context))
03910 return kNMEErrNotEnoughMemory;
03911 state = kNMEStatePar;
03912 }
03913 destLenTmp = context.destLen;
03914 CheckError(addPlugin(token == kNMETokenPluginBlock
03915 || token == kNMETokenPlaceholderBlock,
03916 token == kNMETokenPlaceholder
03917 || token == kNMETokenPlaceholderBlock,
03918 options, outputFormat, &context,
03919 &reparseOutput));
03920 if (reparseOutput)
03921 {
03922 CheckError(swapBuffers(&context.src, &context.srcLen,
03923 &context,
03924 &commonLen,
03925 destLenTmp));
03926
03927 }
03928 }
03929 break;
03930 }
03931 break;
03932 case kNMEStatePreAfterEol:
03933 if (token == kNMETokenPre)
03934 {
03935 if (!NMEAddString(outputFormat->endPre, -1,
03936 context.ctrlChar, &context))
03937 return kNMEErrNotEnoughMemory;
03938 HOOK(parHookFun, kNMEHookLevelPar, 0, FALSE, "{{{");
03939 state = kNMEStateBetweenPar;
03940 break;
03941 }
03942
03943 if (!NMEAddString(outputFormat->beginPreLine, -1,
03944 context.ctrlChar, &context))
03945 return kNMEErrNotEnoughMemory;
03946 state = kNMEStatePre;
03947
03948 if (token == kNMETokenSpace)
03949 {
03950
03951 NMEInt k;
03952
03953 for (k = context.srcIndex; k < context.srcLen && context.src[k] == ' '; k++)
03954 ;
03955 if (k + 3 <= context.srcLen && context.src[k] == '}'
03956 && context.src[k + 1] == '}' && context.src[k + 2] == '}')
03957 break;
03958 }
03959
03960 case kNMEStatePre:
03961 switch (token)
03962 {
03963 case kNMETokenChar:
03964 if (outputFormat->encodeCharPreFun)
03965 {
03966 context.srcIndex--;
03967 CheckError(outputFormat->encodeCharPreFun(context.src, context.srcLen, &context.srcIndex,
03968 &context,
03969 outputFormat->encodeCharPreData));
03970 }
03971 else
03972 {
03973 context.dest[context.destLen++] = context.src[context.srcIndex - 1];
03974 if (isFirstUTF8Byte(context.src[context.srcIndex - 1]))
03975 context.destLenUCS16++;
03976 context.col++;
03977 }
03978 break;
03979 case kNMETokenSpace:
03980 if (outputFormat->encodeCharPreFun)
03981 {
03982 NMEInt tmp = 0;
03983
03984 CheckError(outputFormat->encodeCharPreFun(" ", 1, &tmp,
03985 &context,
03986 outputFormat->encodeCharPreData));
03987 }
03988 else
03989 {
03990 context.dest[context.destLen++] = ' ';
03991 context.destLenUCS16++;
03992 context.col++;
03993 }
03994 break;
03995 case kNMETokenTab:
03996 do
03997 {
03998 if (outputFormat->encodeCharPreFun)
03999 {
04000 NMEInt tmp = 0;
04001
04002 CheckError(outputFormat->encodeCharPreFun(" ", 1, &tmp,
04003 &context,
04004 outputFormat->encodeCharPreData));
04005 }
04006 else
04007 {
04008 context.dest[context.destLen++] = ' ';
04009 context.destLenUCS16++;
04010 context.col++;
04011 }
04012 } while (context.col % kTabWidth != 0);
04013 break;
04014 case kNMETokenEOL:
04015 if (!NMEAddString(outputFormat->endPreLine, -1,
04016 context.ctrlChar, &context))
04017 return kNMEErrNotEnoughMemory;
04018 state = kNMEStatePreAfterEol;
04019 break;
04020 default:
04021
04022 return kNMEErrInternal;
04023 }
04024 break;
04025 case kNMEStateHeading:
04026 switch (token)
04027 {
04028 case kNMETokenChar:
04029 if (outputFormat->charHookFun)
04030 CheckError(outputFormat->charHookFun(i0 + context.srcIndexOffset,
04031 &context,
04032 outputFormat->charHookData));
04033 if (outputFormat->encodeCharFun)
04034 {
04035 context.srcIndex--;
04036 CheckError(outputFormat->encodeCharFun(context.src, context.srcLen, &context.srcIndex,
04037 &context,
04038 outputFormat->encodeCharData));
04039 }
04040 else
04041 {
04042 context.dest[context.destLen++] = context.src[context.srcIndex - 1];
04043 if (isFirstUTF8Byte(context.src[context.srcIndex - 1]))
04044 context.destLenUCS16++;
04045 context.col++;
04046 }
04047 CheckError(checkWordwrap(&context, outputFormat));
04048 break;
04049 case kNMETokenSpace:
04050 case kNMETokenTab:
04051 if (state == kNMEStatePar)
04052 skipBlanks(context.src, context.srcLen, &context.srcIndex);
04053
04054 if (context.srcIndex < context.srcLen && !isEol(context.src[context.srcIndex]))
04055 {
04056 if (!NMEAddString(outputFormat->space, -1,
04057 context.ctrlChar, &context))
04058 return kNMEErrNotEnoughMemory;
04059 CheckError(checkWordwrap(&context, outputFormat));
04060 }
04061 break;
04062 case kNMETokenHeading:
04063
04064 skipBlanks(context.src, context.srcLen, &context.srcIndex);
04065 case kNMETokenEOL:
04066 context.level = headingLevel;
04067 CheckError(flushStyleTags(styleStack, &styleNesting,
04068 i0,
04069 outputFormat, &context));
04070 if (!NMEAddString(outputFormat->endHeading, -1,
04071 context.ctrlChar, &context))
04072 return kNMEErrNotEnoughMemory;
04073 CheckError(checkWordwrap(&context, outputFormat));
04074 HOOK(parHookFun, context.level, 0, FALSE, "=");
04075 context.level = 0;
04076 state = kNMEStateBetweenPar;
04077 break;
04078 case kNMETokenLineBreak:
04079 if (!NMEAddString(outputFormat->lineBreak, -1,
04080 context.ctrlChar, &context))
04081 return kNMEErrNotEnoughMemory;
04082 CheckError(checkWordwrap(&context, outputFormat));
04083 break;
04084 case kNMETokenStyle:
04085 case kNMETokenLinkEnd:
04086 case kNMETokenImageEnd:
04087 CheckError(processStyleTag(styleStack, &styleNesting,
04088 token == kNMETokenLinkEnd
04089 ? kNMEStyleLink
04090 : token == kNMETokenImageEnd
04091 ? kNMEStyleImage : newStyle,
04092 i0,
04093 outputFormat, &context));
04094 break;
04095 case kNMETokenLinkBegin:
04096 case kNMETokenImageBegin:
04097 CheckError(addLinkBegin(token == kNMETokenImageBegin,
04098 styleStack, &styleNesting,
04099 i0, outputFormat, &context));
04100 break;
04101 case kNMETokenPlugin:
04102 case kNMETokenPluginBlock:
04103 case kNMETokenPlaceholder:
04104 case kNMETokenPlaceholderBlock:
04105 destLenTmp = context.destLen;
04106 CheckError(addPlugin(token == kNMETokenPluginBlock
04107 || token == kNMETokenPlaceholderBlock,
04108 token == kNMETokenPlaceholder
04109 || token == kNMETokenPlaceholderBlock,
04110 options, outputFormat, &context,
04111 &reparseOutput));
04112 if (reparseOutput)
04113 {
04114 CheckError(swapBuffers(&context.src, &context.srcLen,
04115 &context,
04116 &commonLen,
04117 destLenTmp));
04118
04119 }
04120 break;
04121 case kNMETokenLI:
04122 case kNMETokenDD:
04123 case kNMETokenTableCell:
04124 case kNMETokenTableHCell:
04125 case kNMETokenHR:
04126 case kNMETokenPre:
04127
04128 return kNMEErrInternal;
04129 }
04130 break;
04131 }
04132 }
04133
04134
04135 switch (state)
04136 {
04137 case kNMEStatePar:
04138 case kNMEStateParAfterEol:
04139 CheckError(flushStyleTags(styleStack, &styleNesting,
04140 context.srcIndex,
04141 outputFormat, &context));
04142 CheckError(addEndPar(TRUE, outputFormat, &context, context.srcIndex));
04143 break;
04144 case kNMEStatePre:
04145 if (!NMEAddString(outputFormat->endPreLine, -1,
04146 context.ctrlChar, &context)
04147 || !NMEAddString(outputFormat->endPre, -1,
04148 context.ctrlChar, &context))
04149 return kNMEErrNotEnoughMemory;
04150 HOOK(parHookFun, kNMEHookLevelPar, 0, FALSE, "{{{");
04151 break;
04152 case kNMEStatePreAfterEol:
04153 if (!NMEAddString(outputFormat->endPre, -1,
04154 context.ctrlChar, &context))
04155 return kNMEErrNotEnoughMemory;
04156 HOOK(parHookFun, kNMEHookLevelPar, 0, FALSE, "{{{");
04157 break;
04158 case kNMEStateHeading:
04159 context.level = headingLevel;
04160 CheckError(flushStyleTags(styleStack, &styleNesting,
04161 context.srcIndex,
04162 outputFormat, &context));
04163 if (!NMEAddString(outputFormat->endHeading, -1,
04164 context.ctrlChar, &context))
04165 return kNMEErrNotEnoughMemory;
04166 CheckError(checkWordwrap(&context, outputFormat));
04167 HOOK(parHookFun, context.level, 0, FALSE, "=");
04168 context.level = 0;
04169 break;
04170 default:
04171 break;
04172 }
04173
04174
04175 if (!(options & kNMEProcessOptNoPreAndPost)
04176 && !NMEAddString(outputFormat->endDoc, -1,
04177 context.ctrlChar, &context))
04178 return kNMEErrNotEnoughMemory;
04179 if (context.destLen + 1 >= context.bufSize)
04180 return kNMEErrNotEnoughMemory;
04181 context.dest[context.destLen] = '\0';
04182
04183
04184 *output = context.dest;
04185 *outputLen = context.destLen;
04186 if (outputUCS16Len)
04187 *outputUCS16Len = context.destLenUCS16;
04188 return kNMEErrOk;
04189 }
04190
04191 void NMEGetTempMemory(NMEContext const *context,
04192 NMEText *addr,
04193 NMEInt *len)
04194 {
04195 *addr = context->src + context->srcLen;
04196 *len = context->bufSize - context->srcLen;
04197 }
04198
04199 void NMEGetFormat(NMEContext const *context,
04200 NMEOutputFormat const **outputFormat,
04201 NMEInt *options,
04202 NMEInt *fontSize)
04203 {
04204 if (outputFormat)
04205 *outputFormat = context->outputFormat;
04206 if (options)
04207 *options = context->options;
04208 if (fontSize)
04209 *fontSize = context->fontSize;
04210 }
04211
04212 NMEInt NMECurrentInputIndex(NMEContext const *context)
04213 {
04214 return context->srcIndex;
04215 }
04216
04217 NMEInt NMECurrentOutputIndex(NMEContext const *context)
04218 {
04219 return context->destLen;
04220 }
04221
04222 NMEInt NMECurrentOutputIndexUCS16(NMEContext const *context)
04223 {
04224 return context->destLenUCS16;
04225 }
04226
04227 void NMECurrentLink(NMEContext const *context,
04228 NMEInt *linkOffset, NMEInt *linkLength)
04229 {
04230 *linkOffset = context->srcIndexOffset + context->linkOffset;
04231 *linkLength = context->linkLength;
04232 }
04233
04234 void NMECurrentOutput(NMEContext const *context,
04235 NMEConstText *output, NMEInt *outputLength)
04236 {
04237 if (output)
04238 *output = context->dest;
04239 if (outputLength)
04240 *outputLength = context->destLen;
04241 }
04242
04243 NMEConstText NMECurrentListNesting(NMEContext const *context)
04244 {
04245 NMEInt i;
04246 static NMEChar str[kMaxNesting + 1];
04247
04248 for (i = 0; i < context->nesting; i++)
04249 str[i] = context->listNum[i] == kNMEListNumUL ? '*'
04250 : context->listNum[i] == kNMEListNumDT ? ';'
04251 : context->listNum[i] == kNMEListNumDD ? ':'
04252 : context->listNum[i] == kNMEListIndented ? ':'
04253 : context->listNum[i] == kNMEListNumTableCell ? '|'
04254 : context->listNum[i] == kNMEListNumTableHCell ? '|'
04255 : '#';
04256 str[i] = '\0';
04257 return str;
04258 }