File indexing completed on 2024-12-22 04:17:58
0001 /*************************************************************************** 0002 labelparser.cpp 0003 ---------------- 0004 begin : Dec 14 2004 0005 Copyright (C) 2004, The University of Toronto 0006 email : netterfield@astro.utoronto.ca 0007 ***************************************************************************/ 0008 0009 /*************************************************************************** 0010 * * 0011 * This program is free software; you can redistribute it and/or modify * 0012 * it under the terms of the GNU General Public License as published by * 0013 * the Free Software Foundation; either version 2 of the License, or * 0014 * (at your option) any later version. * 0015 * * 0016 ***************************************************************************/ 0017 0018 #include "labelparser.h" 0019 0020 #include <assert.h> 0021 #include <stdlib.h> 0022 0023 #include <qregexp.h> 0024 #include <qstring.h> 0025 0026 using namespace Label; 0027 0028 // Debug output for Parsing - 0 Off 1 On 0029 #define DEBUG_PARSING 0 0030 0031 #if DEBUG_PARSING 0032 #define dumpattr(node, text) do { printf("%s: bold:%d italic:%d underline:%d\n", text, (node)->attributes.bold, (node)->attributes.italic, (node)->attributes.underline); } while(0) 0033 #else 0034 #define dumpattr(node, text) 0035 #endif 0036 0037 Chunk::Chunk(Chunk *parent, VOffset dir, bool isGroup, bool inherit) 0038 : next(0L), prev(0L), up(0L), down(0L), group(0L), scalar(false), linebreak(false), tab(false), vector(false), formated(false), vOffset(dir) { 0039 assert(parent || vOffset == None); 0040 if (parent) { // attach and inherit 0041 switch (vOffset) { 0042 case None: 0043 if (isGroup) { 0044 parent->group = this; 0045 } else { 0046 while (parent->next) { 0047 parent = parent->next; 0048 } 0049 parent->next = this; 0050 } 0051 break; 0052 case Up: 0053 assert(!parent->up); 0054 parent->up = this; 0055 break; 0056 case Down: 0057 assert(!parent->down); 0058 parent->down = this; 0059 break; 0060 } 0061 0062 if (inherit) { 0063 // inherit these properties from the parent 0064 attributes = parent->attributes; 0065 } 0066 0067 prev = parent; 0068 } 0069 } 0070 0071 0072 Chunk::~Chunk() { 0073 // These are set to 0 by the child if they're non-zero 0074 delete next; 0075 delete up; 0076 delete down; 0077 delete group; 0078 group = 0L; 0079 if (prev) { 0080 switch (vOffset) { 0081 case None: 0082 prev->next = 0L; 0083 // Note: kind of does the wrong thing if we're a group... no issue though 0084 break; 0085 case Up: 0086 prev->up = 0L; 0087 break; 0088 case Down: 0089 prev->down = 0L; 0090 break; 0091 } 0092 prev = 0L; 0093 } 0094 } 0095 0096 0097 bool Chunk::locked() const { 0098 return scalar || group || linebreak || tab || vector; 0099 } 0100 0101 0102 Parsed::Parsed() : chunk(0L) { 0103 } 0104 0105 0106 Parsed::~Parsed() { 0107 delete chunk; 0108 chunk = 0L; 0109 } 0110 0111 0112 inline void setNormalChar(QChar c, Chunk **tail) { 0113 if (*tail && !(*tail)->locked()) { 0114 (*tail)->text += c; 0115 } else { 0116 Chunk *f = new Chunk(*tail, Chunk::None, false, true); 0117 f->text += c; 0118 *tail = f; 0119 } 0120 } 0121 0122 0123 inline QColor parseColor(const QString& txt, int *skip) { 0124 const int end = txt.indexOf('}'); 0125 if (skip) { 0126 *skip = end; 0127 } 0128 0129 if (end == -1) { 0130 return QColor(); 0131 } 0132 0133 const QString endPart = txt.left(end); 0134 0135 QColor color(endPart); // This one is slow. If we support our own formats 0136 // outside of QColor, make sure that this is called 0137 // -after- we try our own formats. Every cycle 0138 // counts in here. 0139 #if 0 0140 // This is rr,gg,bb support. I'm not sure about supporting H,S,V or even 0141 // about compatibility with LaTeX so for now we don't support it. If it's 0142 // ever re-enabled, make sure that testcases are added. 0143 if (!color.isValid()) { 0144 // the color is in the format "r,g,b" 0145 QStringList components = QStringList::split(',', endPart, true); 0146 if (components.count() == 3) { 0147 int colors[3] = { 0, 0, 0 }; 0148 int base = 10; 0149 0150 // assume the colors are given as decimal numbers unless we have a hex value in the string 0151 if (endPart.find(QRegExp("[A-F]", false)) != -1) { 0152 base = 16; 0153 } 0154 0155 bool ok = true; 0156 colors[0] = components[0].toInt(&ok, base); 0157 if (ok) { 0158 colors[1] = components[1].toInt(&ok, base); 0159 } 0160 if (ok) { 0161 colors[2] = components[2].toInt(&ok, base); 0162 } 0163 0164 if (ok) { 0165 color.setRgb(colors[0], colors[1], colors[2]); 0166 } // Should error out? 0167 } 0168 } 0169 #endif 0170 return color; 0171 } 0172 0173 0174 static Chunk *parseInternal(Chunk *ctail, const QString& txt, uint& start, uint cnt, bool interpretNewLine); 0175 0176 #define EXPAND_GREEK(L_U, L_L, REST, SKIP, UCODE) \ 0177 case L_L: \ 0178 x=0x20; \ 0179 case L_U: \ 0180 if (txt.mid(from + 1).startsWith(REST)) { \ 0181 *skip = SKIP; \ 0182 setNormalChar(QChar(UCODE+x), tail); \ 0183 return true; \ 0184 } \ 0185 break; 0186 0187 0188 inline bool parseOutChar(const QString& txt, uint from, int *skip, Chunk **tail, bool interpretNewLine) { 0189 // STOP! Changes you make here should be made into cclineedit.cpp as well for completion. 0190 QChar c = txt[from]; 0191 bool upper = false; 0192 *skip = 1; 0193 short x = 0; 0194 0195 #if DEBUG_PARSING 0196 qDebug() << "----- parsing " << txt; 0197 #endif 0198 0199 switch (c.unicode()) { 0200 EXPAND_GREEK('B', 'b', "eta", 4, 0x392) 0201 EXPAND_GREEK('D', 'd', "elta", 5, 0x394) 0202 EXPAND_GREEK('Z', 'z', "eta", 4, 0x396) 0203 EXPAND_GREEK('K', 'k', "appa", 5, 0x39a) 0204 EXPAND_GREEK('M', 'm', "u", 2, 0x39c) 0205 EXPAND_GREEK('X', 'x', "i", 2, 0x39e) 0206 EXPAND_GREEK('R', 'r', "ho", 3, 0x3a1) 0207 0208 case 'a': 0209 x = 0x20; 0210 case 'A': 0211 if (txt.mid(from + 1).startsWith(QLatin1String("lpha"))) { 0212 *skip = 5; 0213 setNormalChar(QChar(0x391+x), tail); 0214 return true; 0215 } else if (txt.mid(from + 1).startsWith(QLatin1String("pprox"))) { 0216 *skip = 6; 0217 setNormalChar(QChar(0x2248), tail); 0218 return true; 0219 } 0220 break; 0221 0222 0223 case 'c': 0224 x = 0x20; 0225 case 'C': 0226 if (txt.mid(from + 1).startsWith(QLatin1String("hi"))) { 0227 *skip = 3; 0228 setNormalChar(QChar(0x3a7+x), tail); 0229 return true; 0230 } else if (txt.mid(from + 1).startsWith(QLatin1String("dot"))) { 0231 *skip = 4; 0232 setNormalChar(QChar(0x2219), tail); 0233 return true; 0234 } 0235 break; 0236 0237 case 'e': 0238 x = 0x20; 0239 case 'E': 0240 if (txt.mid(from + 1).startsWith(QLatin1String("psilon"))) { 0241 *skip = 7; 0242 setNormalChar(QChar(0x395+x), tail); 0243 return true; 0244 } else if (txt.mid(from + 1).startsWith(QLatin1String("ta"))) { 0245 *skip = 3; 0246 setNormalChar(QChar(0x397+x), tail); 0247 return true; 0248 } else if (txt.mid(from + 1).startsWith(QLatin1String("ll"))) { 0249 *skip = 3; 0250 setNormalChar(QChar(0x2113), tail); 0251 return true; 0252 } 0253 break; 0254 0255 case 'g': 0256 x = 0x20; 0257 case 'G': 0258 if (txt.mid(from + 1).startsWith(QLatin1String("amma"))) { 0259 *skip = 5; 0260 setNormalChar(QChar(0x393+x), tail); 0261 return true; 0262 } else if (txt.mid(from + 1).startsWith(QLatin1String("eq"))) { 0263 *skip = 3; 0264 setNormalChar(QChar(0x2265), tail); 0265 return true; 0266 } else if (txt.mid(from + 1).startsWith('e')) { 0267 *skip = 2; 0268 setNormalChar(QChar(0x2265), tail); 0269 return true; 0270 } 0271 break; 0272 0273 case 'i': 0274 x = 0x20; 0275 case 'I': 0276 if (txt.mid(from + 1).startsWith(QLatin1String("ota"))) { 0277 *skip = 4; 0278 setNormalChar(QChar(0x399+x), tail); 0279 return true; 0280 } else if (!upper && txt.mid(from + 1).startsWith(QLatin1String("nf"))) { 0281 *skip = 3; 0282 setNormalChar(QChar(0x221E), tail); 0283 return true; 0284 } else if (!upper && txt.mid(from + 1).startsWith(QLatin1String("nt"))) { 0285 *skip = 3; 0286 setNormalChar(QChar(0x222B), tail); 0287 return true; 0288 } 0289 break; 0290 0291 case 'l': 0292 x = 0x20; 0293 case 'L': 0294 if (txt.mid(from + 1).startsWith(QLatin1String("ambda"))) { 0295 *skip = 6; 0296 setNormalChar(QChar(0x39b+x), tail); 0297 return true; 0298 } else if (txt.mid(from + 1).startsWith(QLatin1String("eq"))) { 0299 *skip = 3; 0300 setNormalChar(QChar(0x2264), tail); 0301 return true; 0302 } else if (txt.mid(from + 1).startsWith('e')) { 0303 *skip = 2; 0304 setNormalChar(QChar(0x2264), tail); 0305 return true; 0306 } 0307 break; 0308 0309 case 'n': 0310 x = 0x20; 0311 case 'N': 0312 if (txt.mid(from + 1).startsWith('u')) { 0313 *skip = 2; 0314 setNormalChar(QChar(0x39D+x), tail); 0315 return true; 0316 } else if (txt.mid(from + 1).startsWith('e')) { 0317 *skip = 2; 0318 setNormalChar(QChar(0x2260), tail); 0319 return true; 0320 } else if (interpretNewLine) { 0321 *skip = 1; 0322 if (!*tail || !(*tail)->text.isEmpty() || (*tail)->locked()) { 0323 *tail = new Chunk(*tail, Chunk::None, false, true); 0324 } 0325 (*tail)->linebreak = true; 0326 *tail = new Chunk(*tail, Chunk::None, false, true); 0327 return true; 0328 } else { 0329 *skip = 1; 0330 setNormalChar(QChar(0x20), tail); 0331 return true; 0332 } 0333 break; 0334 0335 case 'o': 0336 x = 0x20; 0337 case 'O': 0338 if (txt.mid(from + 1).startsWith(QLatin1String("verline{"))) { 0339 if ((*tail)->group) { 0340 *tail = new Chunk(*tail, Chunk::None, false, true); 0341 } 0342 Chunk *working = new Chunk(*tail, Chunk::None, true, true); 0343 dumpattr(working, "start group for overline"); 0344 uint parseStart = from + 9; 0345 working->attributes.overline = true; 0346 parseInternal(working, txt, parseStart, txt.length(), interpretNewLine); 0347 *skip = parseStart - from + 1; 0348 dumpattr(working, "end group for overline"); 0349 return true; 0350 } else if (txt.mid(from + 1).startsWith(QLatin1String("micron"))) { 0351 *skip = 7; 0352 setNormalChar(QChar(0x39F+x), tail); 0353 return true; 0354 } else if (txt.mid(from + 1).startsWith(QLatin1String("mega"))) { 0355 *skip = 5; 0356 setNormalChar(QChar(0x3A9+x), tail); 0357 return true; 0358 } else if (txt.mid(from + 1).startsWith(QLatin1String("dot"))) { 0359 *skip = 4; 0360 setNormalChar(QChar(0x2299), tail); 0361 return true; 0362 } 0363 break; 0364 0365 case 'p': 0366 x = 0x20; 0367 case 'P': 0368 if (txt.mid(from + 1).startsWith('i')) { 0369 *skip = 2; 0370 setNormalChar(QChar(0x3a0+x), tail); 0371 return true; 0372 } else if (txt.mid(from + 1).startsWith(QLatin1String("hi"))) { 0373 *skip = 3; 0374 setNormalChar(QChar(0x3A6+x), tail); 0375 return true; 0376 } else if (txt.mid(from + 1).startsWith(QLatin1String("si"))) { 0377 *skip = 3; 0378 setNormalChar(QChar(0x3A8+x), tail); 0379 return true; 0380 } else if (txt.mid(from + 1).startsWith(QLatin1String("artial"))) { 0381 *skip = 7; 0382 setNormalChar(QChar(0x2202), tail); 0383 return true; 0384 } else if (txt.mid(from + 1).startsWith(QLatin1String("rod"))) { 0385 *skip = 4; 0386 setNormalChar(QChar(0x220F), tail); 0387 return true; 0388 } else if (txt.mid(from + 1).startsWith('m')) { 0389 *skip = 2; 0390 setNormalChar(QChar(0xb1), tail); 0391 return true; 0392 } 0393 break; 0394 0395 case 't': 0396 x = 0x20; 0397 case 'T': 0398 if (txt.mid(from + 1).startsWith(QLatin1String("extcolor{"))) { // \textcolor{color}{text} 0399 if ((*tail)->group) { 0400 *tail = new Chunk(*tail, Chunk::None, false, true); 0401 } 0402 Chunk *working = new Chunk(*tail, Chunk::None, true, true); 0403 dumpattr(working, "start group for textcolor"); 0404 uint parseStart = from + 10; 0405 int firstSkip = 0; 0406 working->attributes.color = parseColor(txt.mid(parseStart), &firstSkip); 0407 if (!working->attributes.color.isValid() || txt[parseStart + firstSkip + 1] != '{') { 0408 return false; 0409 } 0410 parseStart += firstSkip + 2; 0411 parseInternal(working, txt, parseStart, txt.length(), interpretNewLine); 0412 *skip = parseStart - from + 1; 0413 dumpattr(working, "end group for textcolor"); 0414 return true; 0415 } else if (txt.mid(from + 1).startsWith(QLatin1String("extbf{"))) { 0416 if ((*tail)->group) { 0417 *tail = new Chunk(*tail, Chunk::None, false, true); 0418 } 0419 Chunk *working = new Chunk(*tail, Chunk::None, true, true); 0420 dumpattr(working, "start group for textbf"); 0421 uint parseStart = from + 7; 0422 working->attributes.bold = true; 0423 parseInternal(working, txt, parseStart, txt.length(), interpretNewLine); 0424 *skip = parseStart - from + 1; 0425 dumpattr(working, "end group for textbf"); 0426 return true; 0427 } else if (txt.mid(from + 1).startsWith(QLatin1String("extit{"))) { 0428 if ((*tail)->group) { 0429 *tail = new Chunk(*tail, Chunk::None, false, true); 0430 } 0431 Chunk *working = new Chunk(*tail, Chunk::None, true, true); 0432 dumpattr(working, "start group for textit"); 0433 uint parseStart = from + 7; 0434 working->attributes.italic = true; 0435 parseInternal(working, txt, parseStart, txt.length(), interpretNewLine); 0436 *skip = parseStart - from + 1; 0437 dumpattr(working, "end group for textit"); 0438 return true; 0439 } else if (txt.mid(from + 1).startsWith(QLatin1String("heta"))) { 0440 *skip = 5; 0441 setNormalChar(QChar(0x398+x), tail); 0442 return true; 0443 } else if (txt.mid(from + 1).startsWith(QLatin1String("au"))) { 0444 *skip = 3; 0445 setNormalChar(QChar(0x3A4+x), tail); 0446 return true; 0447 } else { 0448 *skip = 1; 0449 if (!*tail || !(*tail)->text.isEmpty() || (*tail)->locked()) { 0450 *tail = new Chunk(*tail, Chunk::None, false, true); 0451 } 0452 (*tail)->tab = true; 0453 *tail = new Chunk(*tail, Chunk::None, false, true); 0454 return true; 0455 } 0456 break; 0457 0458 case 's': 0459 x = 0x20; 0460 case 'S': 0461 if (txt.mid(from + 1).startsWith(QLatin1String("igma"))) { 0462 *skip = 5; 0463 setNormalChar(QChar(0x3A3+x), tail); 0464 return true; 0465 } else if (!upper && txt.mid(from + 1).startsWith(QLatin1String("um"))) { 0466 *skip = 3; 0467 setNormalChar(QChar(0x2211), tail); 0468 return true; 0469 } else if (!upper && txt.mid(from + 1).startsWith(QLatin1String("qrt"))) { 0470 *skip = 4; 0471 setNormalChar(QChar(0x221A), tail); 0472 return true; 0473 } 0474 break; 0475 0476 case 'u': 0477 x = 0x20; 0478 case 'U': 0479 if (txt.mid(from + 1).startsWith(QLatin1String("nderline{"))) { 0480 if ((*tail)->group) { 0481 *tail = new Chunk(*tail, Chunk::None, false, true); 0482 } 0483 Chunk *working = new Chunk(*tail, Chunk::None, true, true); 0484 dumpattr(working, "start group for underline"); 0485 uint parseStart = from + 10; 0486 working->attributes.underline = true; 0487 parseInternal(working, txt, parseStart, txt.length(), interpretNewLine); 0488 *skip = parseStart - from + 1; 0489 dumpattr(working, "end group for underline"); 0490 return true; 0491 } else if (txt.mid(from + 1).startsWith(QLatin1String("psilon"))) { 0492 *skip = 7; 0493 setNormalChar(QChar(0x3A5+x), tail); 0494 return true; 0495 } 0496 break; 0497 0498 default: 0499 break; 0500 } 0501 0502 return false; 0503 } 0504 0505 0506 static Chunk *parseInternal(Chunk *ctail, const QString& txt, uint& start, uint cnt, bool interpretNewLine) { 0507 Chunk *chead = ctail; 0508 0509 if (ctail->group) { 0510 ctail = new Chunk(ctail, Chunk::None, false, true); 0511 } 0512 for (uint& i = start; i < cnt; ++i) { 0513 QChar c = txt[i]; 0514 Chunk::VOffset dir = Chunk::Down; 0515 switch (c.unicode()) { 0516 case '\n': 0517 if (ctail->vOffset != Chunk::None && (!ctail->text.isEmpty() || ctail->locked())) { 0518 while (ctail->vOffset != Chunk::None && (!ctail->text.isEmpty() || ctail->locked())) { 0519 ctail = ctail->prev; 0520 } 0521 ctail = new Chunk(ctail, Chunk::None, false, true); 0522 } 0523 if (!ctail->text.isEmpty() || ctail->locked()) { 0524 if (ctail->vOffset != Chunk::None) { 0525 ctail = new Chunk(ctail->prev, Chunk::None, false, true); 0526 } else { 0527 ctail = new Chunk(ctail, Chunk::None, false, true); 0528 } 0529 } 0530 ctail->linebreak = true; 0531 ctail = new Chunk(ctail, Chunk::None, false, true); 0532 break; 0533 case '\t': 0534 if (!ctail->text.isEmpty() || ctail->locked()) { 0535 if (ctail->vOffset != Chunk::None) { 0536 ctail = new Chunk(ctail->prev, Chunk::None, false, true); 0537 } else { 0538 ctail = new Chunk(ctail, Chunk::None, false, true); 0539 } 0540 } 0541 ctail->tab = true; 0542 ctail = new Chunk(ctail, Chunk::None, false, true); 0543 break; 0544 case 0x5c: // \ /**/ 0545 0546 if (ctail->vOffset != Chunk::None && (!ctail->text.isEmpty() || ctail->locked())) { 0547 while (ctail->vOffset != Chunk::None && (!ctail->text.isEmpty() || ctail->locked())) { 0548 ctail = ctail->prev; 0549 } 0550 ctail = new Chunk(ctail, Chunk::None, false, true); 0551 } 0552 0553 0554 if (ctail->vOffset != Chunk::None && !ctail->text.isEmpty()) { 0555 ctail = new Chunk(ctail->prev, Chunk::None, false, true); 0556 } 0557 ++i; 0558 if (i == cnt) { 0559 setNormalChar('\\', &ctail); 0560 } else { 0561 int skip = 0; 0562 if (!parseOutChar(txt, i, &skip, &ctail, interpretNewLine)) { 0563 setNormalChar(txt[i], &ctail); 0564 } else { 0565 i += skip - 1; 0566 } 0567 } 0568 break; 0569 case 0x5e: // ^ 0570 dir = Chunk::Up; 0571 case 0x5f: // _ (dir is set to Down at beginning of loop) 0572 if (ctail->text.isEmpty() && !ctail->group) { 0573 setNormalChar(c, &ctail); 0574 } else { 0575 if (ctail->vOffset != Chunk::None) { 0576 if (ctail->vOffset != dir) { 0577 ctail = new Chunk(ctail->prev, dir, false, true); 0578 } else if (ctail->group) { 0579 ctail = new Chunk(ctail, dir, false, true); 0580 } else { 0581 ctail = new Chunk(ctail, dir, false, true); 0582 } 0583 } else { 0584 ctail = new Chunk(ctail, dir, false, true); 0585 } 0586 } 0587 break; 0588 case 0x7b: // { 0589 if (ctail->text.isEmpty() && !ctail->group) { 0590 bool rc = false; 0591 new Chunk(ctail, Chunk::None, true, true); 0592 dumpattr(ctail->group, "start group with non-group and empty text"); 0593 rc = 0L != parseInternal(ctail->group, txt, ++i, cnt, interpretNewLine); 0594 assert(rc); 0595 dumpattr(ctail->group, "after start group with non-group and empty text"); 0596 if (!rc) { 0597 return 0L; 0598 } 0599 } else { 0600 bool rc = false; 0601 if (ctail->vOffset == Chunk::None) { 0602 rc = 0L != parseInternal(new Chunk(ctail, Chunk::None, true, true), txt, ++i, cnt, interpretNewLine); 0603 } else { 0604 rc = 0L != parseInternal(new Chunk(ctail->prev, Chunk::None, true, true), txt, ++i, cnt, interpretNewLine); 0605 } 0606 if (!rc) { 0607 return 0L; 0608 } 0609 } 0610 break; 0611 case 0x7d: // } 0612 if (chead->prev && chead->prev->group == chead) { 0613 return chead; 0614 } else { 0615 setNormalChar(c, &ctail); 0616 } 0617 break; 0618 case '[': 0619 { 0620 bool vector = false; 0621 int vectorIndexStart = -1; 0622 int vectorIndexEnd = -1; 0623 int bracketStack = 1; 0624 int pos = -1; 0625 bool format = false; 0626 int formatIndexStart = 0; 0627 int formatIndexEnd = 0; 0628 0629 bool equation = txt[i + 1] == '='; 0630 for (uint searchPt = i + 1; bracketStack != 0 && searchPt < cnt; ++searchPt) { 0631 if (txt[searchPt] == ']') { 0632 if (--bracketStack == 0) { 0633 pos = searchPt; 0634 break; 0635 } else if (bracketStack == 1 && vector && vectorIndexEnd == -1) { 0636 vectorIndexEnd = searchPt - 1; 0637 } 0638 } else if (txt[searchPt] == '[') { 0639 ++bracketStack; 0640 if (!vector && !equation) { 0641 vector = true; 0642 vectorIndexStart = searchPt + 1; 0643 } 0644 } 0645 } 0646 0647 if (pos < 0 || pos == int(i) + 1 /* empty [] */) { 0648 return 0L; 0649 } 0650 0651 if (pos+3 < (int)cnt) { // ]{%f} is min size. 0652 if ((txt[pos+1]=='{') && ((txt[pos+2] == '%') || (txt[pos+2] == 'T'))) { 0653 formatIndexStart = pos+1; 0654 for (uint searchPt = pos + 2; searchPt < cnt; ++searchPt) { 0655 if (txt[searchPt] == '}') { 0656 formatIndexEnd = searchPt; 0657 format = true; 0658 break; 0659 } 0660 } 0661 } 0662 } 0663 0664 if (ctail->locked() || !ctail->text.isEmpty()) { 0665 if (ctail->vOffset != Chunk::None) { 0666 ctail = new Chunk(ctail->prev, Chunk::None, false, true); 0667 } else { 0668 ctail = new Chunk(ctail, Chunk::None, false, true); 0669 } 0670 } 0671 0672 if (vector) { 0673 ctail->text = txt.mid(i + 1, vectorIndexStart - i - 2).trimmed(); 0674 ctail->expression = txt.mid(vectorIndexStart, vectorIndexEnd - vectorIndexStart + 1); 0675 ctail->vector = true; 0676 } else { 0677 ctail->text = txt.mid(i + 1, pos - i - 1).trimmed(); 0678 ctail->scalar = true; 0679 } 0680 if (format) { 0681 i = uint(formatIndexEnd); 0682 ctail->formated = true; 0683 ctail->format = txt.mid(formatIndexStart+1, formatIndexEnd - formatIndexStart-1); 0684 0685 } else { 0686 i = uint(pos); 0687 } 0688 } 0689 break; 0690 default: 0691 #if 0 0692 if (ctail->vOffset != Chunk::None && (!ctail->text.isEmpty() || ctail->locked())) { 0693 ctail = new Chunk(ctail->prev, Chunk::None, false, true); 0694 } 0695 #endif 0696 if (ctail->vOffset != Chunk::None && (!ctail->text.isEmpty() || ctail->locked())) { 0697 while (ctail->vOffset != Chunk::None && (!ctail->text.isEmpty() || ctail->locked())) { 0698 ctail = ctail->prev; 0699 } 0700 ctail = new Chunk(ctail, Chunk::None, false, true); 0701 } 0702 setNormalChar(c, &ctail); 0703 break; 0704 } 0705 } 0706 0707 return chead; 0708 } 0709 0710 Parsed *Label::parse(const QString& txt, const QColor &color, bool interpret, bool interpretNewLine) { 0711 Parsed *parsed = new Parsed; 0712 Chunk *ctail = parsed->chunk = new Chunk(0L); 0713 ctail->attributes.color = color; 0714 if (!interpret) { 0715 ctail->text = txt; 0716 return parsed; 0717 } 0718 0719 uint start = 0; 0720 uint cnt = txt.length(); 0721 Chunk *rc = parseInternal(ctail, txt, start, cnt, interpretNewLine); 0722 if (!rc) { 0723 // Parse error - how to recover? 0724 delete parsed; 0725 parsed = 0L; 0726 } 0727 return parsed; 0728 } 0729 0730 0731 // vim: ts=2 sw=2 et