1 eval 'exec perl -S $0 ${1+"$@"}'
2 if $running_under_some_shell;
4 #-----------------------------------------------------------------------------
6 # setext.pl -- Structure Enhanced Text Converter (to HTML or simple text)
8 # $Id: setext,v 1.11 2003/11/22 13:03:38 edg Exp $
10 # Copyright (c) 2000 Steven Haehn
12 # This is free software; you can redistribute it and/or modify it under the
13 # terms of the GNU General Public License as published by the Free Software
14 # Foundation; either version 2 of the License, or (at your option) any later
17 # This software is distributed in the hope that it will be useful, but WITHOUT
18 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
22 # You should have received a copy of the GNU General Public License along with
23 # software; if not, write to the Free Software Foundation, Inc., 59 Temple
24 # Place, Suite 330, Boston, MA 02111-1307 USA
26 #-----------------------------------------------------------------------------
28 # The concept of setext documents is the brain child of Ian Feldman.
29 # Some typotag terms used herein were originally implemented in a perl script
30 # by Tony Sanders, which is the inspirational source for this work.
31 # This perl script understands the original typotags, plus extras needed for
32 # hypertext links, conditional text, and variables.
34 # Samples of setext documents are regularly provided to those folks which
35 # receive the TidBITS publication from www.tidbits.com in their e-mail.
37 # This program is really two programs crammed into one file. The two separate
38 # pieces share lots of code. Instead of having 3 separate files, one of
39 # them being a perl library with the shared code, there was a desire to keep
40 # everything rolled up in one suitcase.
42 #-----------------------------------------------------------------------------
44 # GENERAL TRANSLATOR ROUTINES NEDIT HELP SOURCE CODE GENERATION ROUTINES
46 # check_target_reference collect_internal_hypertext_references
47 # count emit_copyright
49 # emit_paragraph emit_helpTitles
50 # emit_setext_definition emit_help_header
51 # extract_fields emit_help_label
52 # extract_menu_info emit_help_menu
53 # extract_menu_init emit_help_menu_text
54 # get_menu_item emit_help_topic
55 # get_setext get_menu_text
56 # is_member get_newline
57 # parse_setext get_style
58 # preserve_html get_style_name
59 # recover_extractions is_known_link
60 # replace_underlines locate_menu_text
61 # show_usage make_NEdit_menu_code
66 # TYPOTAG TRANSLATION ROUTINES
68 # help_bold_tt text_bold_tt html_bold_tt
69 # help_bullet_tt text_bullet_tt html_bullet_tt
70 # help_emit_line text_emit_line html_emit_line
71 # help_final text_final html_final
72 # help_finishing text_finishing html_finishing
73 # help_hot_tt text_hot_tt html_hot_tt
74 # help_indent text_indent html_indent
75 # help_init text_init html_init, html_init_title
76 # help_italic_tt text_italic_tt html_italic_tt
77 # help_line_break text_line_break html_line_break
78 # help_list_tt text_list_tt html_list_tt
79 # help_line_tt text_line_tt html_line_tt
80 # help_quote_tt text_quote_tt html_quote_tt
81 # help_section_tt text_section_tt html_section_tt
82 # help_target_tt text_target_tt html_target_tt
83 # help_title text_title html_title
84 # help_underline_tt text_underline_tt html_underline_tt
86 # help_fixed_styles html_enter_list, html_leave_list
87 # help_proportional_styles html_enter_pre, html_leave_pre
88 # fix_target_tt html_enter_quote, html_leave_quote
89 # html_emit_header, html_emit_footer
92 #-----------------------------------------------------------------------------
94 use Getopt::Long; # for parsing the program command line (GetOptions)
95 use File::Basename; # for trimming off directory names from files (basename)
98 #-------------------------------------------------------------------------------
103 my $date = "Oct 01, 2003";
105 print "$pgm: Version $version, $date.\n";
109 #-------------------------------------------------------------------------------
114 print "Usage: $pgm [ -dhtTVw ][-D directory][-H [hfile]][-S [htmlExt]] \\\n";
115 print " [-c conditional][-v name=value][setext_file [converted_file]]\n";
117 print " $pgm {-mp} [-c conditional][-M menuSuffix][-v name=value] setext_file\n";
119 print " The first form of $pgm is used to convert Structure Enhanced TEXT\n";
120 print " documents into HTML or simple text documents.\n";
121 print " The second form is specific to generating NEdit help menu code\n";
122 print " from a setext document with Menu and Help directives.\n";
124 print " -c conditional text definitions, separated by commas.\n";
125 print " -d do not automatically make titles hypertext references (HTML only)\n";
126 print " -D specify destination directory for separate HTML files. This also sets\n";
127 print " the value for the variable HTML_DIR.\n";
128 print " -h show this usage clause.\n";
129 print " -H convert setext_file to HyperText Markup Language (HTML).\n";
130 print " Optional file parameter specifies file containing HTML header\n";
131 print " and footer definition overrides. The current defaults are:\n";
132 print " \$htmlHeader = <HTML>\n";
133 print " <TITLE>\$HTML_TITLE</TITLE>\n";
134 print " <HEAD></HEAD>\n";
136 print " \$htmlFooter = </BODY>\n";
138 print " where \$HTML_TITLE is replaced with an appropriate title.\n\n";
139 print " -m generate NEdit help menu code files.\n";
140 print " -M name NEdit help code files with this suffix.\n";
141 print " -p do option -m and print out NEdit help elements.\n";
142 print " -S convert setext_file into separate HTML files.\n";
143 print " (the default name extension is '$htmlExt', but it can be\n";
144 print " changed by specifying it as an argument to this option)\n";
145 print " -t convert setext_file to simple text (default).\n";
146 print " -T emit setext typotag definitions in use.\n";
147 print " -v defines variable name and assigns it the given value.\n";
148 print " (more than one occurrence of -v can be made) The variables\n";
149 print " are made available for use within the setext document parsing.\n";
150 print " -V display the version of this setext script.\n";
151 print " -w do not emit warnings about missing variables.\n";
153 print " When the converted_file argument is missing, STDOUT is used.\n";
154 print " When the setext_file argument is missing, STDIN is used.\n";
156 print " To get conditional text within a setext document to be displayed,\n";
157 print " supply a definition tag through the -c option. For example,\n";
159 print " $pgm -c NEDITDOC help.etx nedit.doc\n";
161 print " would generate a plain text document, nedit.doc, from the source\n";
162 print " help.etx, including/excluding text marked with 'NEDITDOC'\n";
163 print " conditional text markers, also known as 'maybe' typotags.\n";
169 #---------------------------------------------------------------------------
170 # This is a GetOptions call back function for gleaning variables from
171 # the command line so that they can be available to the setext parsing
172 # without having to appear in the setext document. The expected form
173 # on the command line is: -v variableName=value. For example, -v version=5.2
174 #---------------------------------------------------------------------------
177 my $optionName = shift;
178 my $optionValue = shift;
179 my ( $varName, $varValue ) = split( "=", $optionValue );
182 print STDERR "Missing value for variable '$varName'\n";
183 $Getopt::Long::error++;
187 #-----------------------------------------------------
188 # By trimming off leading and trailing spaces allows
189 # data entry like this: "version = 5.2 of Oct. 2001".
190 #-----------------------------------------------------
191 $varName =~ s/$trim_spaces/$2/o;
192 $varValue =~ s/$trim_spaces/$2/o;
194 $variables{ $varName } = $varValue;
197 #-------------------------------------------------------------------------------
199 sub emit_setext_definition
201 print <<END_OF_DEFINITION_TEXT;
206 The following table contains typotags recognized by
207 $pgm. The "setext form" column in the table
208 is formatted such that the left most character of
209 the column represents the first character in a line
210 of setext. The circumflex character (^) means that
211 the characters of the typotag are significant only
212 when they are anchored to the front of the setext
213 line. This definition is a sample of a setext document.
214 Consequently, it must be put through the program so
215 that you can view the actual "setext form" of some
216 of the typotags. Thus, issue the following commands
217 to get a proper text view of the table below.
219 $pgm -T > typotags.etx
222 ============ =================== ==================
223 ! name of setext form acted upon or
224 ! the typotag of typotag displayed as
225 !============ =================== ==================
226 ! title-tt "Title a title
227 ! =====" in chosen style
228 !------------ ------------------- ------------------
229 ! subhead-tt "Subhead a subhead
230 ! -------" in chosen style
231 !------------ ------------------- ------------------
232 ! section-tt ^#> section-text a section heading
235 !------------ ------------------- ------------------
236 ! indent-tt ^ lines indented lines undented
237 ! ^ by 2 spaces and unfolded
238 !------------ ------------------- ------------------
239 ! bold-tt **[multi]word** 1+ bold word(s)
240 ! italic-tt ~multi word~ 1+ italic word(s)
241 !underline-tt [_multi]_word_ underlined text
242 ! hot-tt [multi_]word_ 1+ hot word(s)
243 ! quote-tt ^>[space][text] > [mono-spaced]
244 ! bullet-tt ^*[space][text] [bullet] [text]
245 ! untouch-tt `_quoted typotag!_` `_left alone!_`
246 ! notouch-tt ^!followed by text text-left-alone
247 ! field-tt |>name[=value]<| value of name
248 ! line-tt ^ --- horizontal rule
249 !------------ ------------------- ------------------
250 ! list-tt .([space]list start multiple line list
253 ! endlist-tt .) denotes list end
254 !------------ ------------------- ------------------
255 ! href-tt ^.. \@_word URL jump to address
256 ! note-tt ^.. \@_word Note:("*") ("cause error")
257 ! target-tt \@_[multi_]word [multi ]word
258 !------------ ------------------- ------------------
259 ! twobuck-tt \$\$ [last on a line] [parse another]
260 ! suppress-tt ^..[space][not dot] [line hidden]
261 ! twodot-tt ^..[alone on a line] [taken note of]
262 !------------ ------------------- ------------------
263 ! maybe-tt ^.. ? name[~] text show text when
265 ! maybenot-tt ^.. ! name[~] text show text when
267 ! endmaybe-tt ^.. ~ name end of a multi-
269 !------------ ------------------- ------------------
270 ! passthru-tt ^!![text] text emitted
272 !------------ ------------------- ------------------
273 ! escape-tt @\@x where 'x' is x is what remains
274 ! escaped character @@@@ needed for 1 @@
275 ============ =================== ==================
277 Only one instance of the element subhead-tt (or, in its
278 absence, title-tt) is absolutely _required_ for a text to
279 be considered a valid setext.
281 All the elements, but subhead-tt, are in effect optional,
282 that is, not necessary for a setext to be declared as
283 such. The target-tt element allows the hypertext link
284 definition of href-tt to be within the same setext. The
285 actual reference (href-tt) of the target would look like:
287 .. _word #reference_within_document
289 !Multiple line maybe[not]-tt (conditional text regions)
290 !are introduced as ".. ? name~" or ".. ! name~" and are
291 !terminated with ".. ~ name", on a separate line. Single
292 !line maybe[not]-tt do not use the '~' character and are
293 !terminated with the end of the line. The special
294 !conditional text region named "html" allows a mixture of
295 !setext and HTML tags. Nesting of these typotags is
296 !allowed. For instance, if there are three conditional
297 !regions, A, B, and C, C can be nested inside B, which can
298 !be nested inside A (eg. A-B-C...C-B-A). Note that a
299 !surrounding region cannot end before one of its inner
300 !regions is terminated (eg. of illegal nesting
301 !A-B-C...C-A-B, where A terminated prior to B.
303 Multiple line list-tt are introduced as ".(". Each line
304 belongs to the current list element until an empty line
305 is encountered. Once a list-tt is encountered, line
306 separated paragraphs constitute list elements. A list-tt
307 is terminated by endlist-tt. The list-tt/endlist-tt
308 typotags are allowed to be nested (unlike the bullet-tt).
309 These typo-tags do not have to start in the first column
310 of a line, but must have leading whitespace if they are
313 Field typotags are used to define and reference values.
314 Field definitions can only occur within a suppress-tt.
315 For example: ".. `|>author=Steven Haehn<|`"
316 Field references (eg. |>author<|) can occur in any
317 printable text. If there is no known value for the
318 field, it will remain unchanged and appear as written
320 END_OF_DEFINITION_TEXT
322 #---------------------------------------------------------------
323 # Emit any predefined variables so user knows what is available.
324 #---------------------------------------------------------------
328 print " The following are predefined for use in a field-tt\n";
329 print " for any setext document translated by this utility.\n";
332 foreach $key ( sort keys %variables )
334 print " $key = $variables{$key}\n";
342 #-------------------------------------------------------------------------------
344 $pgm = basename( $PROGRAM_NAME );
346 #==========================
347 # Global shared definitions
348 #==========================
349 $um = "\375"; # untouchable marker
350 $vm = "\374"; # variable marker
351 $escMrk = "\33"; # internal escape marker
352 $trim_spaces = '(\s*)(.*?)(\s*)$';
355 @bullet_list = qw( * * o + * o + * o + );
356 %variables = ( date => &date(), Date => &date("D"), year => &date("y") );
357 @cond_text_definitions = ();
358 $make_title_href = 1;
360 #---------------------------------------
361 # Variables needed for HTML conversions.
362 #---------------------------------------
363 $lt = "\376"; # "<" marker
364 $gt = "\377"; # ">" marker
365 $amp = "\373"; # "&" marker
366 $htmlExt = "html"; # default HTML file name extension
370 "<TITLE>\$HTML_TITLE</TITLE>\n" .
374 $htmlFooter = "</BODY>\n</HTML>\n";
376 #---------------------------------------------------------
377 # Look for following options, complain about unknown ones.
378 #---------------------------------------------------------
379 Getopt::Long::config( "noignorecase" );
383 'c=s', # conditional text definitions, separated by commas
384 'd', # do not make titles hypertext references (HTML only)
385 'D=s', # specify destination directory for separate HTML files
387 'H:s', # create HTML from setext input
388 'm', # create NEdit help menu code from setext input
389 'M=s', # name NEdit help code files with this suffix
390 'p', # same as 'm' but with debug printout
391 'S:s', # generate separate HTML files for each subsection
392 't', # create text from setext input
393 'T', # emit setext typo-tag document
394 'v=s', \&declare_variable,
395 'V', # emit setext script version information
396 'w' # do not emit warning messages.
400 #-----------------------------------
401 # Glean only those options specified
402 #-----------------------------------
403 $opt_c && (@cond_text_definitions = split( ",", $opt_c ));
404 $opt_d && ($make_title_href=0);
405 $opt_D && do { $variables{HTML_DIR}=$opt_D; $outputDirectory="$opt_D/" };
406 $opt_h && show_usage();
407 defined $opt_H && do { $convert_to = "html"; getHtmlAttributes( $opt_H ) };
408 $opt_m && do { $make_menu = 1; $convert_to = "help" };
409 $opt_M && ($helpSuffix = $opt_M );
410 $opt_p && do { $make_menu = 1; $convert_to = "help"; $print_menu = 1 };
411 defined $opt_S && do {
412 $convert_to = "html";
413 $htmlExt = $opt_S if $opt_S; # user can specify file extension
414 $separate_html_files=1;
417 $opt_t && ($convert_to = "text");
418 $opt_T && emit_setext_definition();
419 $opt_V && (emit_version());
420 $opt_w && ($noWarn = 1);
422 #--------------------------------------------------------------
423 # Setext Parser states.
425 # The names are used to construct "enter_" & "leave_" elements
426 # in the state_change hash table required to be initialized
427 # by language specific initialization routines (see html_init).
428 #--------------------------------------------------------------
434 #----------------------------
435 # Typotag Pattern Definitions
436 #----------------------------
437 $bold_tt = '\*\*([^\*]+)\*\*([^\*]|$)';
438 $bullet_tt = '^\* ([^ ])';
439 $empty_line = '^\s*$';
442 $field_tt = "(${fld_left}.+?$fld_right)";
443 $field_content = "${fld_left}(.+?)$fld_right";
444 #$field_tt = "(${fld_left}[^<]+$fld_right)";
445 #$field_content = "${fld_left}([^<]+)$fld_right";
446 $hot_tt = '\b([\S]*)_\b';
447 $href_tt = '^\.\.\s+_([\S]*)\s+(.*)\s*';
448 $indent_tt = '^ ([^ ])';
450 $internal_href = "^$intHrefMrk(.*)\$";
451 $italic_tt = '~([^~]*)~';
452 $line_tt = '^ ---*$';
453 $list_tt = '^\s*\.([()])';
455 $passthru_tt = '^!!';
457 $section_tt = '^([1-6])>';
458 $subtitle_tt = '^---';
459 $suppress_tt = '^\.\.';
460 $target_tt = '(?!(^|\s)_[\S]+_(\s|\W|$))(^|\s)_([\S]+)'; # not underline, then target
462 $twobuck_tt = '^\s*\$\$\s*$';
463 $underline_tt = '\b_([\S]*)_\b';
464 $untouch_tt = "\\s*(`[^`]+[`'])(?=\\s|\\W|\$)";
465 $variable_def = '\s*(\w+)\s*([^=]*(=(.*)))?'; # $1 = name, $4 = value
467 $escape_tt = "@"; # the character escape symbol (need @@ to escape @)
468 $needEscaping = "$escape_tt(.)";
469 $escapedFound = "$escMrk(\\d+)$escMrk";
473 $setext_file = $ARGV[0];
474 open SETEXT, "<$setext_file" or die "Can't access $setext_file, $OS_ERROR";
475 make_NEdit_menu_code();
477 else # Global elements for parsing setext
479 #-------------------------
480 # Program option defaults.
481 #-------------------------
482 $setext_file = "-"; # STDIN, allows program to be used as a filter
483 $converted_file = "-"; # STDOUT
484 $convert_to = "text" if $convert_to eq "";
486 #--------------------------------------
487 # Begin processing file specifications.
488 #--------------------------------------
489 $setext_file = $ARGV[0] if $ARGV[0] ne "";
490 open SETEXT, "<$setext_file" or die "Can't access $setext_file, $OS_ERROR";
494 $converted_file = $ARGV[1];
495 $convert_to = "html" if $converted_file =~ /\.$htmlExt$/; # in case -H forgotten
497 if( $converted_file eq basename( $converted_file ) )
499 if( $outputDirectory )
501 $converted_file = "$outputDirectory/$converted_file";
506 open CONVERT, ">$converted_file" or die "Can't create $converted_file, $OS_ERROR";
510 #-------------------------------------------------------------------------------
511 #-------------------------------------------------------------------------------
512 #-------------------------------------------------------------------------------
516 #--------------------------------------
517 # Adding conversion type to conditional
518 # text definitions for convenience.
519 #--------------------------------------
520 push @cond_text_definitions, $convert_to;
522 get_setext( SETEXT, \@cond_text_definitions, \@data );
524 extract_menu_info( \@data )
525 if( $convert_to eq "html" && $separate_html_files );
527 chomp @data; # remove the newline character from each line.
529 register_tt_translationFunctions( $convert_to );
531 parse_setext( \@data );
534 #-------------------------------------------------------------------------------
536 sub make_NEdit_menu_code
538 #--------------------------------
539 # Supply a default NEdit version.
540 #--------------------------------
541 $neditDefaultMarker = "NEdit release of ";
542 $variables{ version } = $neditDefaultMarker . date()
543 if (not exists $variables{ version } or
544 $variables{ version } eq "default");
546 #--------------------------------------
547 # Adding conversion type to conditional
548 # text definitions for convenience.
549 #--------------------------------------
550 push @cond_text_definitions, $convert_to;
552 get_setext( SETEXT, \@cond_text_definitions, \@data );
553 extract_menu_info( \@data );
554 register_tt_translationFunctions( $convert_to );
557 #-------------------------------------------------------------------------------
561 my $setextData = shift;
563 local($crnt_state, $fold, $a, $i, $unt, $lineNo);
570 foreach (@$setextData)
572 $lineNo++; # current location in data array
574 #--------------------------
575 # process title information
576 #--------------------------
577 (/$title_tt/i or /$subtitle_tt/i) && do {
583 /$section_tt/o && do {
589 /$passthru_tt/ && do {
594 next if ( /$suppress_tt/ or /$twobuck_tt/ );
596 $list_level = 0 if $list_level < 0; # paranoia protection
598 #--------------------------------------------------
599 # handle line breaks, only one empty line gets out.
600 #--------------------------------------------------
601 if ( /$empty_line/o ) {
604 if( $list_level and not $fold ) {
609 $fold = &$do_line_break( $fold );
614 $fold = 0; # no more empty lines
616 /$line_tt/ && do { &$do_line_tt(); next; };
618 #-----------------------------------
619 # No change to current state allowed
620 # during list processing.
621 #-----------------------------------
622 if( $list_level == 0 )
627 if ( /$quote_tt/o ) { &to_state( $QUOTE ) }
628 elsif ( /$bullet_tt/o ) { &to_state( $LIST ) }
629 elsif ( /$indent_tt/o ) { &to_state( $FMT ) }
630 elsif ( /$list_tt/o ) { &to_state( $FMT ) }
631 else { &to_state( $PRE_FMT ) }
634 if( /$notouch_tt/o ) { s/$notouch_tt/ /o; }
637 #--------------------------------------------
638 # Handle the untouchables first.
639 # Mark their locations for later replacement.
640 # (see recover_extractions)
641 #--------------------------------------------
642 for( $i = scalar( @untouchable ); /$untouch_tt/o; $i++ )
645 $unlen = length( $unt );
646 $unloc = index( $_, $unt );
647 $untouchable[ $i ] = $unt;
648 $front = substr( $_, 0, $unloc );
649 $back = substr( $_, $unloc+$unlen );
650 $_ = $front . $um . $back;
669 #-------------------------------------------------------------------------------
671 sub register_tt_translationFunctions
673 my $conversion_type = shift;
675 #----------------------------------------------------
676 # Register call-back functions for typotag processing
677 #----------------------------------------------------
678 $do_bold_tt = "${conversion_type}_bold_tt";
679 $do_bullet_tt = "${conversion_type}_bullet_tt";
680 $do_emit_line = "${conversion_type}_emit_line";
681 $do_final = "${conversion_type}_final";
682 $do_hot_tt = "${conversion_type}_hot_tt";
683 $do_indent_tt = "${conversion_type}_indent";
684 $do_initialize = "${conversion_type}_init";
685 $do_italic_tt = "${conversion_type}_italic_tt";
686 $do_line_break = "${conversion_type}_line_break";
687 $do_line_tt = "${conversion_type}_line_tt";
688 $do_list_tt = "${conversion_type}_list_tt";
689 $do_quote_tt = "${conversion_type}_quote_tt";
690 $do_section_tt = "${conversion_type}_section_tt";
691 $do_target_tt = "${conversion_type}_target_tt";
692 $do_title = "${conversion_type}_title";
693 $do_underline_tt = "${conversion_type}_underline_tt";
695 &$do_initialize; # do any necessary initialization
698 #-------------------------------------------------------------------------------
704 ( $sec,$min,$hour,$mday,$mon,$year,@ignore ) = localtime( time );
705 $month = (January,February,March,April,May,June,July,
706 August,September,October,November,December)[$mon];
707 $year = $year + 1900;
709 return $year if $format eq "y";
710 return "$month $mday, $year" if $format eq "D";
711 return substr($month,0,3) . " $mday, $year";
714 #-------------------------------------------------------------------------------
718 my $given_state = shift;
720 if ( $crnt_state ne $given_state )
722 if( exists $state_change{ "leave_$crnt_state" } )
724 $doStateChange = $state_change{ "leave_$crnt_state" };
728 if( exists $state_change{ "enter_$given_state" } )
730 $doStateChange = $state_change{ "enter_$given_state" };
734 $crnt_state = $given_state;
738 #-------------------------------------------------------------------------------
742 my $whatToCount = shift;
746 $howMany++ while( $line =~ /$whatToCount/g );
750 #-------------------------------------------------------------------------------
755 local $cond_text_region = shift;
757 my ( $field, $variable, $flen, $floc, $front, $back, $v_name, $v_value );
758 my @variable_list = ();
760 #------------------------------------------
761 # Mark all the escaped character sequences.
762 #------------------------------------------
763 while( /$needEscaping/o )
765 $subChar = ord( $1 );
766 s/$needEscaping/$escMrk$subChar$escMrk/o;
769 #-----------------------------------------------------
770 # Collect any field typotags found for later expansion.
771 #-----------------------------------------------------
772 while( /$field_tt/o )
775 $field =~ /$field_content/ && ( $variable = $1 );
777 if( $variable =~ /$variable_def/ ) {
781 #----------------------------------------------
782 # When fields 2 and 3 contain identical strings
783 # then a valid field has been encountered.
784 #----------------------------------------------
790 #-----------------------------------
791 # This is NOT a variable definition.
792 # Have to recover original string.
793 #-----------------------------------
794 $v_name = "_A_${v_name}_Z_"; #internal name
795 $v_value = $variable;
798 #----------------------------------------
799 # Is this only a reference to a variable?
800 #----------------------------------------
801 if ( ! defined $v_value ) {
802 #------------------------------------------------
803 # Only put definitions in the list when it is not
804 # part of a comment. (comments are not emitted)
805 #------------------------------------------------
806 push @variable_list, $v_name unless /$suppress_tt/o;
809 #------------------------------------------------
810 # setting the variable ( |>varName = value<| )
811 # (here $v_value is the value assignment portion)
812 #------------------------------------------------
813 if( /$suppress_tt/o ) {
814 $variables{ $v_name } =
815 preserve_html( $v_value, $cond_text_region );
817 push @variable_list, $variable;
822 #--------------------------------------
823 # Remove field and replace with marker.
824 #--------------------------------------
825 $flen = length( $field );
826 $floc = index( $_, $field );
827 $front = substr( $_, 0, $floc );
828 $back = substr( $_, $floc+$flen );
829 $_ = $front . $vm . $back;
832 #----------------------------
833 # Fill in any variables found
834 #----------------------------
835 foreach $element ( @variable_list )
837 if( exists $variables{ $element } ) {
838 $value = $variables{ $element }
840 $value = "|>$element<|";
841 print STDERR "$pgm: Undefined variable '$element' used in $setext_file.\n" unless $noWarn;
846 $_ = preserve_html( $_, $cond_text_region );
851 #-------------------------------------------------------------------------------
856 my $cond_text_region = shift;
858 #--------------------------------------------------------
859 # When in a conditional text region that only applies to
860 # HTML translation, change the angle brackets to internal
861 # definitions that will be fixed later. This should allow
862 # for a mixture of setext and HTML language together.
863 #--------------------------------------------------------
864 if ( $cond_text_region eq "html" )
866 $text =~ s/</${lt}/go;
867 $text =~ s/>/${gt}/go;
868 $text =~ s/\&/${amp}/go;
874 #===================================================================
875 # Import setext data from given data stream and pay attention to
876 # conditional text considerations, as described below.
878 # ^.. ? name Conditional text when 'name' is defined.
879 # ^.. ! name Conditional text when 'name' is NOT defined.
882 # Multiple line conditional text when 'name' is defined.
883 # (without suppress-tt, will always appear in translated
884 # document going through non-conditional setext conversion)
888 # Multiple line conditional text when 'name' is NOT defined.
889 # (without suppress-tt, will always appear in translated
890 # document going through non-conditional setext conversion)
893 # This procedure also extracts and applies variable definitions
894 # to the text to be emitted.
895 #===================================================================
900 my $cond_text_definitions = shift;
903 my $conditional_text_marker = '^\.\. ([\?!~])\s*(\S+)\s?(.*)$';
907 my ($tense,$def_nm,$text,$multi_line,$crnt_def);
908 my @cond_text_stack = ();
910 while( $_ = <$stream> )
914 if( /$conditional_text_marker/o )
916 $tense = $1; # positive, negative, or end-of conditional text
920 $multi_line = $def_nm =~ s/~//o;
922 #---------------------------------------------
923 # Reach end of multiple line conditional text?
924 #---------------------------------------------
927 $crnt_def = substr( pop @cond_text_stack, 1 );
929 if( $crnt_def ne $def_nm )
931 print STDERR "Incorrectly nested conditinal text sections near line $lineNbr.\n";
932 print STDERR "Expected end of '$crnt_def', but saw end of '$def_nm'\n";
938 #-----------------------------------------
939 # Entering multiple line conditional text?
940 #-----------------------------------------
942 push @cond_text_stack, "$tense$def_nm";
945 #------------------------------------------
946 # This will also catch any non-space
947 # text found on multiple line conditionals.
948 #------------------------------------------
951 $$data[$i++] = extract_fields( "$text\n", $def_nm )
952 if ($tense eq "?") and is_member( $def_nm, $cond_text_definitions );
953 $$data[$i++] = extract_fields( "$text\n", $def_nm )
954 if ($tense eq "!") and not is_member( $def_nm, $cond_text_definitions );
958 elsif( scalar( @cond_text_stack ) == 0 )
960 $$data[$i++] = extract_fields( $_, "" );
964 #--------------------------------------------------------------------
965 # The top element of the conditional text stack is the current
966 # conditional text area. See if it exists in the definitions list.
967 # When present, we want this line of text, depending on 'tense'.
968 #--------------------------------------------------------------------
969 $element = $cond_text_stack[-1];
970 $tense = substr( $element, 0, 1 );
971 $def_nm = substr( $element, 1 );
975 if( is_member( $def_nm, $cond_text_definitions ) ) {
977 $$data[$i++] = extract_fields( $_, $def_nm );
980 elsif( ! is_member( $def_nm, $cond_text_definitions ) )
983 $$data[$i++] = extract_fields( $_, $def_nm );
989 #-------------------------------------------------------------------------------
991 sub extract_menu_init
995 @menuStack = \@helpMenu;
996 $crntMenu = \@helpMenu;
997 @indentStack = ( 0 );
999 $comment_ind = "^\\.\\."; # setext comment indicator ("..")
1000 $menu_element = "${comment_ind} Menu: ";
1001 $help_element = "${comment_ind} Help: ";
1002 $drop_marker = "_(.)_";
1004 $help_code = 9; # special hide-it code indicating not part of help menu
1005 $name_length = 0; # determines padding alignment in HelpMenu data emission
1007 $subMenuIndicator = "\377";
1010 #-------------------------------------------------------------------------------
1012 sub extract_menu_info
1014 my $thisData = shift;
1017 extract_menu_init();
1019 #----------------------------------------------------------------------
1020 # For each and every menu item found in the original data (*.etx) file.
1021 #----------------------------------------------------------------------
1022 while( $_ = get_menu_item( $thisData, \$dataIndex ) )
1024 #----------------------------------------------------------------------
1025 # Here we want to extract the menu title, help name, optional hideIt
1026 # numerical indicator, and optional menu association name.
1028 # Expecting: MenuTitle # HelpName [[,]HideItIndicator] [# Association]
1029 #----------------------------------------------------------------------
1030 if( /^([^#]+)#\s*(\w*)(\s*,\s*)?(\d+)?(\s*#\s*)?(\w+)?/o )
1034 $hideItInd = ($4 eq "") ? "0" : $4;
1035 $assocName = ($6 eq "") ? $helpName : $6;
1036 $helpName =~ s/$trim_spaces/$2/;
1037 $assocName =~ s/$trim_spaces/$2/;
1039 #------------------------------------------------
1040 # Determine to which menu this menu item belongs
1041 # using leading whitespace indentation.
1042 # Extract menu character mneumonic.
1043 #------------------------------------------------
1044 $menuTitle =~ /^(\s*)/ && ($nextMenu = length($1)-$crntIndent);
1045 $menuTitle =~ s/$trim_spaces/$2/o;
1047 $mneumonic = (/$drop_marker/) ? $1 : substr( $menuTitle, 0, 1 );
1049 #--------------------------------------------------
1050 # Identation greater than previous menu element
1051 # indicates that this element is part of a submenu.
1052 #--------------------------------------------------
1055 @$crntMenu[ $end ] .= $subMenuIndicator; # mark previous element
1056 ($menu = $previousTitle) =~ s/ /_/g;
1058 push @menuStack, \@$menu;
1059 push @indentStack, $nextMenu;
1062 #--------------------------------------
1063 # Indentation less than previous menu
1064 # element indicates leaving a submenu.
1065 #--------------------------------------
1066 elsif( $nextMenu < 0 )
1068 $indentLevel = $indentStack[$menuLevel] + $nextMenu;
1074 } while( $indentLevel < $indentStack[$menuLevel] );
1077 $crntIndent += $nextMenu;
1078 $crntMenu = $menuStack[ $#menuStack ];
1079 $end = scalar( @$crntMenu );
1080 @$crntMenu[ $end ] = "$mneumonic,$menuTitle,$helpName,$hideItInd";
1081 $thisTitle = $menuTitle;
1082 $thisTitle =~ s/$drop_marker/$1/;
1083 $thisTitle =~ s/ /_/go;
1084 $MenuNames{ $thisTitle } = "$menuLevel$assocName";
1085 $previousTitle = $menuTitle;
1087 #---------------------------------
1088 # update data for padding purposes
1089 #---------------------------------
1090 if( $mneumonic ne $separator and $name_length < length( $helpName ) )
1092 $name_length = length( $helpName );
1098 #-------------------------------------------------------------------------------
1105 #-------------------------------------------
1106 # Search each and every data line for either
1107 # a '# Menu: ' line or a '# Help: ' line and
1108 # return remainder of the line.
1109 #-------------------------------------------
1110 while( $$line < scalar( @$setext ) )
1112 $_ = $$setext[ $$line++ ];
1113 return $_ if s/$menu_element//o;
1114 return "$_, $help_code" if s/$help_element//o;
1120 #-------------------------------------------------------------------------------
1122 sub check_target_reference
1131 #-----------------------------------
1132 # Are all titles automatically being
1133 # made into hypertext references?
1134 #-----------------------------------
1135 elsif( $make_title_href ) {
1136 /$title_tt/ && ( $target = $2 );
1137 $target =~ s/$trim_spaces/$2/o;
1138 $target =~ s/ /_/go;
1142 print CONVERT "<A NAME=\"$target\"></A>\n";
1144 # only one target-tt reference of this kind allowed per file.
1145 ($index = is_member( $target, \@nm_ref ))
1146 && do{ splice( @nm_ref, $index-1, 1 ); };
1150 #-------------------------------------------------------------------------------
1158 foreach $member ( @$this_list )
1160 if( $item eq $member )
1170 #-------------------------------------------------------------------------------
1172 sub replace_underlines
1174 my $pattern = shift;
1175 s#$pattern#($text = $1) =~ s,_, ,go; $text; #eg;
1178 #-------------------------------------------------------------------------------
1182 #-----------------------------------------
1183 # Put back any escaped characters in text.
1184 #-----------------------------------------
1185 while( /$escapedFound/ )
1187 $subChar = chr( $1 );
1188 s/$escapedFound/$escape_tt$subChar/;
1192 #-------------------------------------------------------------------------------
1194 sub recover_extractions
1198 #------------------------------------
1199 # Replace escaped characters in text.
1200 #------------------------------------
1201 while( /$escapedFound/ )
1203 $subChar = chr( $1 );
1204 s/$escapedFound/$subChar/;
1207 foreach $element ( @untouchable ) { s/$um/$element/; }
1211 #-------------------------------------------------------------------------------
1215 my $paragraph = shift;
1216 my $line = $left_margin;
1218 @words = split ' ', $paragraph;
1220 #-------------------------------------------------------------
1221 # Flow words onto a line up until the right margin is reached.
1222 #-------------------------------------------------------------
1223 foreach $word ( @words )
1225 if( length( $line ) + length( $word ) + 1 <= $right_margin )
1227 $line = "$line$word ";
1231 print CONVERT "$line\n";
1232 $line = "$left_margin$word ";
1236 #--------------------
1237 # emit any remainder.
1238 #--------------------
1239 print CONVERT "$line\n" if( length( $line ) > length( $left_margin ) );
1242 #-------------------------------------------------------------------------------
1244 # This routine is used to override program defaults for HTML settings.
1245 # Two variables are expected to be defined; $htmlHeader and $htmlFooter
1247 sub getHtmlAttributes
1249 my $attrFile = shift;
1253 unless( $return = do $attrFile )
1255 warn "Could not parse $attrFile: $@" if $@;
1256 warn "Could not do $attrFile: $!" unless defined $return;
1257 warn "Could not run $attrFile" unless $return;
1263 #-------------------------------------------------------------------------------
1264 # setext to text conversion call-back routines.
1265 # ( in alphabetical order )
1266 #-------------------------------------------------------------------------------
1268 sub text_bold_tt { s/$bold_tt/$1$2/g }
1270 #-------------------------------------------------------------------------------
1274 # don't do anything if this is no bulleted line.
1277 # remove lead-in from paragraph and put the rest in an array
1279 $paragraph =~ s/$bullet_tt/$1/;
1280 @words = split ' ', $paragraph;
1283 # start with text mode bullet character
1285 foreach $word (@words)
1287 if (length($line) + length($word) + 1 <= $right_margin)
1289 # put every word in a line if there's still room
1290 $line = "$line$word ";
1293 # append line to paragraph if full and start a new line
1294 $paragraph = "$paragraph$line\n";
1299 $paragraph = "$paragraph$line";
1301 # remove trailing white space
1302 $paragraph =~ s/\s$//;
1307 #-------------------------------------------------------------------------------
1311 if( /$passthru_tt/ )
1313 s/$passthru_tt//o; # remove typotag and pass line out as is.
1315 print CONVERT "$_\n";
1319 #-----------------------------
1320 # Handling nested lists first.
1321 #-----------------------------
1324 my $pad = " " x ($list_level * $listIndent);
1325 my $bullet = ($atListStart) ? "$bullet_list[$list_level] " : " ";
1326 s/^\s*/ $pad$bullet/;
1329 elsif( $crnt_state ne $FMT && $text_unfolded_line ne "" )
1331 emit_paragraph( &text_finishing($text_unfolded_line) );
1332 $text_unfolded_line = "";
1335 #-------------------------------------------
1336 # This keeps extra newlines from popping out
1337 # when a list has been terminated.
1338 #-------------------------------------------
1339 unless( $terminatedList )
1341 print CONVERT &text_finishing( $_ ), "\n" unless $_ eq $indentingMode;
1345 $terminatedList = 0;
1350 #-------------------------------------------------------------------------------
1352 sub text_final { emit_paragraph( &text_finishing($text_unfolded_line) ) }
1354 #-------------------------------------------------------------------------------
1359 recover_extractions();
1363 #-------------------------------------------------------------------------------
1368 #---------------------------------------------------------
1369 # The heuristic to prevent Internet addresses from having
1370 # underlines removed, is to check for an '@' character.
1371 #---------------------------------------------------------
1372 if (($text = $1) !~ /\@/ ) {
1379 #-------------------------------------------------------------------------------
1383 s/$indent_tt/$1/o && do {
1384 $text_unfolded_line = "$text_unfolded_line$_ ";
1385 $_ = $indentingMode;
1389 #-------------------------------------------------------------------------------
1394 $text_unfolded_line = ""; # to be used by text_indent & text_emit_line
1395 $left_margin = " "; # for emit_paragraph
1396 $right_margin = 79; # for emit_paragraph
1397 $indentingMode = "?#."; # hopefully unique string not normally found
1399 #----------------------------------------------------------------
1400 # Take all the titles, capitalize and remove title indicator.
1401 #----------------------------------------------------------------
1402 for ($i = 0; $i <= $#data; $i++)
1404 $_ = $data[$i]; # $_ is default for searches
1406 (/$title_tt/ or /$subtitle_tt/) && do {
1407 $titleType = ( /$title_tt/ ) ? "=" : "-";
1408 $data[$i--] = ".."; # suppress title indicator ( --- or === )
1409 $data[$i] =~ s/^\s*//o; # get rid of any leading space.
1410 $this_title = $data[$i];
1412 # Have to fix title if it also happens to be a target-tt.
1413 $this_title =~ /$target_tt/ && do { ($tmp = $4) =~ s,_, ,go; $this_title = $tmp };
1414 $data[$i] = "..$titleType \U$this_title";
1418 #----------------------------------------------------
1419 # NOTE: changing original subtitle-tt search pattern
1420 # to match what was done above.
1421 #----------------------------------------------------
1422 $subtitle_tt = "^\\.\\.- (.*)";
1423 $title_tt = "^\\.\\.= (.*)";
1426 #-------------------------------------------------------------------------------
1428 sub text_italic_tt { s/$italic_tt/$1/g }
1430 #-------------------------------------------------------------------------------
1435 emit_paragraph( &text_finishing($text_unfolded_line) );
1436 $text_unfolded_line = "";
1437 print CONVERT "\n" unless $fold++;
1441 #-------------------------------------------------------------------------------
1443 sub text_line_tt { }
1445 #-------------------------------------------------------------------------------
1461 $terminatedList = 1;
1465 #-----------------------------------------------------
1466 # An empty line terminates a multiple line list entry.
1467 #-----------------------------------------------------
1468 elsif( /$empty_line/o )
1471 #text_line_break( 0 );
1472 $atListStart = 1 if $list_level;
1476 #-------------------------------------------------------------------------------
1478 sub text_quote_tt { }
1480 #-------------------------------------------------------------------------------
1484 my $hdr_level = shift;
1487 print CONVERT "\n \U$_\n" if $hdr_level <= 3; # converted to uppercase
1488 print CONVERT "\n $_\n" if $hdr_level > 3; # left alone
1492 #-------------------------------------------------------------------------------
1496 s#$target_tt#($text = $4) =~ s,_, ,go; " $text"; #eg;
1499 #-------------------------------------------------------------------------------
1505 my $lc = substr( $_, 2, 1 );
1507 #-----------------------------------------------------------------
1508 # Incoming text looks like ..= <title text> or ..- <subtitle text>
1509 #-----------------------------------------------------------------
1511 $_ = substr( $_, 4 );
1513 $size = length( $_ );
1515 #-------------------------------------------------
1516 # Going to wrap titles with lines as long as title
1517 #-------------------------------------------------
1518 for( $size = length( $_ ); $size > 0; $size-- )
1522 print CONVERT "$line\n$_\n$line\n";
1525 sub text_underline_tt { replace_underlines( $underline_tt ) }
1527 #-------------------------------------------------------------------------------
1528 # setext to HTML conversion call-back routines.
1529 # ( in alphabetical order )
1530 #-------------------------------------------------------------------------------
1534 #---------------------------------------
1535 # Turn all "**text**" into "<B>text</B>"
1536 #---------------------------------------
1537 s#$bold_tt#${lt}B${gt}$1${lt}/B${gt}$2#g;
1540 #-------------------------------------------------------------------------------
1544 s/$bullet_tt(.*)/ ${lt}li${gt}$1$2${lt}\/li${gt}/;
1547 #-------------------------------------------------------------------------------
1549 sub html_emit_footer
1551 print CONVERT "</P>\n$htmlFooter";
1555 #-------------------------------------------------------------------------------
1557 sub html_emit_header
1560 my $header = $htmlHeader;
1562 $header =~ s/\$HTML_TITLE/$htitle/o;
1563 print CONVERT $header;
1566 #-------------------------------------------------------------------------------
1570 print CONVERT "<LI>" if $atListStart == 1 and not /${lt}LI${gt}/o;
1573 if( /$passthru_tt/ )
1575 s/$passthru_tt//o; # remove typotag and pass line out as is.
1577 print CONVERT "$_\n"
1581 print CONVERT &html_finishing( $_ ), "\n";
1585 #-------------------------------------------------------------------------------
1587 sub html_enter_list { print CONVERT "<UL>\n" } # state change activities
1588 sub html_leave_list { print CONVERT "</UL>\n" }
1590 sub html_enter_pre { print CONVERT "<PRE>\n"; $insideNoFormatArea = 1 }
1591 sub html_leave_pre { print CONVERT "</PRE>\n"; $insideNoFormatArea = 0 }
1593 sub html_enter_quote { print CONVERT "<BLOCKQUOTE><PRE>\n"; $insideNoFormatArea = 1 }
1594 sub html_leave_quote { print CONVERT "</PRE></BLOCKQUOTE>\n"; $insideNoFormatArea = 0 }
1596 #-------------------------------------------------------------------------------
1603 #----------------------------------------------------
1604 # Report on all internal name references not used up.
1605 #----------------------------------------------------
1606 if( scalar( @nm_ref ) > 0 )
1608 print STDERR "\nMissing reference (target-tt) to the following:\n\n";
1609 for( $i=0; $i < scalar( @nm_ref ); $i++ )
1611 print STDERR " $nm_ref[ $i ]\n";
1616 #-------------------------------------------------------------------------------
1618 sub html_finishing {
1621 s/\&/\&\#38\;/go; s/\</\&\#60\;/go; s/\>/\&\#62\;/go;
1622 s/$lt/</go; s/$gt/>/go; s/$amp/\&/go; # convert markers to real symbols
1624 #-----------------------------------------------
1625 # This fixes the case where an untouchable
1626 # string includes these special html characters.
1627 #-----------------------------------------------
1628 foreach $element ( @untouchable )
1630 $element =~ s/\&/\&\#38\;/go;
1631 $element =~ s/\</\&\#60\;/go;
1632 $element =~ s/\>/\&\#62\;/go;
1634 recover_extractions();
1638 #-------------------------------------------------------------------------------
1642 #----------------------------------------------------
1643 # After finding a hot-tt, substitute all underlines
1644 # with spaces and check to see if the hot-tt had
1645 # a corresponding hypertext reference. Flag it in
1646 # bright, bold red when no hypertext record found.
1647 # Allow user to define the variable HTML_DIR as the
1648 # destination directory for the HTML code.
1649 # Note, the files may have to actually be placed
1650 # in such directory by hand after they are generated.
1651 #----------------------------------------------------
1653 $h = $href{$1}; ($text = $1) =~ s,_, ,go;
1654 $h ? qq'${lt}A HREF="$variables{HTML_DIR}$h"${gt}$text${lt}/A${gt}'
1655 : "${lt}B${gt}${lt}font color=red${gt}--> $text <-- NO HREF!!${lt}/font${gt}${lt}/B${gt}"; #eg;
1658 #-------------------------------------------------------------------------------
1660 sub html_indent { s/$indent_tt/$1/ } # get rid of indent-tt characters
1662 #-------------------------------------------------------------------------------
1666 local $title, $aTitle;
1671 enter_list => "html_enter_list",
1672 leave_list => "html_leave_list",
1674 enter_pre => "html_enter_pre",
1675 leave_pre => "html_leave_pre",
1677 enter_quote => "html_enter_quote",
1678 leave_quote => "html_leave_quote",
1681 $veryFirstTime = 1; # used to force table of content header out
1683 #------------------------------------------
1684 # Make a first pass over the data, looking
1685 # for hypertext linking information.
1686 #------------------------------------------
1687 for ($i = 0; $i <= $#data; $i++)
1689 $_ = $data[$i]; # $_ is default for searches
1691 #---------------------------------------------------------
1692 # This will pick out targets found in the setext not
1693 # hidden by a suppress-tt, that is, the href-tt below.
1694 # With this check, it is unnecessary to have to include
1695 # the href-tt which uses identical text for internal
1696 # document references. External references need href-tt.
1697 # Have to make sure the match does not pick up elements
1698 # inside a notouch-tt ( eg. `_do_not_want_this_as_target`)
1699 #---------------------------------------------------------
1700 if( /$target_tt/ && substr($`,length($`)-1,1) ne "`" &&
1701 (not /$suppress_tt/) )
1703 $href{ $4 } = "$intHrefMrk$4";
1707 #-------------------------------------------------
1708 # Locate HREF's and save. When no target is given,
1709 # assume the target is internal, with same name.
1710 #-------------------------------------------------
1714 $target = ($2) ? $2 : "$intHrefMrk$hrefID"; # assume internal href.
1715 $href{$hrefID} = $2;
1717 #------------------------------
1718 # Remember internal HREF's not
1719 # already seen for target-tt.
1720 #------------------------------
1721 if( $target =~ /$internal_href/ ) {
1722 if( not is_member( substr( $target, 1), \@nm_ref ) ) {
1729 #---------------------------------------------------------
1730 # The first title-tt or subhead-tt gets <TITLE>...</TITLE>
1731 #---------------------------------------------------------
1732 /$title_tt/ && do { $htmlTitle = html_init_title("H1", $i); next; };
1733 /$subtitle_tt/ && do { $htmlTitle = html_init_title("H2", $i); next; };
1736 html_emit_header( $htmlTitle );
1738 #----------------------------------------------------
1739 # NOTE: changing original title-tt search pattern
1740 # to match what was done in html_init_title.
1741 #----------------------------------------------------
1742 $title_tt = "^\\.\\.\\s+(<H.>)(.*)(<\\/H.>)";
1745 #-------------------------------------------------------------------------------
1749 local($head, $i) = @_;
1752 $data[$i--] = ".."; # suppress title indicator ( --- or === )
1753 $data[$i] =~ s/^\s*//; # get rid of any leading space in actual title
1754 $this_title = $data[$i];
1756 # Have to fix title if it also happens to be a target-tt.
1757 $this_title =~ /$target_tt/ && do { ($tmp = $4) =~ s,_, ,go; $this_title = $tmp };
1759 #---------------------------------------------------
1760 # Are all titles automatically considered target-tt?
1761 #---------------------------------------------------
1762 if( $make_title_href )
1764 $hyper_ref = $this_title;
1765 $hyper_ref =~ s/ /_/go;
1766 $externalReference =
1767 ($separate_html_files) ? substr("$MenuNames{ $hyper_ref }.$htmlExt", 1) : "";
1769 $href{ $hyper_ref } ="$externalReference$intHrefMrk$hyper_ref";
1771 #------------------------------
1772 # Remember internal HREF's not
1773 # already seen for target-tt.
1774 #------------------------------
1775 if( not is_member( $hyper_ref, \@nm_ref ) ) {
1776 push @nm_ref, $hyper_ref;
1780 #-----------------------------------------------------------------
1781 # Put out the HTML title and then suppress it for later processing
1782 #-----------------------------------------------------------------
1783 $aTitle = "$this_title" unless $title++;
1784 $data[$i] = ".. <$head> " . $data[$i] . " </$head>";
1789 #-------------------------------------------------------------------------------
1793 #---------------------------------------
1794 # Turn all "~text~" into "<I>text</I>"
1795 #---------------------------------------
1796 s#$italic_tt#${lt}I${gt}$1${lt}/I${gt}#g;
1799 #-------------------------------------------------------------------------------
1805 print CONVERT "$closePgf<P>\n" unless $fold++;
1810 #-------------------------------------------------------------------------------
1814 if( not $insideNoFormatArea )
1816 s/$line_tt/${lt}P${gt}${lt}HR${gt}/;
1817 print CONVERT html_finishing( $_ ), "\n";
1821 #-------------------------------------------------------------------------------
1827 if ( $1 eq '(' ) # open list level
1830 s/$list_tt/${lt}UL${gt}${lt}LI${gt}/;
1832 else # close list level
1835 s,$list_tt,${lt}/LI${gt}${lt}/UL${gt},;
1836 $atListStart = 2 if $list_level;
1837 $terminatedList = 1;
1841 #-----------------------------------------------------
1842 # An empty line terminates a multiple line list entry.
1843 #-----------------------------------------------------
1844 elsif( /$empty_line/o )
1846 print CONVERT "</LI>\n" unless $terminatedList;
1847 print CONVERT "</P><P>\n";
1848 $atListStart = 1 if $list_level;
1849 $terminatedList = 0;
1853 #-------------------------------------------------------------------------------
1860 #-------------------------------------------------------------------------------
1864 my $hdr_level = shift;
1866 print CONVERT "<H$_</H$hdr_level>\n";
1869 #-------------------------------------------------------------------------------
1873 check_target_reference( $_ );
1874 /$target_tt/ && do { ($a = $4) =~ s,_, ,go; s/$target_tt/ $a/; };
1877 #-------------------------------------------------------------------------------
1881 my $titleHolder = $_;
1884 /$target_tt/ && do { ($a = $4) =~ s,_, ,go; s/$target_tt/$a/; };
1886 if( /$title_tt/i ) # this is the new title-tt from html_init
1888 $frontMrk = $1; $thisTitle = $2; $backMrk = $3;
1890 if( not $separate_html_files or $veryFirstTime )
1892 check_target_reference( $titleHolder );
1893 print CONVERT $frontMrk, &html_finishing($thisTitle), $backMrk, "\n";
1896 elsif( $frontMrk eq "<H1>" )
1898 $savedTitle = $thisTitle;
1899 $savedTitleHolder = $titleHolder;
1903 #--------------------------
1904 # Create another HTML file?
1905 #--------------------------
1906 $hyper_ref = $thisTitle;
1907 $hyper_ref =~ s/$trim_spaces/$2/o;
1908 $hyper_ref =~ s/ /_/go;
1909 $association = $MenuNames{ $hyper_ref };
1911 if( $association ne "" )
1913 $assocLevel = substr( $association, 0, 1 );
1914 $association = substr( $association, 1 );
1915 $newFile = "$outputDirectory$association.$htmlExt";
1917 if( $converted_file ne $newFile )
1919 #-----------------------------
1920 # Finish off the current file.
1921 #-----------------------------
1925 #-----------------------------------------------------
1926 # This realigns title after nested sublevels complete.
1927 #-----------------------------------------------------
1928 if ( $assocLevel == 0 ) {
1929 $savedTitle = $thisTitle;
1932 $converted_file = $newFile;
1933 open CONVERT, ">$converted_file" or die "Can't create $converted_file, $OS_ERROR";
1934 html_emit_header( $savedTitle );
1936 #--------------------------------------------
1937 # This puts target reference in correct file.
1938 #--------------------------------------------
1939 if( $savedTitleHolder )
1941 check_target_reference( $savedTitleHolder );
1942 if( $savedTitleHolder =~ /$title_tt/i )
1944 print CONVERT $1, &html_finishing($2), $3, "\n";
1946 $savedTitleHolder = "";
1951 check_target_reference( $titleHolder );
1952 print CONVERT $frontMrk, &html_finishing($thisTitle), $backMrk, "\n";
1957 #-------------------------------------------------------------------------------
1959 sub html_underline_tt
1961 #--------------------------------------------
1962 # Turn all "_text_" into "<I><U>text</U></I>"
1963 # Remembering to substitute intervening
1964 # underlines with spaces.
1965 #--------------------------------------------
1967 ($text = $1) =~ s,_, ,go;
1968 "${lt}I${gt}${lt}U${gt}$text${lt}/U${gt}${lt}/I${gt}"; #eg;
1971 #-------------------------------------------------------------------------------
1972 # setext to NEdit HELP conversion call-back routines.
1973 # ( in alphabetical order )
1974 #-------------------------------------------------------------------------------
1978 #----------------------------------------------------
1979 # Turn all "**text**" into "<stlMrk_B>text<stlMrk_B>"
1980 #----------------------------------------------------
1981 s#$bold_tt#${stlMrk}$TKN_BOLD$1${stlMrk}$TKN_BOLD$2#g;
1984 #-------------------------------------------------------------------------------
1986 sub help_bullet_tt { s/$bullet_tt/ * $1/ }
1988 #-------------------------------------------------------------------------------
1992 #------------------------------------------------------
1993 # The following is here to help us generate conditional
1994 # compilation elements for the 'C' compiler.
1995 #------------------------------------------------------
1996 if( /$passthru_tt/ )
1998 s/$passthru_tt//o; # remove typotag and pass line out as is.
2004 #-------------------------------------------------
2005 # This seems to be the only good place to take
2006 # care of style changes that have occurred between
2007 # usage of proportional and fixed font styles.
2008 #-------------------------------------------------
2011 $_ = $styleMark . get_style_name( $crntStyle ) . $_;
2015 my $finishedLine = help_finishing( $_ );
2017 print HELP "\"", $finishedLine, "\",\n";
2019 #----------------------------------------------------------------
2020 # To minimize newline output for the empty line elements,
2021 # the algorithm remembers if its last line had a newline emitted.
2022 #----------------------------------------------------------------
2023 $newLinePresentInLastLine = $finishedLine =~ /\\n$/;
2027 #-------------------------------------------------------------------------------
2031 #-------------------------------------------------------------------------------
2037 #----------------------------
2038 # When finishing a heading...
2039 #----------------------------
2042 #--------------------------------------------------
2043 # ... destroy any styles inadvertantly placed there
2044 #--------------------------------------------------
2047 my @line = split $stlMrk;
2048 $_ = join '', @line;
2051 #------------------------------------
2052 # ... because only one style allowed.
2053 #------------------------------------
2054 $stlFront = $styleMark . get_style_name( "" );
2056 $stlEnd = $styleMark . get_style_name( $initialStyle );
2057 $stlFront = "" if /^$styleToken/ ; # remove redundancy when present
2058 $_ = $stlFront . $_ .$stlEnd;
2061 #---------------------------------------------
2062 # Any style markers found in the current line?
2063 #---------------------------------------------
2066 #----------------------------------------
2067 # Break line up into style word elements.
2068 #----------------------------------------
2070 my @line = split $stlMrk;
2072 foreach $element ( @line )
2074 #--------------------------------------------------
2075 # Extract word emphasis token and associated words.
2076 # Embed style marker into text line.
2077 #--------------------------------------------------
2078 $element =~ /^($aStyleToken)?(.*)$/o && do {
2080 $token = ($1) ? $1 : $TKN_TEXT; # $TKN_xxx
2082 my $nextStyle = get_style( $crntStyle, $token );
2084 if( $crntStyle eq $nextStyle )
2090 $stlNm = get_style_name( $nextStyle );
2091 $line .= "$styleMark$stlNm$words";
2092 $crntStyle = $nextStyle;
2100 recover_extractions();
2103 #-------------------------------------------
2104 # Apply any initial style change introduced.
2105 #-------------------------------------------
2106 $_ = $newLeadStyle . $_;
2109 #----------------------------------------------------------------
2110 # Add newline element to all lines which are not being currently
2111 # formatted into a flowing paragraph. It is done here because the
2112 # character also has to get included in the character counts.
2113 #----------------------------------------------------------------
2114 $_ .= get_newline( 1 ) if $crnt_state ne $FMT;
2116 #----------------------------------------------------------------------
2117 # Since 2 characters (\ and n) are occupying the space of one newline,
2118 # we need to subract out the number of new lines from the total offset.
2119 #----------------------------------------------------------------------
2120 my $styleCount = count( $styleToken, $_ );
2121 my $newLineCount = count( "\\\\n", $_ );
2122 my $quoteCount = count( '"', $_ );
2123 my $backslashCount = count( "\\\\", $_ ) - $styleCount -
2124 $newLineCount - $quoteCount;
2126 my $adjustment = ($styleCount * $styleTokenSize) +
2127 ($backslashCount / 2) + $newLineCount + $quoteCount;
2129 #-----------------------------------------------------------
2130 # Now keep a running total of how many characters to emit.
2131 # (Keep 2 forms, total number for compiler string length
2132 # considerations, and another for target-tt section offsets.
2133 #-----------------------------------------------------------
2134 $sectionCharacterCnt += length( $_ );
2135 $targetOffset += length( $_ ) - $adjustment;
2140 #-------------------------------------------------------------------------------
2142 sub help_fixed_styles
2144 #----------------------------------------------------------------
2145 # All proportional styles in the style state transition table
2146 # begin with the "_" character. If we are already in the
2147 # proportional styles arena, a link, or header, no change occurs.
2148 #----------------------------------------------------------------
2149 if( $crntStyle =~ /^_/ )
2151 $crntStyle =~ s/^_//o;
2152 $styleChanged = $crntStyle unless $styleChanged;
2156 #-------------------------------------------------------------------------------
2160 my ( $text, $stlNm, $h );
2162 #--------------------------------------------------
2163 # After finding a hot-tt, substitute all underlines
2164 # with spaces and check to see if the hot-tt had
2165 # a corresponding hypertext reference. Make it
2166 # unadorned text when no reference found.
2167 #--------------------------------------------------
2169 ($text = $1) =~ s,_, ,go;
2170 $h = is_known_link( $text );
2171 $stlNm = get_style_name( $crntStyle );
2173 $h ? "$stlMrk$TKN_LINK$text$stlMrk$TKN_LINK"
2178 #-------------------------------------------------------------------------------
2184 s/$indent_tt/$1/; # get rid of indent-tt characters
2185 /\S$/ && do { $_ .= ' ' }; # make sure space available for remaining
2186 } # text in this kind of paragraph
2189 #-------------------------------------------------------------------------------
2195 enter_pre => "help_fixed_styles",
2196 leave_pre => "help_proportional_styles",
2198 enter_quote => "help_fixed_styles",
2199 leave_quote => "help_proportional_styles",
2202 #--------------------------------------------
2203 # Global elements needed for making menu code
2204 #--------------------------------------------
2207 $copy_right_holder = "Mark Edel";
2208 $hlptxt = "help_data$helpSuffix.h"; # name of file holding help data structures
2209 $hlphdr = "help_topic$helpSuffix.h"; # name of file holding help definitions
2210 $stlMrk = "\01"; # this is the character code
2211 $styleMark = '\01'; # this is the text string
2212 $styleToken = "\\$styleMark"; # this for splitting strings on styleMark
2213 $styleTokenSize = length( $styleToken ); # accounts for '\01A'
2214 $illegal_help = "HELP_none";
2216 $menu_record = "(.),(.*),(.*),(\\d)";
2217 $tgtIndx = 0; # target-tt index for hypertext reference array (@href)
2219 #-------------------------------------------------------------------
2220 # The following data is used to embed style data into the help text.
2221 #-------------------------------------------------------------------
2223 # TOKENS => text bold italic underline
2228 plain => { style => "A", states => [ "plain", "bold", "italic", "u_plain" ] },
2229 bold => { style => "B", states => [ "bold", "plain", "b_ital", "u_bold" ] },
2230 italic => { style => "C", states => [ "italic", "b_ital", "plain", "u_italic" ] },
2231 b_ital => { style => "D", states => [ "b_ital", "italic", "bold", "u_b_ital" ] },
2233 u_plain => { style => "E", states => [ "u_plain", "u_bold", "u_italic", "plain" ] },
2234 u_bold => { style => "F", states => [ "u_bold", "u_plain", "u_b_ital", "bold" ] },
2235 u_italic => { style => "G", states => [ "u_italic", "u_b_ital", "u_plain", "italic" ] },
2236 u_b_ital => { style => "H", states => [ "u_b_ital", "u_italic", "u_bold", "bold_ital" ] },
2238 # proportional font styles
2240 _plain => { style => "I", states => [ "_plain", "_bold", "_italic", "_u_plain" ] },
2241 _bold => { style => "J", states => [ "_bold", "_plain", "_b_ital", "_u_bold" ] },
2242 _italic => { style => "K", states => [ "_italic", "_b_ital", "_plain", "_u_italic" ] },
2243 _b_ital => { style => "L", states => [ "_b_ital", "_italic", "_bold", "_u_b_ital" ] },
2245 _u_plain => { style => "M", states => [ "_u_plain", "_u_bold", "_u_italic", "_plain" ] },
2246 _u_bold => { style => "N", states => [ "_u_bold", "_u_plain", "_u_b_ital", "_bold" ] },
2247 _u_italic => { style => "O", states => [ "_u_italic", "_u_b_ital", "_u_plain", "_italic" ] },
2248 _u_b_ital => { style => "P", states => [ "_u_b_ital", "_u_italic", "_u_bold", "_bold_ital" ] },
2250 # hyperLink style => "Q",
2252 # header1 style => "R", --
2253 # header2 style => "S", |_ MAX_HEADER
2254 # header3 style => "T", --
2257 #-----------------------------------------------------------
2258 # The link index is the position in a font style table
2259 # where the linking font will reside. It appears immediately
2260 # after the styles from the table above.
2261 #-----------------------------------------------------------
2262 $linkIndex = scalar( keys %styles_stt );
2263 $maxTokens = scalar( @{ $styles_stt{plain}{states} } );
2265 $STYLE_PLAIN = $styles_stt{plain}{style};
2266 $STYLE_LINK = "Q"; # link style marker, a continuation from style table
2267 $STYLE_HDR = "R"; # beginning of header style markers
2268 $MAX_HEADER = 3; # the maximum number of header styles in use
2270 $TKN_TEXT = 0; # used in style state transition, order important
2271 $TKN_BOLD = 1; # used in style state transition, order important
2272 $TKN_ITALIC = 2; # used in style state transition, order important
2273 $TKN_ULINE = 3; # used in style state transition, order important
2276 $aStyleToken = "[$TKN_TEXT$TKN_BOLD$TKN_ITALIC$TKN_ULINE$TKN_LINK]";
2278 $initialStyle = "_plain"; # the initial style for help text.
2279 $crntStyle = $initialStyle;
2282 print_menu( $crntMenu, "" ) if $print_menu; # sort of debug info
2284 #----------------------------------
2285 # Create help header (help_topic.h)
2286 #----------------------------------
2287 open HLPHDR, ">$hlphdr" or die "Can't create $hlphdr, $OS_ERROR";
2288 emit_help_header( HLPHDR, $crntMenu );
2291 #-------------------------------------------
2292 # Create help text data header (help_data.h)
2293 #-------------------------------------------
2294 open HELP, ">$hlptxt" or die "Can't create $hlptxt, $OS_ERROR";
2295 emit_helpTitles( HELP, $crntMenu );
2297 collect_internal_hypertext_references( \@data );
2299 emit_helpText( HELP, $crntMenu, \@data );
2302 #-------------------------------------------------------------------------------
2306 s/$italic_tt/${stlMrk}$TKN_ITALIC$1${stlMrk}$TKN_ITALIC/g
2309 #-------------------------------------------------------------------------------
2314 $_ .= get_newline( 2 );
2315 help_emit_line() unless $fold++;
2319 #-------------------------------------------------------------------------------
2322 sub help_list_tt { text_list_tt() }
2323 sub help_quote_tt {}
2325 #-------------------------------------------------------------------------------
2327 sub help_proportional_styles
2329 #----------------------------------------------------------------
2330 # All proportional styles in the style state transition table
2331 # begin with the "_" character. If we are already in the
2332 # proportional styles arena, a link, or header, no change occurs.
2333 #----------------------------------------------------------------
2334 unless( $crntStyle =~ /^_/ or
2335 $crntStyle eq "link" or
2336 $crntStyle eq "header" ) {
2338 $crntStyle = "_$crntStyle";
2339 $newLeadStyle = $styleMark . get_style_name( $crntStyle );
2343 #-------------------------------------------------------------------------------
2347 $headingLevel = shift;
2348 #----------------------------------------------------------
2349 # Heading levels for sectioning are being required to start
2350 # at level 3 (considered the first level). This keeps the
2351 # X-resources down inside NEdit. So here is the mapping.
2357 #----------------------------------------------------------
2358 $headingLevel = ($headingLevel > 2 ) ? $headingLevel - 2 : 1;
2359 $headingLevel = $MAX_HEADER if $headingLevel > $MAX_HEADER; #
2362 $crntStyle = $initialStyle;
2366 #-------------------------------------------------------------------------------
2368 sub help_target_tt { } # cannot process target-tt at this time because
2369 # calculation of the hypertext offset requires
2370 # a fully expanded text line (see help_finishing).
2374 if( /$target_tt/ and exists $href{ $4 } )
2376 my ( $text, $tgtOffset, $originalLine );
2378 #---------------------------------------------------
2379 # Have to compute target's offset into help section.
2380 # Need actual text sans styling information. Assuming
2381 # all other text replacement has already occurred.
2382 #---------------------------------------------------
2385 s/$styleToken.//g; # remove all styling markers
2387 #--------------------------------------------------------
2388 # Inside this special substitution, a computation of the
2389 # target's offset from the beginning of the section is
2390 # being computed and applied to the hyper-reference array
2391 # element which will be emitted after all text sections
2392 # have been processed.
2393 #--------------------------------------------------------
2395 ($text = $4) =~ s,_, ,go;
2396 $tgtOffset = index( $_, $text ) + $targetOffset -1;
2397 $tgtOffset = sprintf( "%6d", $tgtOffset );
2398 $href[ $tgtIndx++ ] =~ s /^0/$tgtOffset/o;
2402 #-------------------------------------------------------
2403 # Now fix hyper-references in actual line to be emitted.
2404 #-------------------------------------------------------
2408 ($text = $4) =~ s,_, ,go;
2414 #-------------------------------------------------------------------------------
2416 sub help_title {&help_emit_line}
2418 #-------------------------------------------------------------------------------
2420 sub help_underline_tt
2422 #--------------------------------------------------
2423 # Turn all "_text_" into "<stlMrk_U>text<stlMrk_U>"
2424 # Remembering to substitute intervening
2425 # underlines with spaces.
2426 #--------------------------------------------------
2428 ($text = $1) =~ s,_, ,go;
2429 "${stlMrk}$TKN_ULINE$text${stlMrk}$TKN_ULINE";
2433 #-------------------------------------------------------------------------------
2439 $howMany-- if $newLinePresentInLastLine && $howMany > 1;
2440 return '\n' x $howMany;
2443 #-------------------------------------------------------------------------------
2447 my $linkName = shift;
2449 for( $index = 0; $index < scalar( @hot_tt_links ); $index++ )
2451 $element = $hot_tt_links[ $index ];
2452 return 1 if( $hot_tt_links[ $index ] eq $linkName );
2458 #-------------------------------------------------------------------------------
2462 my $crntStyle = shift; # plain, bold, italic, etc.
2463 my $token = shift; # $TKN_xxx
2464 my $style = "header"; # assume working on header
2466 if( $headingLevel == 0 )
2468 if( $token == $TKN_LINK )
2470 if( $crntStyle eq "link" )
2472 $style = $prevStyle;
2476 $prevStyle = $crntStyle;
2482 @transitions = @{ $styles_stt{$crntStyle}{states} };
2483 $style = $transitions[ $token ];
2490 #-------------------------------------------------------------------------------
2494 my $crntStyle = shift; # plain, bold, italic, etc.
2499 $styleName = chr(ord( $STYLE_HDR )+$headingLevel-1);
2501 elsif( $crntStyle eq "link" )
2503 $styleName = $STYLE_LINK;
2507 $styleName = $styles_stt{$crntStyle}{style};
2513 #-------------------------------------------------------------------------------
2521 while( $$line < scalar( @$setext ) )
2523 $_ = $$setext[ $$line++ ];
2524 return $_ if s/$menu_element//o;
2525 return "$_, $help_code" if s/$help_element//o;
2531 #-------------------------------------------------------------------------------
2535 my $crnt_menu = shift;
2537 my ( $menuTitle, $mneumonic, $helpName, $hideit, $type );
2539 foreach $menuItem ( @$crnt_menu )
2541 if ( $menuItem =~ /$menu_record/o )
2542 { $mneumonic=$1; $menuTitle=$2; $helpName=$3; $hideit=($4) ? $4 : "" }
2544 if( $hideit eq $help_code ) {
2549 $hideit = ", ($hideit)" if $hideit;
2553 print "$type: $indent$mneumonic, $menuTitle [$helpName]$hideit\n";
2555 if( $menuItem =~ /$subMenuIndicator/o )
2557 ($menu = $menuTitle) =~ s/ /_/og;
2558 print_menu( \@$menu, "$indent " );
2563 #-------------------------------------------------------------------------------
2565 sub collect_internal_hypertext_references
2569 my ($source, $destination );
2571 while( $line < scalar( @$setext ) )
2573 $_ = $$setext[ $line++ ];
2579 if( $destination =~ /$internal_href/ )
2581 $href{ $1 } = $source;
2587 #-------------------------------------------------------------------------------
2592 my $crnt_menu = shift;
2599 emit_help_menu_text( $setext, $stream, $crnt_menu, \$line );
2601 print $stream "static char **HelpText[] = {\n$helpNameList\n};\n\n";
2603 print $stream "HelpMenu H_M [] =\n{\n";
2604 emit_help_menu( $stream, $crnt_menu, 0, 1 );
2605 print $stream "\n};\n";
2607 #------------------------------------
2608 # Emit internal hypertext references.
2609 #------------------------------------
2610 print $stream "\nHref H_R [] =\n{\n";
2612 for( $index = 0; $index < scalar( @href ); $index++ )
2614 $element = $href[ $index ];
2615 $nextone = ( $index == $#href ) ? "NULL, " : "&H_R[%2d],";
2616 printf $stream "$sep { $nextone $element }", $index+1;
2619 print $stream "\n};\n";
2621 #-----------------------------
2622 # Emit program version string.
2623 #-----------------------------
2624 $pgmVersion = $variables{ version };
2625 $pgmVersion .= '\n' . date() if $pgmVersion !~ /$neditDefaultMarker/;
2626 print $stream "\nstatic const char * NEditVersion = \"$pgmVersion\\n\";\n";
2629 #-------------------------------------------------------------------------------
2631 sub emit_help_menu_text
2635 my $crnt_menu = shift;
2638 my ( $menuTitle, $mneumonic, $helpName, $prevLine );
2640 #----------------------------------------
2641 # For every node of the menu tree...
2642 #----------------------------------------
2643 foreach $menuItem ( @$crnt_menu )
2645 if ( $menuItem =~ /$menu_record/ )
2646 { $mneumonic=$1; $helpName=$3; ($menuTitle=$2) =~ s/_//; }
2648 #---------------------------------
2649 # ... recursively expand sub-menus
2650 #---------------------------------
2651 if( $menuItem =~ /$subMenuIndicator/ )
2653 ($menu = $menuTitle) =~ s/ /_/g;
2654 emit_help_menu_text( $setext, $stream, \@$menu, $line );
2657 elsif( $mneumonic ne $separator ) # ... and not a menu separator
2659 locate_menu_text( $setext, $menuTitle, $line )
2660 or die "Unable to find \"$menuTitle\" text!";
2665 $s_e_p = ($helpNameList) ? ",\n" : "";
2666 $helpNameList .= $s_e_p . " htxt_$helpName";
2667 $sectionCharacterCnt = 0;
2670 #------------------------
2671 # ... emit help menu text
2672 #------------------------
2675 ($_,$remainder) = get_menu_text( $setext, $remainder, $line );
2679 next if /$empty_line/ and $lineNbr == 1;
2682 #--------------------------------------------------
2683 # Save all hypertext targets found in current topic
2684 #--------------------------------------------------
2685 if( /$target_tt/ and exists $href{ $4 } )
2688 $href = $href{$target};
2690 $target =~ s/_/ /go;
2691 $topic = "HELP_\U$helpName,";
2692 $nl1 = $name_length+6; # for HELP_ and comma
2695 sprintf("0, %-${nl1}.${nl1}s \"$href\", \"$target\"", $topic );
2697 push @hot_tt_links, $href; # collect for later verification.
2700 s/\\/\\\\/go; # escape backslash any where in text
2701 s/"/\\"/go; # escape embedded double quotes
2702 s/^\s*$//; # redefine whitespace as empty line
2706 print $stream "static char * htxt_$helpName [] = {\n";
2707 $styleChanged = $initialStyle; # This forces initial style out
2708 $crntStyle = $initialStyle;
2709 parse_setext( \@section );
2710 print $stream "NULL\n};\n\n";
2715 #-------------------------------------------------------------------------------
2717 sub locate_menu_text
2720 my $menuTitle = shift;
2723 $menuTitle =~ s/_//go; # removing drop key character markers
2724 $menuTitle =~ s/ /./go; # spaces could be underlines in titles
2725 $menuTitle =~ s/\(/./go; # parens are special in regex searches...
2726 $menuTitle =~ s/\)/./go; # ... here they should be ignored
2728 #-----------------------------------------------------
2729 # When the whence value is set to zero, the search
2730 # for the text that belongs with the given menu title
2731 # is started at the beginning of the file. This allows
2732 # the menu text to be in an order other than that
2733 # specified by the menu itself. This gives freedom
2734 # to the writer; inefficiency to the text processing.
2735 #-----------------------------------------------------
2736 $$line = 0 if ( $whence != 1 );
2738 while( $$line < scalar( @$setext ) )
2740 if( $$setext[ $$line++ ] =~ /$menuTitle/ )
2742 if ( $$setext[ $$line ] =~ /$subtitle_tt/ or
2743 $$setext[ $$line ] =~ /$title_tt/ )
2746 return 1; # the first line after the setext title marker
2754 #-------------------------------------------------------------------------------
2759 my $crnt_line = shift;
2762 #-------------------------------------
2763 # Skip any setext comment lines found.
2764 #-------------------------------------
2765 while( $$setext[ $$line ] =~ /$suppress_tt/ ) { $$line ++ };
2767 $crnt_line = $$setext[ $$line++ ] if $crnt_line eq "";
2769 if( $crnt_line =~ /$twobuck_tt/ ) # end of setext document?
2775 #--------------------------------------------
2776 # Have to read ahead by one line to catch the
2777 # title of the next section, or the end of
2778 # the setext document.(Eat horizontal rulers)
2779 #--------------------------------------------
2780 do { $_ = $$setext[ $$line++ ] } until not /^ --/;
2782 #--------------------------------
2783 # Look ahead again, so that an
2784 # empty last line is not emitted.
2785 #--------------------------------
2786 if( $crnt_line =~ /^\s*$/ and
2787 ($$setext[ $$line ] =~ /$subtitle_tt/o or
2788 $$setext[ $$line ] =~ /$title_tt/o or
2789 $$setext[ $$line ] =~ /$twobuck_tt/o))
2794 if( /$subtitle_tt/o or /$twobuck_tt/o )
2796 $$line = $$line - 2;
2801 return ( $crnt_line, $_ );
2804 #-------------------------------------------------------------------------------
2809 my $crnt_menu = shift;
2813 my ( $menuTitle, $mneumonic, $helpName, $hideIt );
2818 $end_index = scalar( @$crnt_menu );
2822 $nl1 = $name_length+6; # for HELP_ and comma
2823 $nl2 = $name_length+3; # for 2 double quotes and comma
2825 #----------------------------------------
2826 # For every node of the menu tree...
2827 #----------------------------------------
2828 foreach $menuItem ( @$crnt_menu )
2830 if ( $menuItem =~ /$menu_record/ )
2835 ($menuTitle=$2) =~ s/_//;
2838 #---------------------------------
2839 # ... recursively expand sub-menus
2840 #---------------------------------
2841 if( $menuItem =~ /$subMenuIndicator/ )
2843 ($menu = $menuTitle) =~ s/ /_/g;
2844 printf $stream "$sep { &H_M[%2d], $level, %-${nl1}.${nl1}s %-${nl2}.${nl2}s $hideIt, '$mneumonic', \"$menuTitle\" }",
2845 $index, "$illegal_help,", "\"$helpName\",";
2846 $index = emit_help_menu( $stream, \@$menu, $level, $index+1 );
2851 $topic = ( $mneumonic eq $separator ) ? "$illegal_help," : "HELP_\U$helpName,";
2852 $helpName = "\"$helpName\",";
2853 $nptr = ( $end_index == 1 && $level == 1 ) ? "NULL" : "&H_M[%2d]";
2855 #---------------------------
2856 # are we at end of the menu?
2857 #---------------------------
2858 if( $end_index == 1 && $level == 1 ) {
2859 print $stream "$sep { NULL, ";
2862 printf $stream "$sep { &H_M[%2d], ", $index;
2864 printf $stream "$level, %-${nl1}.${nl1}s %-${nl2}.${nl2}s $hideIt, '$mneumonic', NULL }", $topic, $helpName;
2869 $end_index-- if $level == 1;
2875 #-------------------------------------------------------------------------------
2880 my $crnt_menu = shift;
2882 emit_copyright( $stream, "$hlptxt -- Nirvana Editor help module data" );
2883 print $stream "char *HelpTitles[] = {\n";
2884 emit_help_label( $stream, $crnt_menu );
2885 print $stream " NULL\n};\n\n";
2888 #-------------------------------------------------------------------------------
2893 my $crnt_menu = shift;
2894 my ( $menuTitle, $mneumonic, $helpName );
2896 #-----------------------------------------------------------------
2897 # Emit help title/labels for only the leaf nodes of the menu tree.
2898 #-----------------------------------------------------------------
2899 foreach $menuItem ( @$crnt_menu )
2901 if ( $menuItem =~ /$menu_record/ )
2905 ($menuTitle = $2) =~ s/_//go;
2908 if( $menuItem =~ /$subMenuIndicator/ )
2910 ($menu = $menuTitle) =~ s/ /_/go;
2911 emit_help_label( $stream, \@$menu );
2913 elsif( $mneumonic ne $separator ) # ... and not a menu separator
2915 print $stream " \"$menuTitle\",\n";
2916 push @hot_tt_links, $menuTitle; # collect for later verification.
2921 #-------------------------------------------------------------------------------
2923 sub emit_help_header # populates NEdit's help_topic.h
2926 my $crnt_menu = shift;
2928 emit_copyright( $stream, "$hlphdr -- Nirvana Editor help display" );
2929 print $stream "#define MAX_HEADING $MAX_HEADER\n";
2930 print $stream "#define STL_HD $linkIndex+1\n";
2931 print $stream "#define STL_LINK $linkIndex\n";
2932 print $stream "#define STL_NM_HEADER '$STYLE_HDR'\n";
2933 print $stream "#define STL_NM_LINK '$STYLE_LINK'\n";
2934 print $stream "#define STYLE_MARKER '$styleMark'\n";
2935 print $stream "#define STYLE_PLAIN '$STYLE_PLAIN'\n";
2936 print $stream "#define TKN_LIST_SIZE $maxTokens\n";
2938 print $stream "enum HelpTopic {\n";
2939 emit_help_topic( $stream, $crnt_menu );
2940 print $stream " HELP_LAST_ENTRY,\n";
2941 print $stream " $illegal_help = 0x7fffffff /* Illegal topic */ \n";
2942 print $stream "};\n";
2944 print $stream "#define NUM_TOPICS HELP_LAST_ENTRY\n";
2948 #-------------------------------------------------------------------------------
2953 my $crnt_menu = shift;
2954 my ( $menuTitle, $mneumonic, $helpName );
2956 #-----------------------------------------------------------------
2957 # Emit help topic name for only the leaf nodes of the menu tree.
2958 #-----------------------------------------------------------------
2959 foreach $menuItem ( @$crnt_menu )
2961 if ( $menuItem =~ /$menu_record/ )
2965 ($menuTitle = $2) =~ s/_//go;
2968 if( $menuItem =~ /$subMenuIndicator/ )
2970 ($menu = $menuTitle) =~ s/ /_/go;
2971 emit_help_topic( $stream, \@$menu );
2973 elsif( $mneumonic ne $separator ) # ... and not a menu separator
2975 print $stream " HELP_\U$helpName,\n";
2980 #-------------------------------------------------------------------------------
2985 my $filename = shift;
2987 my $year = date("y");
2988 my $padlen1 = 76 - length( $filename );
2989 my $padlen2 = 52 - length( $copy_right_holder );
2991 my $pad1 = substr( $blanks, 0, $padlen1 );
2992 my $pad2 = substr( $blanks, 0, $padlen2 );
2994 print $stream "/*******************************************************************************\n";
2995 print $stream "* *\n";
2996 print $stream "* $filename$pad1 *\n";
2997 print $stream "* *\n";
2998 print $stream " Generated on " . date() . " (Do NOT edit!)\n";
2999 print $stream " Source of content from file $setext_file\n";
3000 print $stream "* *\n";
3001 print $stream "* Copyright (c) 1999-$year $copy_right_holder$pad2 *\n";
3002 print $stream "* *\n";
3003 print $stream "* This is free software; you can redistribute it and/or modify it under the *\n";
3004 print $stream "* terms of the GNU General Public License as published by the Free Software *\n";
3005 print $stream "* Foundation; either version 2 of the License, or (at your option) any later *\n";
3006 print $stream "* version. *\n";
3007 print $stream "* *\n";
3008 print $stream "* This software is distributed in the hope that it will be useful, but WITHOUT *\n";
3009 print $stream "* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *\n";
3010 print $stream "* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *\n";
3011 print $stream "* for more details. *\n";
3012 print $stream "* *\n";
3013 print $stream "* You should have received a copy of the GNU General Public License along with *\n";
3014 print $stream "* software; if not, write to the Free Software Foundation, Inc., 59 Temple *\n";
3015 print $stream "* Place, Suite 330, Boston, MA 02111-1307 USA *\n";
3016 print $stream "* *\n";
3017 print $stream "* Nirvana Text Editor *\n";
3018 print $stream "* September 10, 1991 *\n";
3019 print $stream "* *\n";
3020 print $stream "* Written by $copy_right_holder *\n";
3021 print $stream "* *\n";
3022 print $stream "*******************************************************************************/\n";
3027 #-------------------------------------------------------------------------------
3034 Setext - convert Structured Enhanced TEXT into HTML or plain text.
3038 Usage: setext [ -dhtTVw ][-D directory][-H [hfile]][-S [htmlExt]] \
3039 [-c conditional][-v name=value][setext_file [converted_file]]
3041 setext {-mp} [-c conditional][-M menuSuffix][-v name=value] setext_file
3043 The first form of setext is used to convert Structure Enhanced TEXT
3044 documents into HTML or simple text documents.
3045 The second form is specific to generating NEdit help menu code
3046 from a setext document with Menu and Help directives.
3048 -c conditional text definitions, separated by commas.
3049 -d do not automatically make titles hypertext references (HTML only)
3050 -D specify destination directory for separate HTML files. This also sets
3051 the value for the variable HTML_DIR.
3052 -h show this usage clause.
3053 -H convert setext_file to HyperText Markup Language (HTML).
3054 Optional file parameter specifies file containing HTML header
3055 and footer definition overrides. The current defaults are:
3056 $htmlHeader = <HTML>
3057 <TITLE>$HTML_TITLE</TITLE>
3060 $htmlFooter = </BODY>
3062 where $HTML_TITLE is replaced with an appropriate title.
3064 -m generate NEdit help menu code files.
3065 -M name NEdit help code files with this suffix.
3066 -p do option -m and print out NEdit help elements.
3067 -S convert setext_file into separate HTML files.
3068 (the default name extension is 'html', but it can be
3069 changed by specifying it as an argument to this option)
3070 -t convert setext_file to simple text (default).
3071 -T emit setext typotag definitions in use.
3072 -v defines variable name and assigns it the given value.
3073 (more than one occurrence of -v can be made) The variables
3074 are made available for use within the setext document parsing.
3075 -V display the version of this setext script.
3076 -w do not emit warnings about missing variables.
3078 When the converted_file argument is missing, STDOUT is used.
3079 When the setext_file argument is missing, STDIN is used.
3081 To get conditional text within a setext document to be displayed,
3082 supply a definition tag through the -c option. For example,
3084 setext -c NEDITDOC help.etx nedit.doc
3086 would generate a plain text document, nedit.doc, from the source
3087 help.etx, including/excluding text marked with 'NEDITDOC'
3088 conditional text markers, also known as 'maybe' typotags.
3092 This Structured Enhanced TEXT converter produces either HTML or plain
3093 text files from a given setext source. The HTML files produced can
3094 include hypertext references to within itself, or to external
3095 destinations. The setext converter also has the capability of providing
3096 different content in the resulting output files through a conditional
3097 text mechanism, and variable data definitions. All this allows a
3098 publisher to maintain a single, very readable, source while producing
3099 varying content for different output formats and audiences.
3101 When the converted_file argument is missing, STDOUT is used.
3102 When the setext_file argument is missing, STDIN is used. This gives
3103 setext the capability of being a filter to other programs.
3105 To get conditional text within a setext document to be displayed,
3106 supply a definition tag through the -c option. For example,
3108 setext -c NEDITDOC help.etx nedit.doc
3110 would generate a plain text document, nedit.doc, from the source
3111 help.etx, including/excluding text marked with 'NEDITDOC'
3112 conditional text markers, also known as 'maybe' typotags.
3114 Use the -T option to see the set of typotags supported by this
3115 converter. Further explanations of typotags occurs there.
3117 =head2 HTML Generation Examples
3119 The simplest form of HTML generation is:
3121 setext help.etx nedit.html
3122 setext -H help.etx nedit.html
3124 The results will be stored in the current directory in the nedit.html
3127 When the user wants to break up the resulting html file into multiple
3128 files, with cross references between the files, the -S option should
3131 setext -S help.etx nedit.html
3133 The resulting files are broken up according to titled sections and
3134 are placed into the current directory, along with the nedit.html file.
3136 To change the destination of the resulting files, two options are
3137 supplied, the -D and -S options. For instance,
3139 setext -S shtml -D help/nedit help.etx nedit.shtml
3141 The -S option allows the name of the file extension to be altered.
3142 The -D option specifies where the resulting files are going to be
3143 stored. Thus, in the example, all the files will be placed in the
3144 help/nedit directory (relative to the current directory) and will
3145 have ".shtml" as the file extension.
3147 A final nuance has been added to help server side HTML capabilities.
3148 The -H option can be used to specify a file which contains the
3149 definitions of $htmlHeader and $htmlFooter. This will be used to
3150 override that which is supplied by the setext script. For example,
3152 setext -S shtml -H NEdit.ssd help.etx nedit.html
3154 tells setext to use the file NEdit.ssd (server side definition)
3155 to override the HTML header and footer generation. An example of
3156 the contents of this file follows.
3159 '<!--#set var="menu" value="documentation" -->' . "\n" .
3160 '<!--#include virtual="/head.shtml"-->' . "\n";
3163 '<!--#include virtual="/tail.shtml"-->' . "\n";
3165 =head2 NEdit Help Menu
3167 When generating the NEdit help menu code, two files will be produced,
3168 help_data.h and help_topic.h (when the -M option is not used).
3169 These two files contain all the programmatic
3170 data needed to implement hypertext menus within the NEdit program.
3171 The following is an example of a setext invocation which assumes that
3172 the variable 'version' is being used within the help.etx file.
3174 setext -m -v "version=6.0" help.etx
3176 If the -M option is used, its value is appended to the root portion
3177 of the two generated files. For example,
3179 setext -m -c VMS -M _VMS help.etx
3181 will generate the files help_topic_VMS.h and help_data_VMS.h. The
3182 conditional portion of the help menu specifically designated for VMS
3183 will be extracted from the help.etx source.
3185 Below is what is used to guide the generation of 'C'-Motif menus.
3186 Indentation is SIGNIFICANT in the "Menu" directive lines below. It
3187 is used to determine under which menu element another item will belong.
3188 The number of spaces indented is not significant, but items to be placed
3189 in the same menu panel MUST line up at the same indent level.
3190 ALL nodes of this menu "tree" should have help name qualifiers.
3191 These are used to produce the internal lists used by NEdit help code.
3193 By default, the first character of the menu element will be used as a
3194 menu mneumonic key. To use another character in the menu element for
3195 this purpose, surround the character with underscores (eg. I w_a_nt 'a').
3197 The menu title MUST match the one found in the actual help text (sans
3198 special mneumonic key character marking). The help text title may include
3199 underlines (for spaces) when it is a hyperlink target.
3201 The Help-name is used to generate various data structure names. For
3202 instance, the 'start' help name will be used to generate the HelpTopic
3203 enumeration value HELP_START and the character array htxt_start which
3204 holds the actual help text used in the menu dialogs. Consequently, these
3205 names need to be unique and contain only the characters that a 'C'
3206 compiler can digest.
3208 Menu separator lines use a dash (-) character for the Menu Title. They
3209 should also have a unique Help-name.
3211 A numerical value following the Help-name (separated from the name by
3212 a comma and/or spaces) is part of a menu element hiding scheme implemented
3213 in buildHelpMenu (found in 'menu.c'). When the number matches the hideIt
3214 value found in the procedure, that element will effectively become invisible.
3215 This mechanism was created for particular menu features that are not
3216 available to all incarnations of NEdit (in this case, the VMS version).
3218 A "Help" directive is used for all other text used as NEdit help, but
3219 does not show up in the Help menu. The following is a sample of
3220 Menu and Help directives.
3222 .. Menu Title # Help-name
3223 .. ------------------------------------------------------------
3224 .. Menu: Getting Started # start
3225 .. Menu: Basic Operation # basicOp
3226 .. Menu: Selecting Text # select
3227 .. Menu: Finding and Replacing Text # search
3228 .. Menu: Cut and Paste # clipboard
3229 .. Menu: Using the Mouse # mouse
3230 .. Menu: Keyboard Shortcuts # keyboard
3231 .. Menu: S_h_ifting and Filling # fill
3232 .. Menu: F_i_le Format # format
3234 .. Menu: Features for Programming # features
3235 .. Menu: Programming with NEdit # programmer
3236 .. Menu: Tabs/Emulated Tabs # tabs
3237 .. Menu: Auto/Smart Indent # indent
3238 .. Menu: Syntax Highlighting # syntax
3239 .. Menu: Finding Declarations (ctags) # tags
3241 .. Menu: Regular Expressions # regex
3242 .. Menu: Basic Syntax # basicSyntax
3243 .. Menu: Metacharacters # escapeSequences
3244 .. Menu: Parenthetical Constructs # parenConstructs
3245 .. Menu: Advanced Topics # advancedTopics
3246 .. Menu: Examples # examples
3248 .. Menu: Macro/Shell Extensions # extensions
3249 .. Menu: Shell Commands and Filters # shell, 1
3250 .. Menu: Learn/Replay # learn
3251 .. Menu: Macro Language # macro_lang
3252 .. Menu: M_a_cro Subroutines # macro_subrs
3253 .. Menu: Action Routines # actions
3255 .. Menu: Customizing # customizing
3256 .. Menu: Customizing NEdit # customize
3257 .. Menu: Preferences # preferences
3258 .. Menu: X Resources # resources
3259 .. Menu: Key Binding # binding
3260 .. Menu: Highlighting Patterns # patterns
3261 .. Menu: Smart Indent Macros # smart_indent
3263 .. Menu: NEdit Command Line # command_line
3264 .. Menu: Client/Server Mode # server
3265 .. Menu: Cr_a_sh Recovery # recovery
3266 .. Menu: ---------------------------------- # separator1
3267 .. Menu: Version # version
3268 .. Menu: Distribution Policy # distribution
3269 .. Menu: Mailing _L_ists # mailing_list
3270 .. Menu: Problems/Defects # defects
3271 .. ------------------------------------------------------------
3272 .. Help: Tabs Dialog # tabs_dialog