]> bicyclesonthemoon.info Git - ott/bsta/blob - bsta_lib.1.pm
Adapted for new config tool.
[ott/bsta] / bsta_lib.1.pm
1 # bsta_lib.pm is generated from bsta_lib.1.pm
2
3 # Library of functions
4 #
5 # Copyright (C) 2016, 2017, 2019, 2020, 2022, 2023  Balthasar Szczepański
6 #
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as
9 # published by the Free Software Foundation, either version 3 of the
10 # License, or (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU Affero General Public License for more details.
16 #
17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
20 package bsta_lib;
21
22 use strict;
23 #use warnings
24 use Exporter;
25 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
26
27 use constant entitycode => {
28         'amp' => '&',
29         'gt' => '>',
30         'lt' => '<',
31         'quot' => '"',
32         'acute' => '´',
33         'cedil' => '¸',
34         'circ' => 'ˆ',
35         'macr' => '¯',
36         'middot' => '·',
37         'tilde' => '˜',
38         'uml' => '¨',
39         'Aacute' => 'Á',
40         'aacute' => 'á',
41         'Acirc' => 'Â',
42         'acirc' => 'â',
43         'AElig' => 'Æ',
44         'aelig' => 'æ',
45         'Agrave' => 'À',
46         'agrave' => 'à',
47         'Aring' => 'Å',
48         'aring' => 'å',
49         'Atilde' => 'Ã',
50         'atilde' => 'ã',
51         'Auml' => 'Ä',
52         'auml' => 'ä',
53         'Ccedil' => 'Ç',
54         'ccedil' => 'ç',
55         'Eacute' => 'É',
56         'eacute' => 'é',
57         'Ecirc' => 'Ê',
58         'ecirc' => 'ê',
59         'Egrave' => 'È',
60         'egrave' => 'è',
61         'ETH' => 'Ð',
62         'eth' => 'ð',
63         'Euml' => 'Ë',
64         'euml' => 'ë',
65         'Iacute' => 'Í',
66         'iacute' => 'í',
67         'Icirc' => 'Î',
68         'icirc' => 'î',
69         'Igrave' => 'Ì',
70         'igrave' => 'ì',
71         'Iuml' => 'Ï',
72         'iuml' => 'ï',
73         'Ntilde' => 'Ñ',
74         'ntilde' => 'ñ',
75         'Oacute' => 'Ó',
76         'oacute' => 'ó',
77         'Ocirc' => 'Ô',
78         'ocirc' => 'ô',
79         'OElig' => 'Œ',
80         'oelig' => 'œ',
81         'Ograve' => 'Ò',
82         'ograve' => 'ò',
83         'Oslash' => 'Ø',
84         'oslash' => 'ø',
85         'Otilde' => 'Õ',
86         'otilde' => 'õ',
87         'Ouml' => 'Ö',
88         'ouml' => 'ö',
89         'Scaron' => 'Š',
90         'scaron' => 'š',
91         'szlig' => 'ß',
92         'THORN' => 'Þ',
93         'thorn' => 'þ',
94         'Uacute' => 'Ú',
95         'uacute' => 'ú',
96         'Ucirc' => 'Û',
97         'ucirc' => 'û',
98         'Ugrave' => 'Ù',
99         'ugrave' => 'ù',
100         'Uuml' => 'Ü',
101         'uuml' => 'ü',
102         'Yacute' => 'Ý',
103         'yacute' => 'ý',
104         'yuml' => 'ÿ',
105         'Yuml' => 'Ÿ',
106         'cent' => '¢',
107         'curren' => '¤',
108         'euro' => '€',
109         'pound' => '£',
110         'yen' => '¥',
111         'brvbar' => '¦',
112         'bull' => '•',
113         'copy' => '©',
114         'dagger' => '†',
115         'Dagger' => '‡',
116         'frasl' => '⁄',
117         'hellip' => '…',
118         'iexcl' => '¡',
119         'image' => 'ℑ',
120         'iquest' => '¿',
121         'lrm' => '‎',
122         'mdash' => '—',
123         'ndash' => '–',
124         'not' => '¬',
125         'oline' => '‾',
126         'ordf' => 'ª',
127         'ordm' => 'º',
128         'para' => '¶',
129         'permil' => '‰',
130         'prime' => '′',
131         'Prime' => '″',
132         'real' => 'ℜ',
133         'reg' => '®',
134         'rlm' => '‏',
135         'sect' => '§',
136         'shy' => '­',
137         'sup1' => '¹',
138         'trade' => '™',
139         'weierp' => '℘',
140         'bdquo' => '„',
141         'laquo' => '«',
142         'ldquo' => '“',
143         'lsaquo' => '‹',
144         'lsquo' => '‘',
145         'raquo' => '»',
146         'rdquo' => '”',
147         'rsaquo' => '›',
148         'rsquo' => '’',
149         'sbquo' => '‚',
150         'emsp' => ' ',
151         'ensp' => ' ',
152         'nbsp' => ' ',
153         'thinsp' => ' ',
154         'zwj' => '‍',
155         'zwnj' => '‌',
156         'deg' => '°',
157         'divide' => '÷',
158         'frac12' => '½',
159         'frac14' => '¼',
160         'frac34' => '¾',
161         'ge' => '≥',
162         'le' => '≤',
163         'minus' => '−',
164         'sup2' => '²',
165         'sup3' => '³',
166         'times' => '×',
167         'alefsym' => 'ℵ',
168         'and' => '∧',
169         'ang' => '∠',
170         'asymp' => '≈',
171         'cap' => '∩',
172         'cong' => '≅',
173         'cup' => '∪',
174         'empty' => '∅',
175         'equiv' => '≡',
176         'exist' => '∃',
177         'fnof' => 'ƒ',
178         'forall' => '∀',
179         'infin' => '∞',
180         'int' => '∫',
181         'isin' => '∈',
182         'lang' => '⟨',
183         'lceil' => '⌈',
184         'lfloor' => '⌊',
185         'lowast' => '∗',
186         'micro' => 'µ',
187         'nabla' => '∇',
188         'ne' => '≠',
189         'ni' => '∋',
190         'notin' => '∉',
191         'nsub' => '⊄',
192         'oplus' => '⊕',
193         'or' => '∨',
194         'otimes' => '⊗',
195         'part' => '∂',
196         'perp' => '⊥',
197         'plusmn' => '±',
198         'prod' => '∏',
199         'prop' => '∝',
200         'radic' => '√',
201         'rang' => '⟩',
202         'rceil' => '⌉',
203         'rfloor' => '⌋',
204         'sdot' => '⋅',
205         'sim' => '∼',
206         'sub' => '⊂',
207         'sube' => '⊆',
208         'sum' => '∑',
209         'sup' => '⊃',
210         'supe' => '⊇',
211         'there4' => '∴',
212         'Alpha' => 'Α',
213         'alpha' => 'α',
214         'Beta' => 'Β',
215         'beta' => 'β',
216         'Chi' => 'Χ',
217         'chi' => 'χ',
218         'Delta' => 'Δ',
219         'delta' => 'δ',
220         'Epsilon' => 'Ε',
221         'epsilon' => 'ε',
222         'Eta' => 'Η',
223         'eta' => 'η',
224         'Gamma' => 'Γ',
225         'gamma' => 'γ',
226         'Iota' => 'Ι',
227         'iota' => 'ι',
228         'Kappa' => 'Κ',
229         'kappa' => 'κ',
230         'Lambda' => 'Λ',
231         'lambda' => 'λ',
232         'Mu' => 'Μ',
233         'mu' => 'μ',
234         'Nu' => 'Ν',
235         'nu' => 'ν',
236         'Omega' => 'Ω',
237         'omega' => 'ω',
238         'Omicron' => 'Ο',
239         'omicron' => 'ο',
240         'Phi' => 'Φ',
241         'phi' => 'φ',
242         'Pi' => 'Π',
243         'pi' => 'π',
244         'piv' => 'ϖ',
245         'Psi' => 'Ψ',
246         'psi' => 'ψ',
247         'Rho' => 'Ρ',
248         'rho' => 'ρ',
249         'Sigma' => 'Σ',
250         'sigma' => 'σ',
251         'sigmaf' => 'ς',
252         'Tau' => 'Τ',
253         'tau' => 'τ',
254         'Theta' => 'Θ',
255         'theta' => 'θ',
256         'thetasym' => 'ϑ',
257         'upsih' => 'ϒ',
258         'Upsilon' => 'Υ',
259         'upsilon' => 'υ',
260         'Xi' => 'Ξ',
261         'xi' => 'ξ',
262         'Zeta' => 'Ζ',
263         'zeta' => 'ζ',
264         'crarr' => '↵',
265         'darr' => '↓',
266         'dArr' => '⇓',
267         'harr' => '↔',
268         'hArr' => '⇔',
269         'larr' => '←',
270         'lArr' => '⇐',
271         'rarr' => '→',
272         'rArr' => '⇒',
273         'uarr' => '↑',
274         'uArr' => '⇑',
275         'clubs' => '♣',
276         'diams' => '♦',
277         'hearts' => '♥',
278         'spades' => '♠',
279         'loz' => '◊',
280 };
281
282 use constant tagsbb => {
283         'ht'    => '',
284         '/ht'   => '',
285         'fq'    => '[quote]',
286         '/fq'   => '[/quote]',
287         'tq'    => '[quote]',
288         '/tq'   => '[/quote]',
289         'ni'    => '[color=#0057AF]',
290         '/ni'   => '[/color]',
291         'br'    => '[color=#BB6622]',
292         '/br'   => '[/color]',
293         'po'    => '[color=#FF8800]',
294         '/po'   => '[/color]',
295         'url'   => '[url]',
296         'url='  => '[url=',
297         'url/=' => ']',
298         '/url'  => '[/url]',
299         'i'     => '[i]',
300         '/i'    => '[/i]',
301         'list'  => '[list]',
302         'list=' => '[list=',
303         'list/='=> ']',
304         '/list' => '[/list]',
305         '*'     => '[*]',
306         '/*'    => '[/*]',
307         '?'     => '[unknown!]',
308         '/?'    => '[/unknown!]',
309 };
310 use constant tagsht => {
311         'ht'     => '',
312         '/ht'    => '',
313         'fq'     => '<div class="fq">',
314         '/fq'    => '</div>',
315         'tq'     => '<div class="tq">',
316         '/tq'    => '</div>',
317         'ni'     => '<span class="ni">',
318         '/ni'    => '</span>',
319         'br'     => '<span class="br">',
320         '/br'    => '</span>',
321         'po'     => '<span class="po">',
322         '/po'    => '</span>',
323         'url'    => '<a href="#">',#think: how to add selfincluding?
324         'url='   => '<a href="',
325         'url/='  => '">',
326         '/url'   => '</a>',
327         'i'      => '<i>',
328         '/i'     => '</i>',
329         'list'   => '<ul>',
330         'list='  => '<ol style="list-style-type: ',
331         'list=1' => 'decimal',
332         'list=A' => 'upper-alpha',
333         'list=a' => 'lower-alpha',
334         'list=I' => 'upper-roman',
335         'list=i' => 'lower-roman',
336         'list/=' => '">',
337         '/list'  => '</ul>',
338         '/list=' => '</ol>',
339         '*'      => '<li>',
340         '/*'     => '</li>',
341         '?'      => '[unknown!]',
342         '/?'     => '[/unknown!]',
343 };
344
345 ###PERL_EXPORT_VERSION: our $VERSION = 'x.x.x';
346 our @ISA         = qw(Exporter);
347 our @EXPORT      = ();
348 our @EXPORT_OK   = qw(entityencode failpage gethttpheader getcgi urldecode readdatafile writedatafile printdatafile printdatafileht urlencode linehtml bb2ht bb2bb);
349 our %EXPORT_TAGS = ();
350
351 # Function to show an error page
352 # arguments: 1 - header fields, 2 - page title, 3 - error message, 4 method
353 sub failpage {
354         (my $header, my $title, my $message, my $method)=@_;
355         if($header ne ''){
356                 print $header;
357         }
358         if($method eq 'HEAD') {
359                 print "\n";
360                 return;
361         }
362         print "Content-type: text/html\n\n";
363         print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "">'."\n";
364         print '<html lang="en"><head>'."\n";
365         if($title ne ''){
366                 print '<title>'.entityencode($title).'</title>'."\n";
367         }
368         print '<meta http-equiv="Content-type" content="text/html; charset=UTF-8">'."\n";
369         print '</head><body>'."\n";
370         if($title ne ''){
371                 print '<h1>'.entityencode($title).'</h1>'."\n";
372         }
373         if($message ne ''){
374                 print '<p>'.entityencode($message).'</p>'."\n";
375         }
376         print '</body></html>'."\n";
377 }
378
379 # function to encode entities, decimal, 
380 sub entityencode {
381         (my $t, my $all) = @_;
382         if ($all) {
383                 $t =~ s/(.)/sprintf('\&#%02hu;',ord($1))/eg;
384         }
385         else {
386                 $t =~ s/([\"=><\&])/sprintf('&#%02hu;',ord($1))/eg;
387         }
388         return $t;
389 }
390
391 # function to get values of http header fields. Returns a hash. names of header
392 # fields are lowercase
393 sub gethttpheader {
394         (my $env) = @_;
395         
396         my %http;
397         
398         foreach my $ind (keys %$env) {
399                 my $name = '';
400                 my $value= '';
401                 
402                 if ($ind =~ /^HTTP_([A-Z0-9_]+)$/) {
403                         $name=$1;
404                 }
405                 elsif ($ind =~ /^(CONTENT_[A-Z0-9_]+)$/) {
406                         $name=$1;
407                 }
408                 else{
409                         next;
410                 }
411                 $name =~ s/_/-/g;
412                 $name = lc($name);
413                 if ($$env{$ind} =~ /^([\x20-\x7e]*)$/) {
414                         $value=$1;
415                 }
416                 else {
417                         next;
418                 }
419                 $http{$name}=$value;
420         }
421         return %http;
422 }
423
424 # The function to get CGI parameters from string.
425 # Format is: name=url_encoded_value&name=url_encoded_value& ... &name=url_encoded_value
426 sub getcgi {
427         my $arg;
428         my $val;
429         my %cgi;
430         my $i = $_[0];
431         $i =~ s/[\r\n]//g;
432         my @s = split('&',$i);
433         foreach my $l ( @s) {
434                 ($arg,$val)=split('=',$l);
435                 $cgi{$arg}=urldecode($val);
436         }
437         return %cgi;
438 }
439
440 # Function for decoding URL-encoded text
441 sub urldecode {
442         my $t = $_[0];
443         $t =~ s/\+/ /g;
444         $t =~ s/%([a-fA-F0-9]{2})/chr(hex($1))/eg;
445         return $t;
446 }
447
448 # Function to read data from datafiles.
449 # Very similar to http header file reading. (function readheaderfile() in proxy
450 # library)
451
452 # Differences:
453 #
454 # 1. After field name and colon there must be exactly one whitespace (space or
455 # tab). Any other leading or trailing whitespace (but not the newline character
456 # at the end of the line) is treated as part of the field value.
457 #
458 # 2. Instead of colon an equal sign can be used. The number of whitespaces after
459 # it is then zero and not one.
460 #
461 # 3. When header field is split into multiple lines the next lines must start
462 # with exactly one whitespace (tab or space) Any other leading or trailing
463 # whitespace (but not the newline character at the end of the line) is treated
464 # as part of the field value. the lines will be joined with a newline between
465 # them.
466 #
467 # 4. When the same field name appears it replaces the previous one.
468
469 # 5. Line separator is LF and not CR LF. The CR character is treated as part of
470 # the field value.
471 #
472 # 6. After the end of header (double newline) all next lines are treated as the
473 # value of the "content" field.
474 #
475 # Returns a hash containing the values.
476 # Names are case sensitive and are converted to lowercase
477 #
478 # Argument can be a path or a file handle. In case of a file handle it will just
479 # read the file. In case of path it opens the file before reading and closes
480 # after. On failure (file not open) returns empty hash.
481
482 sub readdatafile {
483         (my $datapath) = @_;
484         my $datafile;
485         my %data;
486         my $eoh=0;
487         
488         # check if $datapath is actually a path or maybe a filehandle
489         # filehandles are references.
490         if(ref($datapath)) {
491                 $datafile=$datapath;
492                 unless (seek($datafile, 0, 0)) {
493                         return %data;
494                 }
495         }
496         else {
497                 unless (open ($datafile, "<", $datapath)) {
498                         return %data;
499                 }
500         }
501
502         # The name of header field in previous line. Required for header fields that
503         # occupy multiple lines.
504         my $lastname='';
505         
506         while (defined(my $line = <$datafile>)) {
507                 my $name='';
508                 my $value='';
509                 
510                 if ($eoh){
511                         unless($line eq'') {
512                                 $data{'content'} = $data{'content'}.$line;
513                         }
514                         next;
515                 }
516                 
517                 $line =~ s/[\n]$//g;
518                 
519                 # Empty line - end of header.
520                 if ($line eq ''){
521                         $eoh=1;
522                 }
523                 # Line starts with whitespace. It's a continuation of the previous line.
524                 # Concatenate the field value, separated by newline.
525                 elsif($line =~ /^[ \t](.*)$/){
526                         if($lastname ne '') {
527                                 $data{$lastname}.="\n".$1;
528                         }
529                 }
530                 # Line starts with a name followed by colon/equal sign. Save the value
531                 elsif ($line =~ /^([^:=]+)((:[ \t])|=)(.*)$/) {
532                         $name = lc($1);
533                         $value = $4;
534                         
535                         $data{$name}=$value;
536                         
537                         $lastname = $name;
538                 }
539         }
540         
541         # If argument was a path the file must be closed. 
542         unless (ref($datapath)) {
543                 close ($datafile);
544         }
545         
546         return %data;
547 }
548
549 # the function to write data to datafiles (see readdatafile() description)
550 #
551 # First argument can be a path or a file handle. In case of a file handle it
552 # will just write the file. In case of path it opens the file before writing and
553 # closes after.
554 #
555 # On failure (file not open) returns 0.
556 # On success returns 1.
557 #
558 sub writedatafile {
559         (my $headerpath, my %header) = @_;
560         my $headerfile;
561         
562         if(ref($headerpath)) {
563                 $headerfile=$headerpath;
564                 unless (seek($headerfile, 0, 0)) {
565                         return 0;
566                 }
567         }
568         else {
569                 unless (open ($headerfile, ">", $headerpath)) {
570                         return 0;
571                 }
572         }
573         
574         foreach my $ind (keys %header) {
575                 unless($ind eq 'content') {
576                         my $headname = $ind;
577                         my $headval = $header{$ind};
578                         $headval =~ s/\r//g;
579                         $headval =~ s/\n/\n /g;
580                         print $headerfile "$headname: $headval\n";
581                 }
582         }
583         print $headerfile "\n".$header{'content'};
584         
585         unless (ref($headerpath)) {
586                 close ($headerfile);
587         }
588         else {
589                 truncate ($headerfile , tell($headerfile));
590         }
591         
592         return 1;
593 }
594
595 # the function to print data to stdout (see readdatafile() description)
596 #
597 # On success returns 1.
598 #
599 sub printdatafile {
600         (my %header) = @_;
601         
602         foreach my $ind (keys %header) {
603                 unless($ind eq 'content') {
604                         my $headname = $ind;
605                         my $headval = $header{$ind};
606                         $headval =~ s/\r//g;
607                         $headval =~ s/\n/\n /g;
608                         print "$headname: $headval\n";
609                 }
610         }
611         print "\n".$header{'content'};
612         
613         return 1;
614 }
615
616 # the function to print data to stdout as html (see readdatafile() description)
617 #
618 # On success returns 1.
619 #
620 sub printdatafileht {
621         (my %header) = @_;
622         
623         foreach my $ind (keys %header) {
624                 unless($ind eq 'content') {
625                         my $headname = $ind;
626                         my $headval = $header{$ind};
627                         $headval =~ s/\r//g;
628                         $headval =~ s/\n/\n /g;
629                         print linehtml("$headname: $headval\n");
630                 }
631         }
632         print linehtml("\n".$header{'content'});
633         
634         return 1;
635 }
636
637
638 sub urlencode {
639         (my $t, my $all) = @_;
640         if ($all) {
641                 $t =~ s/(.)/sprintf('%%%02hX',ord($1))/eg;
642         }
643         else {
644                 $t =~ s/([^0-9A-Za-z.~\-_])/sprintf('%%%02hX',ord($1))/eg;
645         }
646         return $t;
647 }
648
649 #analyse bbcode text to build tag tree #TODO make [/*] optional!
650 sub bbtree {
651         (my $bb, my $printdebug) = @_;
652         my %bbtree;
653         my $ind;
654         my $tag;
655         my $tagname;
656         my $tagvalue;
657         my $tagend;
658         my $level=0;
659         my $pretext;
660         my $debug;
661         
662         $ind="_";
663         $level=0;
664         $bbtree{"_.n"}="ht";
665         $bbtree{"_.v"}='';
666         $bbtree{"_.t"}="tg";
667         $bbtree{"_.e"}=0;
668         $bbtree{"_.c"}='';
669         $debug .= debug($printdebug, "\n<!--GENERATING BBCODE TREE:\n".'[_]automatic tag: [ht]'."\n");
670         
671         while ($bb ne '') {
672                 if($bb =~ m/(\[(\/?)([a-z]+|\*)(=([^\[\]]*))?\])/g) {
673                         $tag = $1;
674                         $tagend = $2;
675                         $tagname = $3;
676                         $tagvalue = $5;
677                         $pretext = substr($bb,0,pos ($bb)-length($tag));
678                         $bb = substr ($bb,pos ($bb));
679                         
680                         if ($pretext ne '') {
681                                 $debug .= debug($printdebug, '['.$ind.'.'.$bbtree{$ind.'.e'}.']text: '.$pretext."\n");
682                                 $bbtree{$ind.'.'.$bbtree{$ind.'.e'}.'.t'}='tx';
683                                 $bbtree{$ind.'.'.$bbtree{$ind.'.e'}.'.v'}=$pretext;
684                                 $bbtree{$ind.'.e'} += 1;
685                         }
686                         
687                         if($tagname =~ /^(fq|tq|br|ni|po|url|i|list|\*)$/) {
688                                 if ($tagend ne '') {
689                                         if(($tagname ne $bbtree{$ind.'.n'}) || ($level <= 0)) {
690                                                 $debug .= debug($printdebug, '['.$ind.'.'.$bbtree{$ind.'.e'}.']text: '.$tag."\n");
691                                                 $bbtree{$ind.'.'.$bbtree{$ind.'.e'}.'.t'}='tx';
692                                                 $bbtree{$ind.'.'.$bbtree{$ind.'.e'}.'.v'}=$tag;
693                                                 $bbtree{$ind.'.e'} += 1;
694                                         }
695                                         else {
696                                                 $debug .= debug($printdebug, '['.$ind.'.'.$bbtree{$ind.'.e'}.']tag: '.$tag."\n");
697                                                 $bbtree{$ind.'.'.$bbtree{$ind.'.e'}.'.t'}='tg';
698                                                 $bbtree{$ind.'.'.$bbtree{$ind.'.e'}.'.n'}='/'.$tagname;
699                                                 $bbtree{$ind.'.'.$bbtree{$ind.'.e'}.'.v'}=$tagvalue;
700                                                 $bbtree{$ind.'.e'} += 1;
701                                                 $bbtree{$ind.'.c'}=1;
702                                                 $level -= 1;
703                                                 $ind =~ s/\.[0-9]+$//;
704                                         }
705                                 }
706                                 else
707                                 {
708                                         $debug .= debug($printdebug, '['.$ind.'.'.$bbtree{$ind.'.e'}.']tag: '.$tag."\n");
709                                         $bbtree{$ind.'.'.$bbtree{$ind.'.e'}.'.t'}='tg';
710                                         $bbtree{$ind.'.'.$bbtree{$ind.'.e'}.'.n'}=$tagname;
711                                         $bbtree{$ind.'.'.$bbtree{$ind.'.e'}.'.v'}=$tagvalue;
712                                         $bbtree{$ind.'.'.$bbtree{$ind.'.e'}.'.e'}=0;
713                                         $bbtree{$ind.'.'.$bbtree{$ind.'.e'}.'.c'}='';
714                                         $bbtree{$ind.'.e'} += 1;
715                                         $level += 1;
716                                         $ind = $ind.'.'.($bbtree{$ind.'.e'}-1);
717                                 }
718                         }
719                         else {
720                                 $debug .= debug($printdebug, '['.$ind.'.'.$bbtree{$ind.'.e'}.']text: '.$tag."\n");
721                                 $bbtree{$ind.'.'.$bbtree{$ind.'.e'}.'.t'}='tx';
722                                 $bbtree{$ind.'.'.$bbtree{$ind.'.e'}.'.v'}=$tag;
723                                 $bbtree{$ind.'.e'} += 1;
724                         }
725                 }
726                 else {
727                         $debug .= debug($printdebug, '['.$ind.'.'.$bbtree{$ind.'.e'}.']text: '.$bb."\n");
728                         $bbtree{$ind.'.'.$bbtree{$ind.'.e'}.'.t'}='tx';
729                         $bbtree{$ind.'.'.$bbtree{$ind.'.e'}.'.v'}=$bb;
730                         $bbtree{$ind.'.e'} += 1;
731                         $bb='';
732                 }
733         }
734         $debug .= debug($printdebug, '[_.'.$bbtree{'_.e'}.']automatic tag: [/ht]'."\n -->\n");
735         $bbtree{'_.'.$bbtree{"_.e"}.'.t'}="tg";
736         $bbtree{'_.'.$bbtree{"_.e"}.'.n'}='/ht';
737         $bbtree{"_.e"}+=1;
738         $bbtree{"_.c"}=1;
739         
740         return ($debug, %bbtree);
741 }
742
743 #convert tag tree to final text
744 sub convtree {
745         (my $printdebug, my $debug, my $lang, my %bbtree) = @_;
746         my $ht;
747         my $ind;
748         my $indd;
749         my $level=0;
750         my $tagsr = ($lang eq 'html') ? tagsht : tagsbb;
751         my %tags = %$tagsr;
752         my $escape = ($lang eq 'html');
753         
754         # $debug .= debug($printdebug, "\n****\n");
755         # foreach my $iiii (keys %tags) {
756                 # $debug .= debug($printdebug, $iiii.'='.$tags{$iiii}."\n");
757         # }
758         # $debug .= debug($printdebug, "****\n");
759         
760         $level=0;
761         $ind='_';
762         $ht='';
763         $debug .= debug($printdebug, "\n<!--PROCESSING BBCODE TREE:\n");
764         
765         while ($level >=0) {
766                 $debug .= debug($printdebug, "[$level:$ind:".int($bbtree{$ind.'.e'})."]");
767                 #normal text
768                 if($bbtree{$ind.'.t'} eq 'tx') {
769                         $debug .= debug($printdebug, "text: ".$bbtree{$ind.'.v'});
770                         $ht = $ht.($escape?(linehtml($bbtree{$ind.'.v'})):($bbtree{$ind.'.v'}));
771                         
772                         {do{
773                                 $ind =~ s/\.([0-9]+)$//;
774                                 $indd = int($1)+1;
775                                 if ($indd < $bbtree{$ind.'.e'}){
776                                         $ind = $ind.'.'.$indd;
777                                         last;
778                                 }
779                                 else {
780                                         #should not occur with a correct bbtree
781                                         $debug .= debug($printdebug, "[<tx]");
782                                         $level -= 1;
783                                 }
784                         } while ($level>=0);}
785                 }
786                 #tag
787                 elsif($bbtree{$ind.'.t'} eq 'tg') {
788                         #endtag
789                         if($bbtree{$ind.'.n'} =~ /^\//) {
790                                 $debug .= debug($printdebug, "tag: [".$bbtree{$ind.'.n'}."]");
791                                 $indd = $ind;
792                                 $indd =~ s/\.([0-9]+)$//;
793                                 if (exists($tags{$bbtree{$ind.'.n'}.'='}) && ($bbtree{$indd.'.v'} ne '')) {
794                                         $ht = $ht.$tags{$bbtree{$ind.'.n'}.'='};
795                                 }
796                                 elsif (exists($tags{$bbtree{$ind.'.n'}})) {
797                                         $ht = $ht.$tags{$bbtree{$ind.'.n'}};
798                                 }
799                                 else {
800                                         $ht = $ht.$tags{'/?'};
801                                         $debug .= debug($printdebug, "[unknown!]");
802                                 }
803                                 
804                                 $ind =~ s/\.([0-9]+)$//;
805                                 $level -= 1;
806                                 $debug .= debug($printdebug, "[<]");
807                                 if($level>=0) {
808                                         {do{
809                                                 $ind =~ s/\.([0-9]+)$//;
810                                                 $indd = int($1)+1;
811                                                 if ($indd < $bbtree{$ind.'.e'}){
812                                                         $ind = $ind.'.'.$indd;
813                                                         last;
814                                                 }
815                                                 else {
816                                                         #should not occur with a correct bbtree
817                                                         $debug .= debug($printdebug, "[<nd]");
818                                                         $level -= 1;
819                                                 }
820                                         } while ($level>=0);}
821                                 }
822                                 else {
823                                         # time to end this
824                                         $level = -1;
825                                 }
826                         }
827                         #starttag
828                         else {
829                                 if($bbtree{$ind.'.c'} ne '') {
830                                         $debug .= debug($printdebug, "tag: [".$bbtree{$ind.'.n'}."]");
831                                         
832                                         if (exists($tags{$bbtree{$ind.'.n'}.'='}) && ($bbtree{$ind.'.v'} ne '')) {
833                                                 if (exists($tags{$bbtree{$ind.'.n'}.'='.$bbtree{$ind.'.v'}})) {
834                                                         $ht = $ht.$tags{$bbtree{$ind.'.n'}.'='}.$tags{$bbtree{$ind.'.n'}.'='.$bbtree{$ind.'.v'}}.$tags{$bbtree{$ind.'.n'}.'/='};
835                                                 }
836                                                 else {
837                                                         $ht = $ht.$tags{$bbtree{$ind.'.n'}.'='}.($escape?entityencode($bbtree{$ind.'.v'}):$bbtree{$ind.'.v'}).$tags{$bbtree{$ind.'.n'}.'/='};
838                                                 }
839                                         }
840                                         elsif (exists($tags{$bbtree{$ind.'.n'}})) {
841                                                 $ht = $ht.$tags{$bbtree{$ind.'.n'}};
842                                         }
843                                         else {
844                                                 $ht = $ht.$tags{'?'};
845                                                 $debug .= debug($printdebug, "[unknown!]");
846                                         }
847                                 }
848                                 else {
849                                         $debug .= debug($printdebug, "unclosed tag: [".$bbtree{$ind.'.n'}."]");
850                                         $ht = $ht.'['.($escape?linehtml($bbtree{$ind.'.n'}):$bbtree{$ind.'.n'}).']';
851                                 }
852                                 if($bbtree{$ind.'.e'}>0) {
853                                         $ind = $ind.'.0';
854                                         $level += 1;
855                                         $debug .= debug($printdebug, "[>]");
856                                 }
857                                 else {
858                                         {do{
859                                                 $ind =~ s/\.([0-9]+)$//;
860                                                 $indd = int($1)+1;
861                                                 if ($indd < $bbtree{$ind.'.e'}){
862                                                         $ind = $ind.'.'.$indd;
863                                                         last;
864                                                 }
865                                                 else {
866                                                         #should not occur with a correct bbtree
867                                                         $debug .= debug($printdebug, "[<st]");
868                                                         $level -= 1;
869                                                 }
870                                         } while ($level>=0);}
871                                 }
872                         }
873                 }
874                 #what is this
875                 else {
876                         $debug .= debug($printdebug, "unknown thing: ".$bbtree{$ind.'.t'});
877                         #should not occur with a correct bbtree
878                         #unless unimplemented
879                         $ind =~ s/\.([0-9]+)$//;
880                         $level -= 1;
881                         $debug .= debug($printdebug, "[<ui]");
882                         if($level>0) {
883                                 {do{
884                                         $ind =~ s/\.([0-9]+)$//;
885                                         $indd = int($1)+1;
886                                         if ($indd < $bbtree{$ind.'.e'}){
887                                                 $ind = $ind.'.'.$indd;
888                                                 last;
889                                         }
890                                         else {
891                                                 #should not occur with a correct bbtree
892                                                 $debug .= debug($printdebug, "[<un]");
893                                                 $level -= 1;
894                                         }
895                                 } while ($level>=0);}
896                         }
897                         else {
898                                 # time to end this
899                                 $level = -1;
900                         }
901                 }
902                 $debug .= debug($printdebug, "[>$level:$ind]\n");
903         }
904         
905         $debug .= debug($printdebug, "-->\n");
906         return ($debug, $ht);
907 }
908
909 #bbcode to html, TBD
910 sub bb2ht {
911         (my $bb, my $printdebug) = @_;
912         my $ht;
913         my %bbtree;
914         my $debug;
915         
916         ($debug, %bbtree) = bbtree($bb,$printdebug);
917         ($debug, $ht) = convtree ($printdebug, $debug, 'html', %bbtree);
918         
919         return $ht;
920         
921         # $level=0;
922         # $ind='_';
923         # $ht='';
924         # $debug .= debug($printdebug, "\n<!--PROCESSING BBCODE TREE:\n");
925         
926         # while ($level >=0) {
927                 # $debug .= debug($printdebug, "[$level:$ind:".int($bbtree{$ind.'.e'})."]");
928                 # if($bbtree{$ind.'.t'} eq 'tx') {
929                         # $debug .= debug($printdebug, "text: ".$bbtree{$ind.'.v'});
930                         # $ht = $ht.linehtml($bbtree{$ind.'.v'});
931                         
932                         # {do{
933                                 # $ind =~ s/\.([0-9]+)$//;
934                                 # $indd = int($1)+1;
935                                 # if ($indd < $bbtree{$ind.'.e'}){
936                                         # $ind = $ind.'.'.$indd;
937                                         # last;
938                                 # }
939                                 # else {
940                                         # #should not occur with a correct bbtree
941                                         # $debug .= debug($printdebug, "[<tx]");
942                                         # $level -= 1;
943                                 # }
944                         # } while ($level>=0);}
945                 # }
946                 # elsif($bbtree{$ind.'.t'} eq 'tg') {
947                         # if($bbtree{$ind.'.n'} =~ /^\//) {
948                                 # $debug .= debug($printdebug, "tag: [".$bbtree{$ind.'.n'}."]");
949                                 # if($bbtree{$ind.'.n'} eq '/ht') {
950                                         # #
951                                 # }
952                                 # elsif ($bbtree{$ind.'.n'} =~ /^\/(fq|tq)$/) {
953                                         # $ht = $ht.'</div>';
954                                 # }
955                                 # elsif ($bbtree{$ind.'.n'} =~ /^\/(br|ni|po)$/) {
956                                         # $ht = $ht.'</span>';
957                                 # }
958                                 # elsif ($bbtree{$ind.'.n'} eq '/url') {
959                                         # $ht = $ht.'</a>';
960                                 # }
961                                 # elsif ($bbtree{$ind.'.n'} eq '/i') {
962                                         # $ht = $ht.'</i>';
963                                 # }
964                                 # else { #unimpl.
965                                         # $ht = $ht.'['.linehtml($bbtree{$ind.'.n'}).']';
966                                         # $debug .= debug($printdebug, "[unknown!]");
967                                 # }
968                                 # $ind =~ s/\.([0-9]+)$//;
969                                 # $level -= 1;
970                                 # $debug .= debug($printdebug, "[<]");
971                                 # if($level>=0) {
972                                         # {do{
973                                                 # $ind =~ s/\.([0-9]+)$//;
974                                                 # $indd = int($1)+1;
975                                                 # if ($indd < $bbtree{$ind.'.e'}){
976                                                         # $ind = $ind.'.'.$indd;
977                                                         # last;
978                                                 # }
979                                                 # else {
980                                                         # #should not occur with a correct bbtree
981                                                         # $debug .= debug($printdebug, "[<nd]");
982                                                         # $level -= 1;
983                                                 # }
984                                         # } while ($level>=0);}
985                                 # }
986                                 # else {
987                                         # # time to end this
988                                         # $level = -1;
989                                 # }
990                         # }
991                         # else {
992                                 # if($bbtree{$ind.'.c'} ne '') {
993                                         # if($bbtree{$ind.'.n'} eq 'ht') {
994                                                 # #
995                                         # }
996                                         # elsif($bbtree{$ind.'.n'} eq 'fq') {
997                                                 # $ht = $ht.'<div class="fq">';
998                                         # }
999                                         # elsif($bbtree{$ind.'.n'} eq 'tq') {
1000                                                 # $ht = $ht.'<div class="tq">';
1001                                         # }
1002                                         # elsif($bbtree{$ind.'.n'} eq 'br') {
1003                                                 # $ht = $ht.'<span class="br">';
1004                                         # }
1005                                         # elsif($bbtree{$ind.'.n'} eq 'ni') {
1006                                                 # $ht = $ht.'<span class="ni">';
1007                                         # }
1008                                         # elsif($bbtree{$ind.'.n'} eq 'po') {
1009                                                 # $ht = $ht.'<span class="po">';
1010                                         # }
1011                                         # elsif($bbtree{$ind.'.n'} eq 'i') {
1012                                                 # $ht = $ht.'<i>';
1013                                         # }
1014                                         # elsif($bbtree{$ind.'.n'} eq 'url') {
1015                                                 # $ht = $ht.'<a href="'.entityencode($bbtree{$ind.'.v'}).'">';
1016                                         # }
1017                                         # else { #unimpl.
1018                                                 # $ht = $ht.'['.linehtml($bbtree{$ind.'.n'}).(($bbtree{$ind.'.v'} ne '' )?entityencode($bbtree{$ind.'.v'}):'').']';
1019                                                 # $debug .= debug($printdebug, "[unknown!]");
1020                                         # }
1021                                 # }
1022                                 # else {
1023                                         # $debug .= debug($printdebug, "unclosed tag: [".$bbtree{$ind.'.n'}."]");
1024                                         # $ht = $ht.'['.linehtml($bbtree{$ind.'.n'}).']';
1025                                 # }
1026                                 # if($bbtree{$ind.'.e'}>0) {
1027                                         # $ind = $ind.'.0';
1028                                         # $level += 1;
1029                                         # $debug .= debug($printdebug, "[>]");
1030                                 # }
1031                                 # else {
1032                                         # {do{
1033                                                 # $ind =~ s/\.([0-9]+)$//;
1034                                                 # $indd = int($1)+1;
1035                                                 # if ($indd < $bbtree{$ind.'.e'}){
1036                                                         # $ind = $ind.'.'.$indd;
1037                                                         # last;
1038                                                 # }
1039                                                 # else {
1040                                                         # #should not occur with a correct bbtree
1041                                                         # $debug .= debug($printdebug, "[<st]");
1042                                                         # $level -= 1;
1043                                                 # }
1044                                         # } while ($level>=0);}
1045                                 # }
1046                         # }
1047                 # }
1048                 # else {
1049                         # $debug .= debug($printdebug, "unknown thing: ".$bbtree{$ind.'.t'});
1050                         # #should not occur with a correct bbtree
1051                         # #unless unimplemented
1052                         # $ind =~ s/\.([0-9]+)$//;
1053                         # $level -= 1;
1054                         # $debug .= debug($printdebug, "[<ui]");
1055                         # if($level>0) {
1056                                 # {do{
1057                                         # $ind =~ s/\.([0-9]+)$//;
1058                                         # $indd = int($1)+1;
1059                                         # if ($indd < $bbtree{$ind.'.e'}){
1060                                                 # $ind = $ind.'.'.$indd;
1061                                                 # last;
1062                                         # }
1063                                         # else {
1064                                                 # #should not occur with a correct bbtree
1065                                                 # $debug .= debug($printdebug, "[<un]");
1066                                                 # $level -= 1;
1067                                         # }
1068                                 # } while ($level>=0);}
1069                         # }
1070                         # else {
1071                                 # # time to end this
1072                                 # $level = -1;
1073                         # }
1074                 # }
1075                 # $debug .= debug($printdebug, "[>$level:$ind]\n");
1076         # }
1077         
1078         # $debug .= debug($printdebug, "-->\n");
1079         # # print $debug;
1080         
1081         
1082         
1083 }
1084
1085 #bbcode to bb, TBD
1086 sub bb2bb {
1087         (my $bb, my $printdebug) = @_;
1088         my $ht;
1089         my %bbtree;
1090         my $debug;
1091         
1092         ($debug, %bbtree) = bbtree($bb,$printdebug);
1093         ($debug, $ht) = convtree ($printdebug, $debug, 'bb', %bbtree);
1094         
1095         return $ht;
1096         
1097         # $level=0;
1098         # $ind='_';
1099         # $ht='';
1100         # $debug .= debug($printdebug, "\n<!--PROCESSING BBCODE TREE:\n");
1101         
1102         # while ($level >=0) {
1103                 # $debug .= debug($printdebug, "[$level:$ind:".int($bbtree{$ind.'.e'})."]");
1104                 # if($bbtree{$ind.'.t'} eq 'tx') {
1105                         # $debug .= debug($printdebug, "text: ".$bbtree{$ind.'.v'});
1106                         # $ht = $ht.$bbtree{$ind.'.v'};
1107                         
1108                         # {do{
1109                                 # $ind =~ s/\.([0-9]+)$//;
1110                                 # $indd = int($1)+1;
1111                                 # if ($indd < $bbtree{$ind.'.e'}){
1112                                         # $ind = $ind.'.'.$indd;
1113                                         # last;
1114                                 # }
1115                                 # else {
1116                                         # #should not occur with a correct bbtree
1117                                         # $debug .= debug($printdebug, "[<tx]");
1118                                         # $level -= 1;
1119                                 # }
1120                         # } while ($level>=0);}
1121                 # }
1122                 # elsif($bbtree{$ind.'.t'} eq 'tg') {
1123                         # if($bbtree{$ind.'.n'} =~ /^\//) {
1124                                 # $debug .= debug($printdebug, "tag: [".$bbtree{$ind.'.n'}."]");
1125                                 # if($bbtree{$ind.'.n'} eq '/ht') {
1126                                         # #
1127                                 # }
1128                                 # elsif ($bbtree{$ind.'.n'} =~ /^\/(fq|tq)$/) {
1129                                         # $ht = $ht.'[/quote]';
1130                                 # }
1131                                 # elsif ($bbtree{$ind.'.n'} =~ /^\/(br|ni|po)$/) {
1132                                         # $ht = $ht.'[/color]';
1133                                 # }
1134                                 # elsif ($bbtree{$ind.'.n'} eq '/url') {
1135                                         # $ht = $ht.'[/url]';
1136                                 # }
1137                                 # elsif ($bbtree{$ind.'.n'} eq '/i') {
1138                                         # $ht = $ht.'[/i]';
1139                                 # }
1140                                 # else { #unimpl.
1141                                         # $ht = $ht.'['.$bbtree{$ind.'.n'}.']';
1142                                         # $debug .= debug($printdebug, "[unknown!]");
1143                                 # }
1144                                 # $ind =~ s/\.([0-9]+)$//;
1145                                 # $level -= 1;
1146                                 # $debug .= debug($printdebug, "[<]");
1147                                 # if($level>0) {
1148                                         # {do{
1149                                                 # $ind =~ s/\.([0-9]+)$//;
1150                                                 # $indd = int($1)+1;
1151                                                 # if ($indd < $bbtree{$ind.'.e'}){
1152                                                         # $ind = $ind.'.'.$indd;
1153                                                         # last;
1154                                                 # }
1155                                                 # else {
1156                                                         # #should not occur with a correct bbtree
1157                                                         # $debug .= debug($printdebug, "[<nd]");
1158                                                         # $level -= 1;
1159                                                 # }
1160                                         # } while ($level>=0);}
1161                                 # }
1162                                 # else {
1163                                         # # time to end this
1164                                         # $level = -1;
1165                                 # }
1166                         # }
1167                         # else {
1168                                 # if($bbtree{$ind.'.c'} ne '') {
1169                                         # $debug .= debug($printdebug, "tag: [".$bbtree{$ind.'.n'}."]");
1170                                         # if($bbtree{$ind.'.n'} eq 'ht') {
1171                                                 # #
1172                                         # }
1173                                         # elsif($bbtree{$ind.'.n'} =~ /^(fq|tq)$/) {
1174                                                 # $ht = $ht.'[quote]';
1175                                         # }
1176                                         # elsif($bbtree{$ind.'.n'} eq 'br') {
1177                                                 # $ht = $ht.'[color=#BB6622]';
1178                                         # }
1179                                         # elsif($bbtree{$ind.'.n'} eq 'po') {
1180                                                 # $ht = $ht.'[color=#FF8800]';
1181                                         # }
1182                                         # elsif($bbtree{$ind.'.n'} eq 'ni') {
1183                                                 # $ht = $ht.'[color=#0057AF]';
1184                                         # }
1185                                         # elsif($bbtree{$ind.'.n'} eq 'url') {
1186                                                 # $ht = $ht.'[url='.$bbtree{$ind.'.v'}.']';
1187                                         # }
1188                                         # elsif($bbtree{$ind.'.n'} eq 'i') {
1189                                                 # $ht = $ht.'[i]';
1190                                         # }
1191                                         # else { #unimpl.
1192                                                 # $ht = $ht.'['.$bbtree{$ind.'.n'}.(($bbtree{$ind.'.v'} ne '' )?($bbtree{$ind.'.v'}):'').']';
1193                                                 # $debug .= debug($printdebug, "[unknown!]");
1194                                         # }
1195                                 # }
1196                                 # else {
1197                                         # $debug .= debug($printdebug, "unclosed tag: [".$bbtree{$ind.'.n'}."]");
1198                                         # $ht = $ht.'['.$bbtree{$ind.'.n'}.']';
1199                                 # }
1200                                 # if($bbtree{$ind.'.e'}>0) {
1201                                         # $ind = $ind.'.0';
1202                                         # $level += 1;
1203                                         # $debug .= debug($printdebug, "[>]");
1204                                 # }
1205                                 # else {
1206                                         # {do{
1207                                                 # $ind =~ s/\.([0-9]+)$//;
1208                                                 # $indd = int($1)+1;
1209                                                 # if ($indd < $bbtree{$ind.'.e'}){
1210                                                         # $ind = $ind.'.'.$indd;
1211                                                         # last;
1212                                                 # }
1213                                                 # else {
1214                                                         # #should not occur with a correct bbtree
1215                                                         # $debug .= debug($printdebug, "[<st]");
1216                                                         # $level -= 1;
1217                                                 # }
1218                                         # } while ($level>=0);}
1219                                 # }
1220                         # }
1221                 # }
1222                 # else {
1223                         # $debug .= debug($printdebug, "unknown thing: ".$bbtree{$ind.'.t'});
1224                         # #should not occur with a correct bbtree
1225                         # #unless unimplemented
1226                         # $ind =~ s/\.([0-9]+)$//;
1227                         # $level -= 1;
1228                         # $debug .= debug($printdebug, "[<ui]");
1229                         # if($level>0) {
1230                                 # {do{
1231                                         # $ind =~ s/\.([0-9]+)$//;
1232                                         # $indd = int($1)+1;
1233                                         # if ($indd < $bbtree{$ind.'.e'}){
1234                                                 # $ind = $ind.'.'.$indd;
1235                                                 # last;
1236                                         # }
1237                                         # else {
1238                                                 # #should not occur with a correct bbtree
1239                                                 # $debug .= debug($printdebug, "[<un]");
1240                                                 # $level -= 1;
1241                                         # }
1242                                 # } while ($level>=0);}
1243                         # }
1244                         # else {
1245                                 # # time to end this
1246                                 # $level = -1;
1247                         # }
1248                 # }
1249                 # $debug .= debug($printdebug, "[>$level:$ind]\n");
1250         # }
1251         
1252         # $debug .= debug($printdebug, "-->\n");
1253         # # print $debug;
1254         
1255         
1256         
1257 }
1258
1259 sub linehtml {
1260         (my $ht) = @_;
1261         my $esc;
1262         my $ind;
1263         
1264         $ht =~ s/\r\n/\n/g;
1265         $ht =~ s/\r/\n/g;
1266         
1267         while ($ht ne '') {
1268                 $ind = index($ht,"\n");
1269                 if($ind>=0){
1270                         $esc = $esc.entityencode(substr($ht,0,$ind))."<br>\n";
1271                         $ht=substr($ht,$ind+1);
1272                 }
1273                 else
1274                 {
1275                         $esc = $esc.entityencode($ht);
1276                         $ht = '';
1277                 }
1278         }
1279         return $esc;
1280 }
1281
1282 sub debug {
1283         (my $print, my $text) = @_;
1284         
1285         if ($print) {
1286                 print $text;
1287         }
1288         
1289         return $text;
1290 }
1291
1292 1