1 /* webcpp - engine.cpp
2 * Copyright (C)2001-2003 Jeffrey Bakker
3
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 ___________________________________ .. .
18 */
19
20 //--build=i386-linux --host=i386-linux --target=i386-linux
21
22 #define CHILD( x , y ) Child=new ( x );\
23 Child->setLangExt( y )
24
25 // uncomment to debug
26 //#include "defdebug.h"
27
28 #include "deflangs.h"
29 #include "defparse.h"
30 #include "defsys.h"
31 #include "engine.h"
32 #include <cstdlib>
33 #include <cctype>
34 using namespace std;
35
36
37 // initialize data members ----------------------------------------------------
init_switches()38 void Engine::init_switches() {
39
40 childLang = false;
41
42 // command line options
43 opt_bigtab = false;
44 opt_webcpp = false;
45 opt_hypinc = false;
46 opt_follow = false;
47 opt_number = false;
48 opt_extcss = false;
49 opt_anchor = false;
50 opt_htsnip = false;
51
52 // abort switches
53 inHtmTags = false;
54 inDblQuotes = false;
55 inSinQuotes = false;
56 inBckQuotes = false;
57 inComment = false;
58 endComment = false;
59
60 // common language
61 doStrings = true;
62 doNumbers = true;
63 doKeywords = true;
64 doCaseKeys = true;
65 doSymbols = false;
66 doLabels = false;
67 doPreProc = false;
68 doScalars = false;
69 doArrays = false;
70 doHashes = false;
71 doHtmlTags = false;
72 doHtmComnt = false;
73 doHskComnt = false;
74 doPasComnt = false;
75 doBigComnt = false;
76 doCinComnt = false;
77 doUnxComnt = false;
78 doAsmComnt = false;
79 doRemComnt = false;
80 doAdaComnt = false;
81 doFtnComnt = false;
82 doTclComnt = false;
83 doAspComnt = false;
84 doBatComnt = false;
85
86 lncount = 1;
87 tabwidth = 8;
88 tw = "8";
89 }
90 // set the width of the tabs --------------------------------------------------
setTabWidth(string width)91 void Engine::setTabWidth(string width) {
92
93 tabwidth = atoi(width.data());
94 if(tabwidth == 0) {
95 tabwidth = 8;
96 tw = "8";
97 }
98 tw = width;
99 }
100 // format the plain text for proper display in HTML ---------------------------
pre_parse()101 void Engine::pre_parse() {
102
103 // the virtual Nth character factoring in for escapes
104 int i_esc = 0;
105
106 for (int i=0; i < (int)buffer.size(); i++) {
107
108 // escape from HTML escapes
109 if (buffer[i] == '&') {buffer.replace(i,1,"&");i_esc+=4;}
110 else
111 if (buffer[i] == '<') {buffer.replace(i,1, "<");i_esc+=3;}
112 else
113 if (buffer[i] == '>') {buffer.replace(i,1, ">");i_esc+=3;}
114 // escape from accidental HTML tags
115
116 if (opt_bigtab)
117 // convert tabs into spaces
118 if (buffer[i] == '\t') {
119
120 int j;
121 buffer.erase(i,1);
122
123 // factor in the number of escapes
124 if((i-i_esc) % tabwidth == 0) {
125
126 for(j=0; j < tabwidth; j++) {
127
128 buffer.insert(i," ");
129 }
130 i+=tabwidth-1;
131 }else{
132 int spaces = tabwidth - ((i-i_esc) % tabwidth);
133
134 for(j=0; j < spaces; j++) {
135
136 buffer.insert(i," ");
137 }
138 i+=spaces-1;
139 }
140 }
141 // for browsers that don't display tabs properly
142 }
143 }
144 // erases tags (use for inside of inline comments) ----------------------------
eraseTags(int start,int fin)145 void Engine::eraseTags(int start, int fin) {
146
147 if(fin == 0) {fin = buffer.size();}
148 if(fin == -1) {fin = buffer.size();}
149
150 int erase1, erase2;
151 int offset1, offset2;
152 string srchstr;
153
154 srchstr = "<font CLASS=";
155 offset1 = 20;
156 offset2 = 7;
157
158 // erase all the colours previously made
159 while(buffer.find(srchstr,start) != -1 &&
160 buffer.find(srchstr,start) < fin) {
161
162 //erasing opening font tags
163 erase1 = buffer.find(srchstr,start);
164 if(erase1 != -1 && erase1 < fin) {
165 buffer.erase(erase1,offset1);
166 }
167 //erasing closing font tags
168 erase2 = buffer.find("</font>",start);
169 if(erase2 != -1 && erase2 < fin) {
170 buffer.erase(erase2,offset2);
171 }
172 }
173 inDblQuotes = false;
174 inSinQuotes = false;
175 inBckQuotes = false;
176 }
177 // anchors the line (for hyperlinking capabilities) ---------------------------
makeAnchor()178 void Engine::makeAnchor() {
179
180 *IO << "<a name=\"line" << lncount << "\"/>";
181 }
182 // prints the line number in the margin ---------------------------------------
makeMargin()183 void Engine::makeMargin() {
184
185 string space = "";
186
187 // setting margin alignment
188 if(lncount < 100000) {space += " ";}
189 if(lncount < 10000) {space += " ";}
190 if(lncount < 1000) {space += " ";}
191 if(lncount < 100) {space += " ";}
192 if(lncount < 10) {space += " ";}
193
194 *IO << space << "<font CLASS=comment>"
195 << lncount << ":</font> ";
196 }
197 //-----------------------------------------------------------------------------
198 // check if parsing needs to be aborted ---------------------------------------
abortParse()199 bool Engine::abortParse() {
200
201 // if(doHtmlTags && inHtmTags)
202 // {return true;}
203
204 if(endComment) {return true;}
205 if(inDblQuotes) {return true;}
206 if(!doAspComnt) {
207 if(inSinQuotes) {return true;}
208 }
209 if(inBckQuotes) {return true;}
210 if(inComment) {return true;}
211
212 return false;
213 }
214 // check if colouring needs to be aborted -------------------------------------
abortColour(int index)215 bool Engine::abortColour(int index) {
216
217 if(doHtmComnt
218 && ( isInsideIt(index,"<",">")
219 && isInsideIt(index,">","<") )) {return true;}
220 if(isInsideIt(index,"/*","*/")) {return true;}
221 if(isInsideIt(index,"(*","*)")) {return true;}
222 if(isInsideIt(index,"<!",">")) {return true;}
223 if(isInsideIt(index,"\"","\"")) {return true;}
224 if(!doAspComnt) {
225 if(isInsideIt(index,"'","'")) {return true;}
226 }
227 if(isInsideIt(index,"`","`")) {return true;}
228
229 return false;
230 }
231 // check if the index is inside the specified boundaries ----------------------
isInsideIt(int index,string start,string end)232 bool Engine::isInsideIt(int index, string start, string end) {
233
234 // count the number of starts and ends
235 // and return true for an odd number
236
237 if(buffer.find(start,0) == -1) {return false;}
238
239 int l = 0;
240 int r = 0;
241 int idx;
242
243 idx = buffer.find(end,index);
244 while(idx < buffer.size()) { // idx < string::npos && idx != -1
245 if(idx != -1 && buffer[idx-1] != '\\'){r++;}
246 idx = buffer.find(end,idx+1);
247 }
248
249 idx = buffer.rfind(start,index);
250 while(idx > 0) {
251 if(idx != -1 && buffer[idx-1] != '\\'){l++;}
252 idx = buffer.rfind(start,idx-1);
253 }
254
255 if(r % 2 == 1 && l % 2 == 1) {return true;}
256
257 return false;
258 }
259 // for HTML highlighting ------------------------------------------------------
isInsideTag(int index)260 bool Engine::isInsideTag(int index) {
261
262 return false;
263 }
264 // number accuracy ------------------------------------------------------------
isNotWord(int index)265 bool Engine::isNotWord(int index) {
266
267 if(isalpha(buffer[index+1])) {return false;}
268
269 while(index > 0) {
270
271 if(isalpha(buffer[index])) {return false;}
272 if(buffer[index] == '_') {return false;}
273 if(buffer[index] == '#') {return false;}
274
275 if(ispunct(buffer[index]) ||
276 isspace(buffer[index])) {return true;}
277 index--;
278 }
279 return true;
280 }
281 // parse for preprocessor directives ------------------------------------------
parsePreProc()282 void Engine::parsePreProc() {
283
284 if(abortParse()) {return;}
285 if(buffer[0] != '#') {return;}
286
287 if(opt_hypinc) {
288 hyperIncludeMe();
289 }
290
291 buffer += " ";
292 buffer.insert(0, "<font CLASS=preproc>");
293
294 int end;
295 for(int i=8;i<buffer.size();i++) {
296 if(isspace(buffer[i])) {end = i;i=buffer.size();}
297 }
298 buffer.insert(end, "</font>");
299 }
300 // define symbol characters ---------------------------------------------------
isSymbol(char c)301 bool Engine::isSymbol(char c) {
302
303 // FIXME: make all symbols work
304 // without conflicting with the other parsing
305 // the current implementaion is also rather slow
306 switch(c) {
307
308 // case '*':
309 case '!':
310 case '|':
311 // case '&':
312 // case '<':
313 // case '>':
314 // case '{':
315 // case '}':
316 // case '[':
317 // case ']':
318 // case '(':
319 // case ')':
320 // case ':':
321 case '-':
322 case '=':
323 case '+': return true;
324 default : return false;
325 }
326 }
327 // parse for symbols ----------------------------------------------------------
parseSymbol()328 void Engine::parseSymbol() {
329
330 // FIXME: make all symbols work
331 // without conflicting with the other parsing
332 // the current implementaion is also rather slow
333 if(abortParse()) {return;}
334
335 int end;
336 int insert = 0;
337
338 for(int i=0; i < buffer.size(); i++) {
339
340 if(isSymbol(buffer[i])) {
341
342 end = i;
343 while(isSymbol(buffer[end+1])) {end++;}
344
345 if(colourSymbol(i,end)) {
346
347 insert += 27;
348 i = end + insert;
349 }
350 }
351 }
352 // currently enabled for:
353 // C,C++,Cg,C#,Objective C,Java,Perl,PHP,Python,UScript
354 }
355 // colour the symbols ---------------------------------------------------------
colourSymbol(int s,int f)356 bool Engine::colourSymbol(int s, int f) {
357
358 if(abortColour(s)) {return false;}
359 if(!isNotWord(s)) {return false;}
360
361 buffer.insert(s,"<font CLASS=symbols>");
362 buffer.insert(f+21,"</font>");
363
364 return true;
365 }
366 // parse labels ---------------------------------------------------------------
parseLabel()367 void Engine::parseLabel() {
368
369 if(abortParse()) {return;}
370
371 if(buffer.find("/*") != -1) {return;} //prevent comment loop
372 if(buffer.find("(*") != -1) {return;}
373
374
375 int end, beg;
376
377 end = buffer.size()-1;
378 beg = buffer.rfind(" ",end);
379
380 if(beg == -1) {beg = 0;}
381 if(buffer[end] == ':') {
382 colourLabel(beg,end);
383 }
384 }
385 // colourize the labels -------------------------------------------------------
colourLabel(int beg,int end)386 void Engine::colourLabel(int beg, int end) {
387
388 if(abortColour(beg)) {return;}
389 buffer.insert(beg,"<font CLASS=preproc>");
390 buffer.insert(end+21,"</font>");
391 }
392 //-----------------------------------------------------------------------------
393 // parse the buffer for numbers -----------------------------------------------
parseNum()394 void Engine::parseNum()
395 {
396 if(buffer[0] == '#') {return;}
397 if(abortParse()) {return;}
398
399 vector<int> nums;
400 vector<int> ends;
401 int end, insert;
402
403 // grab indexes of all numbers into the vector
404 for(int i=0; i < buffer.size(); i++) {
405
406 if(isdigit(buffer[i]) && !isalpha(buffer[i-1])) {
407 end = i;
408
409 while(isdigit(buffer[end+1]) ||
410 (buffer[end+1] == '.' &&
411 isdigit(buffer[end+2])))
412 {end++;}
413
414 nums.push_back(i);
415 ends.push_back(end);
416 i=end;
417 }
418 }
419 // now colour each number
420 for(int j=0; j < (int)ends.size(); j++) {
421
422 if(j == 0) {insert = 0;}
423 else {insert += 27;}
424
425 if(!colourNum(nums[j]+insert, ends[j]+insert)) {
426 insert -= 27;
427 }
428 }
429
430 }
431 // insert number highlighting tags --------------------------------------------
colourNum(int s,int f)432 bool Engine::colourNum(int s, int f) {
433
434 if(abortColour(s)) {return false;}
435 if(!isNotWord(s)) {return false;}
436
437 string cssclass;
438 int fpt;
439
440 fpt = buffer.find(".",s);
441
442 if(fpt != -1 && fpt < f) {
443
444 cssclass = "<font CLASS=floatpt>";
445 } else
446 cssclass = "<font CLASS=integer>";
447
448
449 // insert the font tags
450 buffer.insert(s, cssclass);
451 buffer.insert(f+21, "</font>");
452
453 return true;
454 }
455 //-----------------------------------------------------------------------------
456 // parse the buffer for strings -----------------------------------------------
parseString(char quotetype,bool & inside)457 void Engine::parseString(char quotetype, bool &inside) {
458
459 if(doAdaComnt && !doRemComnt && quotetype == SIN_QUOTES) {return;}
460 if(doAspComnt && quotetype == SIN_QUOTES) {return;}
461
462 string quote, escap1, escap2, cssclass;
463 int index,offset;
464 index = 0;
465
466 // Support for 3 different string types
467 if (quotetype == DBL_QUOTES) {
468 if(inSinQuotes || inBckQuotes) {return;}
469
470 quote = "\"";
471
472 // Asp uses single ticks for comments and this
473 // screws up if a double-quoted line is commented out
474 if (!doAspComnt) {
475 escap1 = "'";
476 } else {
477 escap1 = "`";
478 }
479 escap2 = "`";
480
481 cssclass = "dblquot";
482
483 } else if(quotetype == SIN_QUOTES) {
484 if(inDblQuotes || inBckQuotes) {return;}
485
486 quote = "'";
487 escap1 = "\"";
488 escap2 = "`";
489
490 cssclass = "sinquot";
491
492 } else if(quotetype == BCK_QUOTES) {
493 if(inDblQuotes || inSinQuotes) {return;}
494
495 quote = "`";
496 escap1 = "\"";
497 escap2 = "'";
498
499 cssclass = "preproc";
500 }
501 // Double, single, and back quoted ///
502
503
504 index = buffer.find(quote,index);
505 if(index == -1) {return;}
506
507 while (index < string::npos) {
508
509 if(buffer[index -1] == '\\') {
510 if(buffer[index -2] == '\'' && buffer[index +1] == '\'') {
511 index = buffer.find(quote,index+1);
512 }
513 }
514 if(index == -1) {return;}
515
516 while(isInsideIt(index,escap1,escap1)){
517 index = buffer.find(quote,index +1);
518 if(index == -1) {return;}
519 }
520 while(isInsideIt(index,escap2,escap2)){
521 index = buffer.find(quote,index +1);
522 if(index == -1) {return;}
523 }
524
525 while(doHtmComnt && isInsideIt(index,">","<") ) {
526 index = buffer.find(quote,index +1);
527 if(index == -1) {return;}
528 }
529
530 // keep escape characters in mind
531 while (buffer[index -1] == '\\' &&
532 (buffer[index -2] != '\\' ||
533 (buffer[index -3] == '\\' &&
534 buffer[index -4] != '\\'))) {
535
536 index = buffer.find(quote,index +1);
537 if(index == -1) {return;}
538 }
539
540 if(index != -1 && !inComment) {
541
542 colourString(index, inside, cssclass);
543 }
544
545 if(inside) {offset = index + 21;}
546 else {offset = index + 7;}
547
548 index = buffer.find(quote,offset);
549 if(index == -1) {return;}
550 if(index > buffer.size()){return;}
551 }
552 }
553 // insert string highlighting tags --------------------------------------------
colourString(int index,bool & inside,string cssclass)554 void Engine::colourString(int index, bool &inside, string cssclass) {
555
556 if(index > buffer.size()){return;}
557
558 string fntag = "<font CLASS=" + cssclass + ">";
559
560 // open tag
561 if(!inside) {
562 buffer.insert(index, fntag);
563 } else {
564 buffer.insert(index+1, "</font>");
565 }
566 // or close tag
567 // depending on whether or not inside
568
569 inside = !inside;
570 }
571 // parse for multi-line comments ----------------------------------------------
parseBigComment(string start,string end,bool & inside)572 void Engine::parseBigComment(string start, string end, bool &inside) {
573
574 string search, escap, css;
575 int index,offset;
576 bool erase;
577
578 index = 0;
579 erase = true;
580 css = "comment";
581
582 if(inside) {search = end;}
583 else {search = start;}
584
585 index = buffer.find(search,index);
586 if(index == -1) {return;}
587 if(doCinComnt && start == "/*" && buffer.find("//") < index) {return;}
588 if(doUnxComnt && start == "/*" && buffer.find("#") < index) {return;}
589
590 if(start == "<" && end == ">" && doHtmlTags) {
591
592 if(buffer.find("<!-") == index || inHtmTags)
593 if(!inside)
594 return;
595 erase = false;
596 css = "preproc";
597 }
598
599 while (index < string::npos) {
600
601 if(inside) {search = end;}
602 else {search = start;}
603
604 index = buffer.find(search,index);
605 if(index == -1) {return;}
606
607 if(buffer[index -1] == '\\') {
608 if(buffer[index -2] == '\'' && buffer[index +1] == '\'') {
609 index = buffer.find(search,index+1);
610 }
611 }
612 if(index == -1) {return;}
613 if(!isInsideIt(index, "\"", "\"") &&
614 !isInsideIt(index, "'", "'") &&
615 !isInsideIt(index, "`", "`")) {
616 if(inside) {
617 index += end.size()-1;
618 if(buffer.find(end) == -1) {endComment = true;}
619 }
620 else if(erase)eraseTags(index,0);
621 colourString(index, inside, css);
622 }
623
624 if(inside) {
625 offset = index + 21;
626 search = end;
627 }
628 else {
629 offset = index + 7;
630 search = start;
631 }
632
633 index = buffer.find(search,offset);
634 if(index == -1) {return;}
635 if(index > buffer.size()){return;}
636 }
637 }
638 // parse for keywords ---------------------------------------------------------
parseKeys()639 void Engine::parseKeys() {
640
641 if(buffer[0] == '#') {return;}
642 if(abortParse()) {return;}
643
644 int i, index, offset = 20;
645 string cmpkey;
646
647 for(i=0; i < (int)keys.size(); i++) {
648
649 cmpkey = keys[i];
650 index = noCaseFind(cmpkey,0);
651
652 while(index < buffer.size() && index != -1) {
653
654 if(isKey(index-1, (index) + keys[i].size())) {
655 colourKeys(index, keys[i], "keyword");
656 }
657 index = noCaseFind(cmpkey,(index+cmpkey.size()+offset));
658 }
659 }
660
661 for(i=0; i < (int)types.size(); i++) {
662
663 cmpkey = types[i];
664 index = noCaseFind(cmpkey,0);
665
666 while(index < buffer.size() && index != -1) {
667
668 if(isKey(index-1, (index) + types[i].size())) {
669 colourKeys(index, types[i], "keytype");
670 }
671 index = noCaseFind(cmpkey,(index+cmpkey.size()+offset));
672 }
673 }
674 }
675 // checks for case sensitive keys ---------------------------------------------
noCaseFind(string search,int index)676 int Engine::noCaseFind(string search, int index) {
677
678 if(doCaseKeys) {
679 return buffer.find(search,index);
680 }
681 if(search == "class") {
682 return buffer.find(search,index);
683 }
684
685 string tmp;
686 tmp = buffer;
687
688 for(int i=0; i < tmp.size(); i++) {
689 tmp[i] = toupper(tmp[i]);
690 }
691 for(int j=0; j < search.size(); j++) {
692 search[j] = toupper(search[j]);
693 }
694
695 return tmp.find(search,index);
696 }
697 // asserts word boundaries for keywords ---------------------------------------
isKey(int before,int after) const698 bool Engine::isKey(int before, int after) const {
699
700 if(buffer[before] == '#') {return false;}
701 if(buffer[before] == '_') {return false;}
702 if(buffer[after] == '_') {return false;}
703 if(isalnum(buffer[before])) {return false;}
704 if(isalnum(buffer[after])) {return false;}
705
706 if(ispunct(buffer[before]) || isspace(buffer[before])) {
707 if(ispunct(buffer[after]) || isspace(buffer[after])) {
708 return true;
709 }
710 }
711 return true;
712 }
713 // colourize the keywords -----------------------------------------------------
colourKeys(int index,string key,string cssclass)714 void Engine::colourKeys(int index, string key, string cssclass) {
715
716 if(abortColour(index)) {
717 return;
718 }
719 buffer.insert(index, "<font CLASS=" + cssclass + ">");
720 buffer.insert(index+key.size()+20, "</font>");
721 }
722 //-----------------------------------------------------------------------------
723 // parse for variables --------------------------------------------------------
parseVariable(string var)724 void Engine::parseVariable(string var) {
725
726 int index;
727 int test;
728
729 index = buffer.find(var,0);
730 test = buffer.find("#",0);
731 if(test != -1 && test < index) {return;}
732
733 while(index < string::npos) {
734
735 if(index != -1) {colourVariable(index);}
736 index = buffer.find(var,index +22);
737 }
738 }
739 // colourize the variables ----------------------------------------------------
colourVariable(int index)740 void Engine::colourVariable(int index) {
741
742 int end = 0;
743 buffer.insert(index, "<font CLASS=preproc>");
744
745 int i = index+21;
746
747 // search for a variable name delimiter
748 while(!end && i < buffer.size()) {
749
750 if(!isalnum(buffer[i])) {
751 if(buffer[i] == '_') {i++;}
752 if(isspace(buffer[i])) {end = i;}
753 if(ispunct(buffer[i])) {end = i;}
754 if(buffer[i] == '=') {end = i;}
755 if(buffer[i] == ',') {end = i;}
756 if(buffer[i] == '{') {end = i;}
757 if(buffer[i] == '[') {end = i;}
758 if(buffer[i] == '(') {end = i;}
759 if(buffer[i] == '\'') {end = i;}
760 if(buffer[i] == '\n') {end = i;}
761 }
762 if(i == buffer.size() -1) {end = i+1;}
763 else i++;
764 }
765
766 if(buffer[end -1] == '\"') {end--;}
767 if(buffer[end -1] == ')') {end--;}
768
769 buffer.insert(end, "</font>");
770 }
771 //-----------------------------------------------------------------------------
772 // check for comments ---------------------------------------------------------
parseComment(string cmnt)773 void Engine::parseComment(string cmnt) {
774
775 if(inComment) {return;}
776
777 int index = buffer.find(cmnt,0);
778 if(index == -1) {return;}
779
780 // do not misktake HTML attributes for UNIX comments
781 if(cmnt == "#" && index != -1 && buffer[index -1] != '\\') {
782 if(index != 0) {
783 while(buffer[index -1] == '=' && index < string::npos) {
784 index = buffer.find("#",index+1);
785 }
786 }
787 }
788 //-----------------------------------------------//
789
790 if(buffer[index -1] == '$') {return;}
791 if(buffer[index -1] == '\\') {return;}
792
793 colourComment(index);
794 }
795 // colour an inline comment ---------------------------------------------------
colourComment(int index)796 void Engine::colourComment(int index) {
797
798 if(abortColour(index)) {
799 return;
800 }
801 if(doCinComnt) {
802 if(buffer.rfind("http:",index) == index -5) {return;}
803 if(buffer.rfind("!DOCTYPE", index) != -1) {return;}
804 }
805
806 // no highlighting inside of comments
807 eraseTags(index,0);
808
809 // insert the font tags
810 buffer.insert(index, "<font CLASS=comment>");
811 buffer.insert(buffer.size(), "</font>");
812 }
813 //-----------------------------------------------------------------------------
parseCharZeroComment(char zchar)814 void Engine::parseCharZeroComment(char zchar) {
815
816 if(buffer[0] == zchar) {colourComment(0);}
817 }
818 // here is where the parsing rules apply --------------------------------------
doParsing()819 void Engine::doParsing() {
820
821 if(opt_anchor) {
822 makeAnchor();
823 }
824 if(opt_number) {
825 makeMargin();
826 }
827
828 IO->rline(buffer);
829
830 // preformat HTML escapes
831 PRE_PARSE_CODE;
832
833 if(doSymbols) parseSymbol();
834
835 #ifdef DEBUG_DO_PARSING
836 PRINT_DEBUG(0);
837 #endif
838
839 if(doLabels) PARSE_LABELS;
840
841 if(doStrings)
842 {
843 PARSE_DBL_QUO_STRING;
844 PARSE_SIN_QUO_STRING;
845 PARSE_BCK_QUO_STRING;
846 }
847
848 #ifdef DEBUG_DO_PARSING
849 PRINT_DEBUG(1);
850 #endif
851
852 if(doPreProc) PARSE_PREPROCESSOR;
853
854 if(doPasComnt) PARSE_PAS_MOD2_COMNT;
855 if(doHtmComnt) PARSE_A_MARKUP_COMNT;
856 if(doBigComnt) PARSE_CLASSICC_COMNT;
857 if(doHskComnt) PARSE_HASKL_98_COMNT;
858 if(doHtmlTags) PARSE_HTML_TAGS;
859
860 if(doKeywords) PARSE_KEYWORDS;
861
862 #ifdef DEBUG_DO_PARSING
863 PRINT_DEBUG(2);
864 #endif
865
866 if(doScalars) PARSE_SCALAR_VARIABL;
867 if(doArrays) PARSE_ARRAYS_VARIABL;
868 if(doHashes) PARSE_HASHED_VARIABL;
869
870 #ifdef DEBUG_DO_PARSING
871 PRINT_DEBUG(3);
872 #endif
873
874 if(doNumbers) PARSE_NUMBERS;
875
876 #ifdef DEBUG_DO_PARSING
877 PRINT_DEBUG(4);
878 #endif
879
880 if(doAdaComnt) {PARSE_A_ADA_95_COMNT;}
881 if(doAspComnt) {PARSE_A_MS_ASP_COMNT;}
882 if(doCinComnt) {PARSE_C_INLINE_COMNT;}
883 if(doUnxComnt) {PARSE_UNIXHASH_COMNT;}
884 if(doAsmComnt) {PARSE_ASSEMBLY_COMNT;}
885 if(doBatComnt) {PARSE_DBLCOLON_COMNT;}
886 if(doRemComnt) {PARSE_REMINDER_COMNT;}
887 if(doFtnComnt) {PARSE_ZFORTRAN_COMNT;}
888 if(doTclComnt) {PARSE_ZEROHASH_COMNT;}
889
890 #ifdef DEBUG_DO_PARSING
891 PRINT_DEBUG(5);
892 #endif
893
894 hyperTagMe();
895 hyperNameMe();
896 hyperLinkMe();
897
898 #ifdef DEBUG_DO_PARSING
899 PRINT_DEBUG(6);
900 #endif
901
902 *IO << buffer << "\n";
903 if(!childLang) {parseChildLang();}
904 endComment = inComment;
905
906 lncount++;
907 }
908 //-----------------------------------------------------------------------------
909 // write the initial HTML tags ------------------------------------------------
begHtml(string name)910 void Engine::begHtml(string name) {
911
912 string gen;
913 string style;
914 string openht;
915
916 string ImgPath;
917 string CssFile;
918 string Path;
919 int dir_idx;
920
921
922 gen = "\
923 <!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\
924 \n\n<!--\nSyntax highlighting generated by Web C Plus Plus software v0.8.4\n\
925 Webcpp Copyright (C)2001-2004 Jeffrey Bakker under the GNU GPL\n\
926 Get webcpp at http://webcpp.sf.net\n-->\n\n";
927
928
929 if(Scs2.getImageFile() != "\0") {
930
931 string CopyCmd = COPY;
932
933 ImgPath = Scs2.getImageFile();
934 dir_idx = IO->getStrOf().rfind(DIRECTORY_SLASH);
935
936 if(dir_idx != -1) {
937
938 Path = IO->getStrOf().substr(0,dir_idx+1);
939
940 Scs2.setImageLeaf();
941 CopyCmd += " \"" + ImgPath + "\" \"" + Path + Scs2.getImageFile() + "\"";
942 system(CopyCmd.data());
943 // IO->backup(ImgPath, Path + Scs2.getImageFile(), true);
944 }
945 }
946
947 // external or embedded stylesheet
948 if(opt_extcss) {
949
950 CssFile = Scs2.getThemeName() + ".css";
951
952 dir_idx = IO->getStrOf().rfind(DIRECTORY_SLASH);
953
954 if(dir_idx != -1) {
955
956 Path = IO->getStrOf().substr(0,dir_idx+1);
957 CssFile = Path + CssFile;
958 }
959
960 Scs2.writeCSS(CssFile);
961 // cerr << endl << CssFile << endl;
962
963 style =
964 "<link rel=\"stylesheet\" type=\"text/css\" href=\""
965 + Scs2.getThemeName() + ".css\"/>\n";
966 } else {
967 style =
968 "<style type=\"text/css\">\n\n"
969 + Scs2.getCSSdata() + "</style>\n";
970 }
971
972 // html snippet or complete html tags
973 if(opt_htsnip) {
974
975 openht = style;
976 } else {
977 openht =
978 "<html>\n<head>\n<title>" + name + "</title>\n"
979 + style + "</head>\n<body>\n\n"; // bgcolor="
980 // + Scs2.getColourByID(BGCOLOR) + ">\n\n";
981 }
982
983 if(IO->isOredir()) {
984
985 *IO << "Content-Type: text/html\n\n"; // cgi-ready
986 }
987 *IO << gen << openht << "<div class=\"webcpp\">\n<pre>\n\n";
988 }
989 // write the closing HTML tags ------------------------------------------------
endHtml()990 void Engine::endHtml() {
991
992 *IO << "\n\n</pre>\n";
993 if(opt_webcpp) {
994
995 string made;
996 made = "<center>\n<hr size=4 width=95%>\n<br>\n\
997 syntax highlighting by<br><br>\n\
998 <table cellpadding=3 cellspacing=3 bgcolor=#000000><tr>\n\
999 <td bgcolor=#ff0000><tt><font size=+2 color=#000000>w</font></tt></td>\n\
1000 <td bgcolor=#ffbb00><tt><font size=+2 color=#000000>e</font></tt></td>\n\
1001 <td bgcolor=#ffff00><tt><font size=+2 color=#000000>b</font></tt></td>\n\
1002 <td bgcolor=#00ff00><tt><font size=+2 color=#000000>c</font></tt></td>\n\
1003 <td bgcolor=#0000ff><tt><font size=+2 color=#000000>p</font></tt></td>\n\
1004 <td bgcolor=#bb00ff><tt><font size=+2 color=#000000>p</font></tt></td>\n\
1005 </tr><tr><td colspan=6>\n\
1006 <a href=\"http://webcpp.sf.net\"><center><b>\
1007 <font color=#ffffff>web c plus plus</font></b></center>\n\
1008 </a></td></tr>\n</table>\n<br>\n</center>";
1009
1010 *IO << made;
1011 }
1012 *IO << "\n</div>\n";
1013 if(!opt_htsnip) {*IO << "\n\n</body>\n</html>\n";}
1014 }
1015 // place HTML tags without being stripped -------------------------------------
hyperTagMe()1016 void Engine::hyperTagMe() {
1017
1018 int index;
1019 index = buffer.find("TagMe:",0);
1020 if(index == -1) {return;}
1021 if(abortColour(index)) {
1022 return;
1023 }
1024 buffer.erase(index,6);
1025
1026 for(int i=index; i < buffer.size(); i++) {
1027 if (buffer.substr(i,4) == "<") buffer.replace(i,4, "<");
1028 else if (buffer.substr(i,4) == ">") buffer.replace(i,4, ">");
1029 }
1030 }
1031 // hyperlink a line of code ---------------------------------------------------
hyperLinkMe()1032 void Engine::hyperLinkMe() {
1033
1034 int index;
1035 index = buffer.find("LinkMe:",0);
1036 if(index == -1) {return;}
1037 if(abortColour(index)) {
1038 return;
1039 }
1040 string link;
1041 link = buffer.substr(index+7);
1042 buffer.erase(index, buffer.size() - index);
1043
1044 buffer.insert(0, "<a href=\"" + link + "\">");
1045 buffer += "</a>";
1046 }
1047 // anchor a line of code ------------------------------------------------------
hyperNameMe()1048 void Engine::hyperNameMe() {
1049
1050 int index;
1051 index = buffer.find("NameMe:",0);
1052 if(index == -1) {return;}
1053 if(abortColour(index)) {
1054 return;
1055 }
1056 string name;
1057 name = buffer.substr(index+7);
1058 buffer.erase(index, buffer.size() - index);
1059
1060 buffer.insert(0, "<a name=\"" + name + "\">");
1061 buffer += "</a>";
1062 }
1063 // automatically hyperlink included C/C++ files -------------------------------
hyperIncludeMe()1064 void Engine::hyperIncludeMe() {
1065
1066 int incl, insr;
1067
1068 incl = buffer.find("#include",0);
1069 if(incl == -1) {return;}
1070
1071 insr = buffer.find("\"",incl+1);
1072 if(insr == -1) {return;}
1073
1074 string cmd;
1075 string link;
1076 link = buffer.substr(insr);
1077 link = link.substr(0,link.find("\"</font>"));
1078
1079 if(opt_follow) {
1080 // follow and process the include file
1081
1082 string path;
1083
1084 int dir_idx = IO->getStrIf().rfind(DIRECTORY_SLASH);
1085
1086 if(dir_idx != -1) {
1087
1088 path = IO->getStrIf().substr(0,dir_idx+1);
1089 path = path + link.substr(1);
1090 } else {
1091 path = link.substr(1);
1092 }
1093
1094 cmd = "webcpp " + path + " -A:f -H";
1095 // retain switches from the current file
1096 if(opt_bigtab) {
1097 cmd += " -t";
1098 if(tabwidth != 8) {
1099 cmd += "=";
1100 cmd += tw;
1101 }
1102 }
1103 if(opt_webcpp) cmd += " -m";
1104 if(opt_number) cmd += " -l";
1105 if(opt_anchor) cmd += " -a";
1106 if(opt_htsnip) cmd += " -s";
1107 if(opt_extcss) cmd += " -X";
1108
1109 if(Scs2.getThemeName() != "typical") {
1110 cmd += " -c=" + Scs2.getThemeName();
1111 }
1112 if(Scs2.getImageFile() != "") {
1113 cmd += " -i=" + Scs2.getImageFile();
1114 }
1115 cerr << "\nSuperInclude found " + path + "\n";
1116 cerr << cmd << "\n";
1117 system(cmd.data());
1118 }
1119 // make the hyperlink
1120 link = "<a href=" + link + ".html\">";
1121 buffer.insert(insr, link);
1122 buffer.insert(buffer.size(),"</a>");
1123 }
1124 //-----------------------------------------------------------------------------
1125 // parse for inline languages -------------------------------------------------
parseChildLang()1126 void Engine::parseChildLang() {
1127
1128 // if(abortParse()) {return;}
1129 // cerr << "\nNow in parseChildLang()\n";
1130
1131 switch(langext)
1132 {
1133 case CPP_FILE : PARSE_INLINE_ASM; break;
1134 case HTM_FILE : PARSE_INLINE_JS; break;
1135 default : return;
1136 }
1137 }
1138 // process an inline child language -------------------------------------------
colourChildLang(string beg,string end)1139 void Engine::colourChildLang(string beg, string end) {
1140
1141 // cerr << "\nNow in colourChildLang()\n";
1142
1143 if(buffer.find(beg) != -1) {
1144
1145 // cerr << "\nNow in if of colourChildLang()\n";
1146
1147 Engine *Child;
1148
1149 switch(langext)
1150 {
1151 case CPP_FILE : CHILD(LangAssembler, ASM_FILE); break;
1152 case HTM_FILE : CHILD(LangJScript, JSC_FILE); break;
1153 }
1154 Child->setupIO(IO);
1155 Child->setChildLang(true);
1156 Child->setLineCount(lncount +1);
1157 if(opt_anchor) {Child->toggleAnchor();}
1158 if(opt_number) {Child->toggleNumber();}
1159
1160 if(langext == CPP_FILE)
1161 {Child->setInline();}
1162 if(langext == HTM_FILE && inComment)
1163 {*IO << "</font>";}
1164
1165 do {
1166 Child->doParsing();
1167 // cerr << endl << Child->getBuffer() << endl;
1168 } while(Child->getBuffer().find(end) == -1 &&
1169 (Child->IO->ifile && cin));
1170
1171 if(langext == HTM_FILE && inComment)
1172 {*IO << "<font CLASS=comment>";}
1173
1174 setLineCount(Child->getLineCount() -1);
1175 }
1176 }
1177 //-----------------------------------------------------------------------------
1178