Don't quit if getpwuid() fails. It can fail if some nameservices are not
[nedit.git] / doc / setext
blob0a9ef6183ce625f6974608f88355ecca839577b8
2 eval 'exec perl -S $0 ${1+"$@"}'
3     if $running_under_some_shell;
5 #-----------------------------------------------------------------------------
7 # setext.pl -- Structure Enhanced Text Converter (to HTML or simple text)
8
9 # $Id: setext,v 1.10 2002/11/15 12:21:14 edg Exp $
10
11 # Copyright (c) 2000 Steven Haehn
12
13 # This is free software; you can redistribute it and/or modify it under the   
14 # terms of the GNU General Public License as published by the Free Software   
15 # Foundation; either version 2 of the License, or (at your option) any later  
16 # version.                                                                    
17 #                                                                             
18 # This software is distributed in the hope that it will be useful, but WITHOUT
19 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       
20 # FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
21 # for more details.                                                           
22 #                                                                             
23 # You should have received a copy of the GNU General Public License along with
24 # software; if not, write to the Free Software Foundation, Inc., 59 Temple    
25 # Place, Suite 330, Boston, MA  02111-1307 USA                                
26
27 #-----------------------------------------------------------------------------
29 # The concept of setext documents is the brain child of Ian Feldman.
30 # Some typotag terms used herein were originally implemented in a perl script
31 # by Tony Sanders, which is the inspirational source for this work
32 # (http://www.bsdi.com/setext). This perl script understands the original
33 # typotags, plus extras needed for hypertext links, conditional text, and
34 # variables.
36 # Samples of setext documents are regularly provided to those folks which
37 # receive the TidBITS publication from www.tidbits.com in their e-mail.
39 # This program is really two programs crammed into one file. The two separate
40 # pieces share lots of code. Instead of having 3 separate files, one of
41 # them being a perl library with the shared code, there was a desire to keep
42 # everything rolled up in one suitcase.
44 #-----------------------------------------------------------------------------
46 # GENERAL TRANSLATOR ROUTINES    NEDIT HELP SOURCE CODE GENERATION ROUTINES
48 # check_target_reference         collect_internal_hypertext_references
49 # count                          emit_copyright
50 # date                           emit_helpText
51 # emit_paragraph                 emit_helpTitles
52 # emit_setext_definition         emit_help_header
53 # extract_fields                 emit_help_label
54 # extract_menu_info              emit_help_menu
55 # extract_menu_init              emit_help_menu_text
56 # get_menu_item                  emit_help_topic
57 # get_setext                     get_menu_text
58 # is_member                      get_newline
59 # parse_setext                   get_style
60 # recover_extractions            get_style_name
61 # replace_underlines             is_known_link
62 # show_usage                     locate_menu_text
63 # to_state                       make_NEdit_menu_code
64 # translate_setext               print_menu
65 #                                
66 #                                
67 # TYPOTAG TRANSLATION ROUTINES
68
69 # help_bold_tt      text_bold_tt        html_bold_tt
70 # help_bullet_tt    text_bullet_tt      html_bullet_tt
71 # help_emit_line    text_emit_line      html_emit_line
72 # help_final        text_final          html_final
73 # help_finishing    text_finishing      html_finishing
74 # help_hot_tt       text_hot_tt         html_hot_tt
75 # help_indent       text_indent         html_indent
76 # help_init         text_init           html_init,  html_init_title
77 # help_italic_tt    text_italic_tt      html_italic_tt
78 # help_line_break   text_line_break     html_line_break
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 #                                       
90 #                                       
91 #                                       
92 #-----------------------------------------------------------------------------
94 use Getopt::Long;   # for parsing the program command line (GetOptions)
95 use File::Basename; # for trimming off directory names from files (basename)
96 use English;
98 #-------------------------------------------------------------------------------
100 sub emit_version
102     my $version = "1.6";
103     my $date    = "Feb 14, 2002";
104     
105     print "$pgm: Version $version, $date.\n";
106     exit 0;
109 #-------------------------------------------------------------------------------
111 sub show_usage
113     print "\n";
114     print "Usage: $pgm [ -dhHStTVw ][-c conditional][-v name=value] \\\n";
115     print "              [setext_file [converted_file]]\n";
116     print "\n";
117     print "       $pgm {-mp} [-c conditional][-M menuSuffix][-v name=value] setext_file\n";
118     print "\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";
123     print "\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 "  -h show this usage clause.\n";
127     print "  -H convert setext_file to HyperText Markup Language (HTML).\n";
128     print "  -m generate NEdit help menu code files.\n";
129     print "  -M name NEdit help code files with this suffix.\n";
130     print "  -p do option -m and print out NEdit help elements.\n";
131     print "  -S convert setext_file into separate HTML files.\n";
132     print "  -t convert setext_file to simple text (default).\n";
133     print "  -T emit setext typotag definitions in use.\n";
134     print "  -v defines variable name and assigns it the given value.\n";
135     print "     (more than one occurrence of -v can be made) The variables\n";
136     print "     are made available for use within the setext document parsing.\n";
137     print "  -V display the version of this setext script.\n";
138     print "  -w do not emit warnings about missing variables.\n";
139     print "\n";
140     print "  When the converted_file argument is missing, STDOUT is used.\n";
141     print "  When the setext_file argument is missing, STDIN is used.\n";
142     print "\n";
143     print "  To get conditional text within a setext document to be displayed,\n";
144     print "  supply a definition tag through the -c option. For example,\n";
145     print "\n";
146     print "          $pgm -c NEDITDOC help.etx nedit.doc\n";
147     print "\n";
148     print "  would generate a plain text document, nedit.doc, from the source\n";
149     print "  help.etx, including/excluding text marked with 'NEDITDOC'\n";
150     print "  conditional text markers, also known as 'maybe' typotags.\n";
151     print "\n";
153     exit 0;
156 #---------------------------------------------------------------------------
157 # This is a GetOptions call back function for gleaning variables from
158 # the command line so that they can be available to the setext parsing
159 # without having to appear in the setext document. The expected form
160 # on the command line is: -v variableName=value. For example, -v version=5.2
161 #---------------------------------------------------------------------------
162 sub declare_variable
164     my $optionName  = shift;
165     my $optionValue = shift;
166     my ( $varName, $varValue ) = split( "=", $optionValue );
167     
168     $varValue or do { 
169        print STDERR "Missing value for variable '$varName'\n"; 
170        $Getopt::Long::error++; 
171        return 
172        };
173     
174     #-----------------------------------------------------
175     # By trimming off leading and trailing spaces allows
176     # data entry like this: "version = 5.2 of Oct. 2001".
177     #-----------------------------------------------------
178     $varName  =~ s/$trim_spaces/$2/o;
179     $varValue =~ s/$trim_spaces/$2/o;
180     
181     $variables{ $varName } = $varValue;
184 #-------------------------------------------------------------------------------
186 sub emit_setext_definition
188     print <<END_OF_DEFINITION_TEXT;
190 Typotags Available
191 ------------------
193  The following table contains typotags recognized by
194  $pgm. The "setext form" column in the table
195  is formatted such that the left most character of
196  the column represents the first character in a line
197  of setext. The circumflex character (^) means that
198  the characters of the typotag are significant only
199  when they are anchored to the front of the setext
200  line. This definition is a sample of a setext document.
201  Consequently, it must be put through the program so
202  that you can view the actual "setext form" of some
203  of the typotags. Thus, issue the following commands
204  to get a proper text view of the table below.
206      $pgm -T > typotags.etx
207      $pgm -w typotags.etx
209  ============  ===================  ==================
210 !     name of  setext form          acted upon or
211 ! the typotag  of typotag           displayed as
212 !============  ===================  ==================
213 !    title-tt "Title                a title
214 !              ====="               in chosen style
215 !------------  -------------------  ------------------
216 !  subhead-tt "Subhead              a subhead
217 !              -------"             in chosen style
218 !------------  -------------------  ------------------
219 !  section-tt ^#> section-text      a section heading
220 !                                   with '#' from 1..9
221 !                                   in chosen style
222 !------------  -------------------  ------------------
223 !   indent-tt ^  lines indented     lines undented
224 !             ^  by 2 spaces        and unfolded
225 !------------  -------------------  ------------------
226 !     bold-tt      **[multi]word**  1+ bold word(s)
227 !   italic-tt         ~multi word~  1+ italic word(s)
228 !underline-tt       [_multi]_word_  underlined text
229 !      hot-tt        [multi_]word_  1+ hot word(s)
230 !    quote-tt ^>[space][text]       > [mono-spaced]
231 !   bullet-tt ^*[space][text]       [bullet] [text]
232 !  untouch-tt  `_quoted typotag!_`  `_left alone!_`
233 !  notouch-tt ^!followed by text    text-left-alone
234 !    field-tt     |>name[=value]<|  value of name
235 !     line-tt ^   ---               horizontal rule
236 !------------  -------------------  ------------------
237 !     href-tt ^.. \@_word URL         jump to address
238 !     note-tt ^.. \@_word Note:("*")  ("cause error")
239 !   target-tt     \@_[multi_]word     [multi ]word
240 !------------  -------------------  ------------------
241 !  twobuck-tt  \$\$ [last on a line]  [parse another]
242 ! suppress-tt ^..[space][not dot]   [line hidden]
243 !   twodot-tt ^..[alone on a line]  [taken note of]
244 !------------  -------------------  ------------------
245 !    maybe-tt ^.. ? name[~] text    show text when
246 !                                   name defined
247 ! maybenot-tt ^.. ! name[~] text    show text when
248 !                                   name NOT defined
249 ! endmaybe-tt ^.. ~ name            end of a multi-
250 !                                   line maybe[not]-tt 
251 !------------  -------------------  ------------------
252 ! passthru-tt ^!![text]             text emitted
253 !                                   without processing
254 !------------  -------------------  ------------------
255 !   escape-tt  @\@x where 'x'  is     x is what remains
256 !              escaped character    @@@@ needed for 1 @@
257  ============  ===================  ==================
259  Only one instance of the element subhead-tt (or, in its
260  absence, title-tt) is absolutely _required_ for a text to
261  be considered a valid setext.
263  All the elements, but subhead-tt, are in effect optional,
264  that is, not necessary for a setext to be declared as
265  such. The target-tt element allows the hypertext link
266  definition of href-tt to be within the same setext. The
267  actual reference (href-tt) of the target would look like:
269     .. _word #reference_within_document
271 !Multiple line maybe[not]-tt (conditional text regions)
272 !are introduced as ".. ? name~" or ".. ! name~" and are
273 !terminated with ".. ~ name", on a separate line. Single
274 !line maybe[not]-tt do not use the '~' character and are
275 !terminated with the end of the line. The special
276 !conditional text region named "html" allows a mixture of
277 !setext and HTML tags. Nesting of these typotags is
278 !allowed. For instance, if there are three conditional
279 !regions, A, B, and C, C can be nested inside B, which can
280 !be nested inside A (eg. A-B-C...C-B-A). Note that a
281 !surrounding region cannot end before one of its inner
282 !regions is terminated (eg. of illegal nesting
283 !A-B-C...C-A-B, where A terminated prior to B.
285  Field typotags are used to define and reference values.
286  Field definitions can only occur within a suppress-tt.
287  For example:  "..  `|>author=Steven Haehn<|`"
288  Field references (eg. |>author<|) can occur in any 
289  printable text. If there is no known value for the 
290  field, it will remain unchanged and appear as written
291  in the setext.
292 END_OF_DEFINITION_TEXT
294     #---------------------------------------------------------------
295     # Emit any predefined variables so user knows what is available.
296     #---------------------------------------------------------------
297     if( %variables )
298     {
299         print "\n";
300         print " The following are predefined for use in a field-tt\n";
301         print " for any setext document translated by this utility.\n";
302         print "\n";
303         
304         foreach $key ( sort keys %variables )
305         {
306             print "    $key = $variables{$key}\n";
307         }
308     }
309     
310     print "\n \$\$\n";
311     exit 0;
314 #-------------------------------------------------------------------------------
316 $pgm = basename( $PROGRAM_NAME );
318 #==========================
319 # Global shared definitions
320 #==========================
321 $um          = "\375"; # untouchable marker
322 $vm          = "\374"; # variable marker
323 $escMrk      = "\33";  # internal escape marker
324 $trim_spaces = '(\s*)(.*?)(\s*)$';
325 %variables   = ( date => &date(), Date => &date("D"), year => &date("y") );
326 @cond_text_definitions = ();
327 $make_title_href = 1;
329 #---------------------------------------------------------
330 # Look for following options, complain about unknown ones.
331 #---------------------------------------------------------
332 Getopt::Long::config( "noignorecase" );
334 GetOptions( 
336     'c=s',  # conditional text definitions, separated by commas
337     'd',    # do not make titles hypertext references (HTML only)
338     'h',      \&show_usage,
339     'H',    # create HTML from setext input
340     'm',    # create NEdit help menu code from setext input
341     'M=s',  # name NEdit help code files with this suffix
342     'p',    # same as 'm' but with debug printout
343     'S',    # generate separate HTML files for each subsection
344     't',    # create text from setext input
345     'T',    # emit setext typo-tag document
346     'v=s',    \&declare_variable,
347     'V',    # emit setext script version information
348     'w'     # do not emit warning messages.
350 ) || &show_usage;
352 #-----------------------------------
353 # Glean only those options specified
354 #-----------------------------------
355 $opt_c && (@cond_text_definitions = split( ",", $opt_c ));
356 $opt_d && ($make_title_href=0);
357 $opt_h && show_usage();
358 $opt_H && ($convert_to = "html");
359 $opt_m && do { $make_menu = 1; $convert_to = "help" };
360 $opt_M && ($helpSuffix = $opt_M );
361 $opt_p && do { $make_menu = 1; $convert_to = "help"; $print_menu = 1 };
362 $opt_S && do { $separate_html_files=1; $make_title_href=1 };
363 $opt_t && ($convert_to = "text");
364 $opt_T && emit_setext_definition();
365 $opt_V && (emit_version());
366 $opt_w && ($noWarn = 1);
368 #--------------------------------------------------------------
369 # Setext Parser states.
371 # The names are used to construct "enter_" & "leave_" elements
372 # in the state_change hash table required to be initialized
373 # by language specific initialization routines (see html_init).
374 #--------------------------------------------------------------
375 $FMT     = "f";
376 $LIST    = "list";
377 $PRE_FMT = "pre";
378 $QUOTE   = "quote";
380 #----------------------------
381 # Typotag Pattern Definitions
382 #----------------------------
383 $bold_tt       = '\*\*([^\*]+)\*\*([^\*]|$)';
384 $bullet_tt     = '^\* ([^ ])';
385 $empty_line    = '^\s*$';
386 $fld_left      = '\|>';
387 $fld_right     = '<\|';
388 $field_tt      = "(${fld_left}[^<]+$fld_right)";
389 $field_content = "${fld_left}([^<]+)$fld_right";
390 $hot_tt        = '\b([\S]*)_\b';
391 $href_tt       = '^\.\.\s+_([\S]*)\s+(.*)\s*';
392 $indent_tt     = '^  ([^ ])';
393 $intHrefMrk    = "#";
394 $internal_href = "^$intHrefMrk(.*)\$";
395 $italic_tt     = '~([^~]*)~';
396 $line_tt       = '^   ---*$';
397 $notouch_tt    = '^!';
398 $passthru_tt   = '^!!';
399 $quote_tt      = '^> ';
400 $section_tt    = '^([1-6])>';
401 $subtitle_tt   = '^---';
402 $suppress_tt   = '^\.\.';
403 $target_tt     = '(?!(^|\s)_[\S]+_(\s|\W|$))(^|\s)_([\S]+)'; # not underline, then target
404 $title_tt      = '^===';
405 $twobuck_tt    = '^\s*\$\$\s*$';
406 $underline_tt  = '\b_([\S]*)_\b';
407 $untouch_tt    = "\\s*(`[^`]+[`'])(?=\\s|\\W|\$)";
408 $variable_def  = '\s*(\w+)\s*([^=]*(=(.+)))?'; # $1 = name, $4 = value
410 $escape_tt     = "@"; # the character escape symbol (need @@ to escape @)
411 $needEscaping  = "$escape_tt(.)";
412 $escapedFound  = "$escMrk(\\d+)$escMrk";
414 if( $make_menu )
416     $setext_file = $ARGV[0];
417     open SETEXT, "<$setext_file" or die "Can't access $setext_file, $OS_ERROR";
418     make_NEdit_menu_code();
419 }    
420 else  # Global elements for parsing setext
422     #-------------------------
423     # Program option defaults.
424     #-------------------------
425     $setext_file    = "-";  # STDIN, allows program to be used as a filter
426     $converted_file = "-";  # STDOUT
427     $convert_to     = "text" if $convert_to eq "";
428     
429     #--------------------------------------
430     # Begin processing file specifications.
431     #--------------------------------------
432     $setext_file = $ARGV[0] if $ARGV[0] ne "";
433     open SETEXT, "<$setext_file" or die "Can't access $setext_file, $OS_ERROR";
435     if( $ARGV[1] ne "" ) 
436     { 
437         $converted_file = $ARGV[1];
438         $convert_to = "html" if $converted_file =~ /\.html$/; # in case -H forgotten
439     }
441     open CONVERT, ">$converted_file" or die "Can't create $converted_file, $OS_ERROR";
442     translate_setext();
445 #-------------------------------------------------------------------------------
446 #-------------------------------------------------------------------------------
447 #-------------------------------------------------------------------------------
449 sub translate_setext
451     #--------------------------------------
452     # Adding conversion type to conditional
453     # text definitions for convenience.
454     #--------------------------------------
455     push @cond_text_definitions, $convert_to;
457     get_setext( SETEXT, \@cond_text_definitions, \@data );
458     
459     extract_menu_info( \@data )
460        if( $convert_to eq "html" && $separate_html_files );
462     chomp @data;        # remove the newline character from each line.
463     
464     register_tt_translationFunctions( $convert_to );
466     parse_setext( \@data );
469 #-------------------------------------------------------------------------------
471 sub make_NEdit_menu_code
473     #--------------------------------
474     # Supply a default NEdit version.
475     #--------------------------------
476     $neditDefaultMarker   = "NEdit release of ";
477     $variables{ version } = $neditDefaultMarker . date() 
478        if (not exists $variables{ version } or 
479           $variables{ version } eq "default");
480     
481     #--------------------------------------
482     # Adding conversion type to conditional
483     # text definitions for convenience.
484     #--------------------------------------
485     push @cond_text_definitions, $convert_to;
487     get_setext( SETEXT, \@cond_text_definitions, \@data );
488     extract_menu_info( \@data );
489     register_tt_translationFunctions( $convert_to );
492 #-------------------------------------------------------------------------------
494 sub parse_setext
496     my $setextData = shift;
497     
498     local($crnt_state, $fold, $a, $i, $unt, $lineNo);
500     $crnt_state    = $FMT;
501     $lineNo        = -1;
502     @untouchable   = ();
503     $fold          = 0;
505     foreach (@$setextData) 
506     {
507         $lineNo++;  # current location in data array
508         
509         #--------------------------
510         # process title information
511         #--------------------------
512         (/$title_tt/i or /$subtitle_tt/i) && do { 
513             &$do_title(); 
514             $fold = 0; 
515             next; 
516             };
517             
518         /$section_tt/o && do { 
519             &$do_section_tt($1); 
520             $fold = 0; 
521             next;
522             };
523         
524         /$passthru_tt/ && do { 
525             &$do_emit_line();
526             next;
527             };
528         
529         next if ( /$suppress_tt/ or /$twobuck_tt/ );
531         #--------------------------------------------------
532         # handle line breaks, only one empty line gets out.
533         #--------------------------------------------------
534         if ( /$empty_line/) {
535             to_state( $FMT ); 
536             $fold = &$do_line_break( $fold );
537             next; 
538         }
539         
540         $fold = 0;  # no more empty lines
542         /$line_tt/ && do { &$do_line_tt(); next; };
543         
544         #------------------
545         # State transitions
546         #------------------
547         if    ( /$quote_tt/o  ) { &to_state( $QUOTE )   }
548         elsif ( /$bullet_tt/o ) { &to_state( $LIST )    }
549         elsif ( /$indent_tt/o ) { &to_state( $FMT )     }
550         else                    { &to_state( $PRE_FMT ) }
552         if( /$notouch_tt/o ) { s/$notouch_tt/ /o; }
553         else
554         {
555             #--------------------------------------------
556             # Handle the untouchables first.
557             # Mark their locations for later replacement.
558             # (see recover_extractions)
559             #--------------------------------------------
560             for( $i = scalar( @untouchable ); /$untouch_tt/o; $i++ )
561             {
562                 $unt = $1;
563                 $unlen = length( $unt );
564                 $unloc = index( $_, $unt );
565                 $untouchable[ $i ] = $unt; 
566                 $front = substr( $_, 0, $unloc );
567                 $back  = substr( $_, $unloc+$unlen );
568                 $_ = $front . $um . $back; 
569             }
571             &$do_bullet_tt();
572             &$do_quote_tt();
573             &$do_bold_tt();
574             &$do_italic_tt();
575             &$do_underline_tt();
576             &$do_target_tt();
577             &$do_hot_tt();
578             &$do_indent_tt();
579         }
580         &$do_emit_line();
581     }
582     
583     &$do_final();
586 #-------------------------------------------------------------------------------
588 sub register_tt_translationFunctions
590     my $conversion_type = shift;
591     
592     #----------------------------------------------------
593     # Register call-back functions for typotag processing
594     #----------------------------------------------------
595     $do_bold_tt       = "${conversion_type}_bold_tt";
596     $do_bullet_tt     = "${conversion_type}_bullet_tt";
597     $do_emit_line     = "${conversion_type}_emit_line";
598     $do_final         = "${conversion_type}_final";
599     $do_hot_tt        = "${conversion_type}_hot_tt";
600     $do_indent_tt     = "${conversion_type}_indent";
601     $do_initialize    = "${conversion_type}_init";
602     $do_italic_tt     = "${conversion_type}_italic_tt";
603     $do_line_break    = "${conversion_type}_line_break";
604     $do_line_tt       = "${conversion_type}_line_tt";
605     $do_quote_tt      = "${conversion_type}_quote_tt";
606     $do_section_tt    = "${conversion_type}_section_tt";
607     $do_target_tt     = "${conversion_type}_target_tt";
608     $do_title         = "${conversion_type}_title";
609     $do_underline_tt  = "${conversion_type}_underline_tt";
611     &$do_initialize;  # do any necessary initialization
614 #-------------------------------------------------------------------------------
616 sub date
618     $format = $_[0];
619     
620     ( $sec,$min,$hour,$mday,$mon,$year,@ignore ) = localtime( time );
621     $month = (January,February,March,April,May,June,July,
622               August,September,October,November,December)[$mon];
623     $year  = $year + 1900;
624     
625     return $year if $format eq "y";
626     return "$month $mday, $year" if $format eq "D";
627     return substr($month,0,3) . " $mday, $year";
630 #-------------------------------------------------------------------------------
632 sub to_state 
634     my $given_state = shift;
635     
636     if ( $crnt_state ne $given_state ) 
637     {
638         if( exists  $state_change{ "leave_$crnt_state"  } )
639         {
640             $doStateChange = $state_change{ "leave_$crnt_state"  };
641             &$doStateChange();
642         }
644         if( exists  $state_change{ "enter_$given_state" } )
645         {
646             $doStateChange = $state_change{ "enter_$given_state"  };
647             &$doStateChange();
648         }
650         $crnt_state = $given_state;
651     }
654 #-------------------------------------------------------------------------------
656 sub count
658     my $whatToCount = shift;
659     my $line        = shift;
660     my $howMany     = 0;
661     
662     $howMany++ while( $line =~ /$whatToCount/g );
663     return $howMany;
666 #-------------------------------------------------------------------------------
668 sub extract_fields
670     local $_ = shift;
671     local $cond_text_region = shift;
672     
673     my ( $field, $variable, $flen, $floc, $front, $back, $v_name, $v_value );
674     my @variable_list = ();
676     #------------------------------------------
677     # Mark all the escaped character sequences.
678     #------------------------------------------
679     while( /$needEscaping/o )
680     {
681         $subChar = ord( $1 );
682         s/$needEscaping/$escMrk$subChar$escMrk/o;
683     }
685     #-----------------------------------------------------
686     # Collect any field typotags found for later expansion.
687     #-----------------------------------------------------
688     while( /$field_tt/o )
689     {
690         $field = $1;
691         $field =~ /$field_content/ && ( $variable = $1 );
692         
693         if( $variable =~ /$variable_def/ ) {
694         
695             $v_name = $1;
696             
697             #----------------------------------------------
698             # When fields 2 and 3 contain identical strings
699             # then a valid field has been encountered.
700             #----------------------------------------------
701             if( $2 eq $3 ) {
702                 $v_value = $4;
703             }
704             else
705             {
706                 #-----------------------------------
707                 # This is NOT a variable definition.
708                 # Have to recover original string.
709                 #-----------------------------------
710                 $v_name  = "_A_${v_name}_Z_"; #internal name
711                 $v_value = $variable;
712             }
713             
714             #----------------------------------------
715             # Is this only a reference to a variable?
716             #----------------------------------------
717             if ($v_value eq "") { 
718                 #------------------------------------------------
719                 # Only put definitions in the list when it is not
720                 # part of a comment. (comments are not emitted)
721                 #------------------------------------------------
722                 push @variable_list, $v_name unless /$suppress_tt/o;
723             }
724             else {
725                 #------------------------------------------------
726                 # setting the variable ( |>varName = value<| )
727                 # (here $v_value is the value assignment portion)
728                 #------------------------------------------------
729                 if( /$suppress_tt/o ) {
730                     $variables{ $v_name } = $v_value;
731                 } else {
732                     push @variable_list, $variable;
733                 }
734             }
735         }
736         
737         #--------------------------------------
738         # Remove field and replace with marker.
739         #--------------------------------------
740         $flen  = length( $field );
741         $floc  = index( $_, $field );
742         $front = substr( $_, 0, $floc );
743         $back  = substr( $_, $floc+$flen );
744         $_ = $front . $vm . $back; 
745     }
747     #----------------------------
748     # Fill in any variables found
749     #----------------------------
750     foreach $element ( @variable_list ) 
751     {
752         if( exists $variables{ $element } ) {
753             $value = $variables{ $element }
754         } else {
755             $value = "|>$element<|";
756             print STDERR "$pgm: Undefined variable '$element' used in $setext_file.\n" unless $noWarn;
757         }
758         s/$vm/$value/;
759     }
760     
761     #--------------------------------------------------------
762     # When in a conditional text region that only applies to
763     # HTML translation, change the angle brackets to internal
764     # definitions that will be fixed later. This should allow
765     # for a mixture of setext and HTML language together.
766     #--------------------------------------------------------
767     if ( $cond_text_region eq "html" )
768     {
769         s/</${lt}/go;
770         s/>/${gt}/go;
771         s/\&/${amp}/go;
772     }
773     return $_;
776 #===================================================================
777 # Import setext data from given data stream and pay attention to
778 # conditional text considerations, as described below.
780 #   ^.. ? name   Conditional text when 'name' is defined.
781 #   ^.. ! name   Conditional text when 'name' is NOT defined.
783 #   ^.. ? name~
784 #         Multiple line conditional text when 'name' is defined.
785 #         (without suppress-tt, will always appear in translated
786 #         document going through non-conditional setext conversion)
787 #   ^.. ~ name
789 #   ^.. ! name~
790 #         Multiple line conditional text when 'name' is NOT defined.
791 #         (without suppress-tt, will always appear in translated
792 #         document going through non-conditional setext conversion)
793 #   ^.. ~ name
795 # This procedure also extracts and applies variable definitions
796 # to the text to be emitted.
797 #===================================================================
799 sub get_setext
801     my $stream = shift;
802     my $cond_text_definitions = shift;
803     my $data = shift;
805     my $conditional_text_marker = '^\.\. ([\?!~])\s*(\S+)\s?(.*)$';
806     my $lineNbr = 0;
807     my $i = 0;
808     my $element = "";
809     my ($tense,$def_nm,$text,$multi_line,$crnt_def);
810     my @cond_text_stack = ();
812     while( $_ = <$stream> )
813     {
814         $lineNbr++;
815         
816         if( /$conditional_text_marker/o )
817         {
818             $tense      = $1;  # positive, negative, or end-of conditional text
819             $def_nm     = $2;
820             $text       = $3;
821             
822             $multi_line = $def_nm =~ s/~//o;
823             
824             #---------------------------------------------
825             # Reach end of multiple line conditional text?
826             #---------------------------------------------
827             if( $tense eq "~" )
828             {
829                 $crnt_def = substr( pop @cond_text_stack, 1 );
830                 
831                 if( $crnt_def ne $def_nm )
832                 {
833                     print STDERR "Incorrectly nested conditinal text sections near line $lineNbr.\n";
834                     print STDERR "Expected end of '$crnt_def', but saw end of '$def_nm'\n";
835                     exit 1;
836                 }
837             }
838             else
839             {
840                 #-----------------------------------------
841                 # Entering multiple line conditional text?
842                 #-----------------------------------------
843                 if( $multi_line ) {
844                     push @cond_text_stack, "$tense$def_nm";
845                 }
846     
847                 #------------------------------------------
848                 # This will also catch any non-space 
849                 # text found on multiple line conditionals.
850                 #------------------------------------------
851                 if( $text =~ /\S/o )
852                 {
853                     $$data[$i++] = extract_fields( "$text\n", $def_nm ) 
854                        if ($tense eq "?") and is_member( $def_nm, $cond_text_definitions );
855                     $$data[$i++] = extract_fields( "$text\n", $def_nm ) 
856                        if ($tense eq "!") and not is_member( $def_nm, $cond_text_definitions );
857                 }
858             }
859         }
860         elsif( scalar( @cond_text_stack ) == 0 )
861         {
862             $$data[$i++] = extract_fields( $_, "" );
863         }
864         else
865         {
866             #--------------------------------------------------------------------
867             # The top element of the conditional text stack is the current
868             # conditional text area. See if it exists in the definitions list.
869             # When present, we want this line of text, depending on 'tense'.
870             #--------------------------------------------------------------------
871             $element = $cond_text_stack[-1];
872             $tense   = substr( $element, 0, 1 );
873             $def_nm  = substr( $element, 1 );
874                 
875             if( $tense eq "?") 
876             {
877                 if( is_member( $def_nm, $cond_text_definitions ) ) {
878                     s/$suppress_tt //o; 
879                     $$data[$i++] = extract_fields( $_, $def_nm );
880                 }
881             }
882             elsif( ! is_member( $def_nm, $cond_text_definitions ) )
883             {
884                 s/$suppress_tt //o;
885                 $$data[$i++] = extract_fields( $_, $def_nm );
886             }
887         }
888     }
891 #-------------------------------------------------------------------------------
893 sub extract_menu_init
895     %MenuNames    = ();
896     @helpMenu     = ();
897     @menuStack    = \@helpMenu;
898     $crntMenu     = \@helpMenu;
899     @indentStack  = ( 0 );
900     $menuLevel    = 0;
901     $comment_ind  = "^\\.\\.";     # setext comment indicator ("..")
902     $menu_element = "${comment_ind} Menu: ";
903     $help_element = "${comment_ind} Help: ";
904     $drop_marker  = "_(.)_";
905     $separator    = "-";
906     $help_code    = 9; # special hide-it code indicating not part of help menu
907     $name_length  = 0; # determines padding alignment in HelpMenu data emission
908     $crntIndent   = 0;
909     $subMenuIndicator = "\377";
912 #-------------------------------------------------------------------------------
914 sub extract_menu_info
916     my $thisData  = shift;
917     my $dataIndex = 0;
919     extract_menu_init();
920     
921     #----------------------------------------------------------------------
922     # For each and every menu item found in the original data (*.etx) file.
923     #----------------------------------------------------------------------
924     while( $_ = get_menu_item( $thisData, \$dataIndex ) )
925     {
926         #----------------------------------------------------------------------
927         # Here we want to extract the menu title, help name, optional hideIt
928         # numerical indicator, and optional menu association name.
929         #
930         # Expecting:  MenuTitle # HelpName [[,]HideItIndicator] [# Association]
931         #----------------------------------------------------------------------
932         if( /^([^#]+)#\s*(\w*)(\s*,\s*)?(\d+)?(\s*#\s*)?(\w+)?/o )
933         {
934             $menuTitle = $1;
935             $helpName  = $2;
936             $hideItInd = ($4 eq "") ? "0" : $4;
937             $assocName = ($6 eq "") ? $helpName : $6;
938             $helpName  =~ s/$trim_spaces/$2/;
939             $assocName =~ s/$trim_spaces/$2/;
941             #------------------------------------------------
942             # Determine to which menu this menu item belongs
943             # using leading whitespace indentation.
944             # Extract menu character mneumonic.
945             #------------------------------------------------
946             $menuTitle =~ /^(\s*)/ && ($nextMenu = length($1)-$crntIndent);
947             $menuTitle =~ s/$trim_spaces/$2/o;
949             $mneumonic = (/$drop_marker/) ? $1 : substr( $menuTitle, 0, 1 );
951             #--------------------------------------------------
952             # Identation greater than previous menu element
953             # indicates that this element is part of a submenu.
954             #--------------------------------------------------
955             if( $nextMenu > 0 )
956             {
957                 @$crntMenu[ $end ] .= $subMenuIndicator; # mark previous element
958                 ($menu = $previousTitle) =~ s/ /_/g;
959                 @$menu = ();
960                 push @menuStack, \@$menu;
961                 push @indentStack, $nextMenu;
962                 $menuLevel++;
963             }
964             #--------------------------------------
965             # Indentation less than previous menu 
966             # element indicates leaving a submenu.
967             #--------------------------------------
968             elsif( $nextMenu < 0 )
969             {
970                 $indentLevel = $indentStack[$menuLevel] + $nextMenu;
971                 do {
972                     pop @menuStack;
973                     pop @indentStack;
974                     $menuLevel--;
976                 } while( $indentLevel < $indentStack[$menuLevel] );
977             }
979             $crntIndent += $nextMenu;
980             $crntMenu    = $menuStack[ $#menuStack ];
981             $end = scalar( @$crntMenu );
982             @$crntMenu[ $end ] = "$mneumonic,$menuTitle,$helpName,$hideItInd";
983             $thisTitle = $menuTitle;
984             $thisTitle =~ s/$drop_marker/$1/;
985             $thisTitle =~ s/ /_/go;
986             $MenuNames{ $thisTitle } = "$menuLevel$assocName";
987             $previousTitle     = $menuTitle;
989             #---------------------------------
990             # update data for padding purposes
991             #---------------------------------
992             if( $mneumonic ne $separator and $name_length < length( $helpName ) )
993             {
994                 $name_length = length( $helpName );
995             }
996         }
997     }
1000 #-------------------------------------------------------------------------------
1002 sub get_menu_item
1004     my $setext = shift;
1005     my $line   = shift;
1007     #-------------------------------------------
1008     # Search each and every data line for either
1009     # a '# Menu: ' line or a '# Help: ' line and
1010     # return remainder of the line.
1011     #-------------------------------------------
1012     while( $$line < scalar( @$setext ) )
1013     {
1014         $_ = $$setext[ $$line++ ];
1015         return $_               if s/$menu_element//o;
1016         return "$_, $help_code" if s/$help_element//o;
1017     }
1018     
1019     return "";
1022 #-------------------------------------------------------------------------------
1024 sub check_target_reference
1026     local($_) = @_;
1027     my $index;
1028     my $target = "";
1029     
1030     if( /$target_tt/ ){
1031         $target = $4;
1032     }
1033     #-----------------------------------
1034     # Are all titles automatically being
1035     # made into hypertext references?
1036     #-----------------------------------
1037     elsif( $make_title_href ) { 
1038         /$title_tt/ && ( $target = $2 );
1039         $target =~ s/$trim_spaces/$2/o;
1040         $target =~ s/ /_/go;
1041     }
1043     if( $target ) {
1044         print CONVERT "<A NAME=\"$target\"</A>\n";
1045         
1046         # only one target-tt reference of this kind allowed per file.
1047         ($index = is_member( $target, \@nm_ref )) 
1048             && do{ splice( @nm_ref, $index-1, 1 ); };
1049     }
1052 #-------------------------------------------------------------------------------
1054 sub is_member
1056     $item      = shift;
1057     $this_list = shift;
1058     my $index  = 1;
1059     
1060     foreach $member ( @$this_list )
1061     {
1062         if( $item eq $member )
1063         {
1064             return $index;
1065         }
1066         $index++;
1067     }
1068     
1069     return 0;
1072 #-------------------------------------------------------------------------------
1074 sub replace_underlines
1076     my $pattern = shift;
1077     s#$pattern#($text = $1) =~ s,_, ,go; $text; #eg;
1080 #-------------------------------------------------------------------------------
1082 sub reclaim_escapes
1084     #-----------------------------------------
1085     # Put back any escaped characters in text.
1086     #-----------------------------------------
1087     while( /$escapedFound/ )
1088     {
1089         $subChar = chr( $1 );
1090         s/$escapedFound/$escape_tt$subChar/;
1091     }
1094 #-------------------------------------------------------------------------------
1096 sub recover_extractions
1098     my $element;
1100     #------------------------------------
1101     # Replace escaped characters in text.
1102     #------------------------------------
1103     while( /$escapedFound/ )
1104     {
1105         $subChar = chr( $1 );
1106         s/$escapedFound/$subChar/;
1107     }
1109     foreach $element ( @untouchable )   { s/$um/$element/; }
1110     @untouchable = ();
1113 #-------------------------------------------------------------------------------
1115 sub emit_paragraph
1117     my $paragraph = shift;
1118     my $line = $left_margin;
1119     
1120     @words = split ' ', $paragraph;
1122     #-------------------------------------------------------------
1123     # Flow words onto a line up until the right margin is reached.
1124     #-------------------------------------------------------------
1125     foreach $word ( @words )
1126     {
1127         if( length( $line ) + length( $word ) + 1 <= $right_margin )
1128         {
1129             $line = "$line$word ";
1130         }
1131         else
1132         {
1133             print CONVERT "$line\n";
1134             $line = "$left_margin$word ";
1135         }
1136     }
1137     
1138     #--------------------
1139     # emit any remainder.
1140     #--------------------
1141     print CONVERT "$line\n" if( length( $line ) > length( $left_margin ) );
1144 #-------------------------------------------------------------------------------
1145 #                setext to text conversion call-back routines.
1146 #                         ( in alphabetical order )
1147 #-------------------------------------------------------------------------------
1149 sub text_bold_tt      { s/$bold_tt/$1$2/g }
1151 #-------------------------------------------------------------------------------
1153 sub text_bullet_tt
1155     #   don't do anything if this is no bulleted line.
1156     if (/$bullet_tt/)
1157     {
1158         #   remove lead-in from paragraph and put the rest in an array
1159         my $paragraph = $_;
1160         $paragraph =~ s/$bullet_tt/$1/;
1161         @words = split ' ', $paragraph;
1162         $paragraph = "";
1163         
1164         #   start with text mode bullet character
1165         my $line = '    * ';
1166         foreach $word (@words)
1167         {
1168             if (length($line) + length($word) + 1 <= $right_margin)
1169             {
1170                 #   put every word in a line if there's still room
1171                 $line = "$line$word ";
1172             } else
1173             {
1174                 #   append line to paragraph if full and start a new line
1175                 $paragraph = "$paragraph$line\n";
1176                 $line = "      $word ";
1177             }
1178         }
1179         #   get last line
1180         $paragraph = "$paragraph$line";
1182         #   remove trailing white space
1183         $paragraph =~ s/\s$//;
1184         $_ = $paragraph;
1185     }
1188 #-------------------------------------------------------------------------------
1190 sub text_emit_line
1192     if( /$passthru_tt/ )
1193     {
1194         s/$passthru_tt//o;  # remove typotag and pass line out as is.
1195         reclaim_escapes();
1196         print CONVERT "$_\n";
1197     }
1198     else
1199     {
1200         if( $crnt_state ne $FMT && $text_unfolded_line ne "" )
1201         {
1202             emit_paragraph( &text_finishing($text_unfolded_line) );
1203             $text_unfolded_line = "";
1204         }
1206         print CONVERT &text_finishing( $_ ), "\n" unless $_ eq $indentingMode;
1207     }
1210 #-------------------------------------------------------------------------------
1212 sub text_final { emit_paragraph( &text_finishing($text_unfolded_line) ) }
1214 #-------------------------------------------------------------------------------
1216 sub text_finishing
1218     local($_) = @_;
1219     recover_extractions();
1220     $_;
1223 #-------------------------------------------------------------------------------
1225 sub text_hot_tt
1227     if ( /$hot_tt/ ) {
1228         #---------------------------------------------------------
1229         # The heuristic to prevent Internet addresses from having
1230         # underlines removed, is to check for an '@' character.
1231         #---------------------------------------------------------
1232         if (($text = $1) !~ /\@/ ) {
1233             $text =~ s/_/ /g;
1234         }
1235         s/$hot_tt/$text/;
1236     }
1239 #-------------------------------------------------------------------------------
1241 sub text_indent
1243     s/$indent_tt/$1/o && do {
1244         $text_unfolded_line = "$text_unfolded_line$_ ";
1245         $_ = $indentingMode;
1246     };
1249 #-------------------------------------------------------------------------------
1251 sub text_init         
1253     %state_change = ();
1254     $text_unfolded_line = ""; # to be used by text_indent & text_emit_line
1255     $left_margin   = "  ";    # for emit_paragraph
1256     $right_margin  = 79;      # for emit_paragraph
1257     $indentingMode = "?#.";   # hopefully unique string not normally found
1258     
1259     #----------------------------------------------------------------
1260     # Take all the titles, capitalize and remove title indicator.
1261     #----------------------------------------------------------------
1262     for ($i = 0; $i <= $#data; $i++) 
1263     {
1264         $_ = $data[$i];                 # $_ is default for searches
1266         (/$title_tt/ or /$subtitle_tt/) && do {
1267             $titleType = ( /$title_tt/ ) ? "=" : "-";
1268             $data[$i--] = "..";       # suppress title indicator ( --- or === )
1269             $data[$i]   =~ s/^\s*//o; # get rid of any leading space.
1270             $this_title = $data[$i];
1272             # Have to fix title if it also happens to be a target-tt.
1273             $this_title =~ /$target_tt/ && do { ($tmp = $4) =~ s,_, ,go; $this_title = $tmp };
1274             $data[$i] = "..$titleType \U$this_title";
1275         };
1276     }
1278     #----------------------------------------------------
1279     # NOTE: changing original subtitle-tt search pattern
1280     #       to match what was done above.
1281     #----------------------------------------------------
1282     $subtitle_tt = "^\\.\\.- (.*)";
1283     $title_tt    = "^\\.\\.= (.*)";
1286 #-------------------------------------------------------------------------------
1288 sub text_italic_tt    { s/$italic_tt/$1/g }
1290 #-------------------------------------------------------------------------------
1292 sub text_line_break
1294     my $fold = shift;
1295     emit_paragraph( &text_finishing($text_unfolded_line) );
1296     $text_unfolded_line = "";
1297     print CONVERT "\n" unless $fold++;
1298     return $fold;
1301 #-------------------------------------------------------------------------------
1303 sub text_line_tt      { }
1304 sub text_quote_tt     { }
1306 #-------------------------------------------------------------------------------
1308 sub text_section_tt
1310     my $hdr_level = shift;
1312     s/$section_tt//;
1313     print CONVERT "\n  \U$_\n" if $hdr_level <= 3;  # converted to uppercase
1314     print CONVERT "\n  $_\n" if $hdr_level > 3;     # left alone
1318 #-------------------------------------------------------------------------------
1320 sub text_target_tt 
1322     s#$target_tt#($text = $4) =~ s,_, ,go; " $text"; #eg;
1325 #-------------------------------------------------------------------------------
1327 sub text_title
1329     my $size;
1330     my $line = "";
1331     my $lc = substr( $_, 2, 1 );
1332     
1333     #-----------------------------------------------------------------
1334     # Incoming text looks like ..= <title text> or ..- <subtitle text>
1335     #-----------------------------------------------------------------
1336     to_state( $FMT ); 
1337     $_ = substr( $_, 4 );
1338     text_target_tt();
1339     $size = length( $_ );
1340     
1341     #-------------------------------------------------
1342     # Going to wrap titles with lines as long as title
1343     #-------------------------------------------------
1344     for( $size = length( $_ ); $size > 0; $size-- )
1345     {
1346         $line="$line$lc";
1347     }
1348     print CONVERT "$line\n$_\n$line\n";
1351 sub text_underline_tt { replace_underlines( $underline_tt ) }
1353 #-------------------------------------------------------------------------------
1354 #                setext to HTML conversion call-back routines.
1355 #                         ( in alphabetical order )
1356 #-------------------------------------------------------------------------------
1358 sub html_bold_tt
1360     #---------------------------------------
1361     # Turn all "**text**" into "<B>text</B>"
1362     #---------------------------------------
1363     s#$bold_tt#${lt}B${gt}$1${lt}/B${gt}$2#g;
1366 #-------------------------------------------------------------------------------
1368 sub html_bullet_tt
1370     s/$bullet_tt(.*)/    ${lt}li${gt}$1$2${lt}\/li${gt}/;
1373 #-------------------------------------------------------------------------------
1375 sub html_emit_line
1377     if( /$passthru_tt/ )
1378     {
1379         s/$passthru_tt//o;  # remove typotag and pass line out as is.
1380         reclaim_escapes();
1381         print CONVERT "$_\n"
1382     }
1383     else
1384     {
1385         print CONVERT &html_finishing( $_ ), "\n";
1386     }
1389 #-------------------------------------------------------------------------------
1391 sub html_enter_list  { print CONVERT "<UL>\n"  }    # state change activities
1392 sub html_leave_list  { print CONVERT "</UL>\n" }
1394 sub html_enter_pre   { print CONVERT "<PRE>\n"  }
1395 sub html_leave_pre   { print CONVERT "</PRE>\n" }
1397 sub html_enter_quote { print CONVERT "<BLOCKQUOTE><PRE>\n"   }
1398 sub html_leave_quote { print CONVERT "</PRE></BLOCKQUOTE>\n" }
1400 #-------------------------------------------------------------------------------
1402 sub html_final
1404     &to_state( $FMT );
1405     print CONVERT "</BODY>\n</HTML>\n";
1407     #----------------------------------------------------
1408     # Report on all internal name references not used up.
1409     #----------------------------------------------------
1410     if( scalar( @nm_ref ) > 0 )
1411     {
1412         print STDERR "\nMissing reference (target-tt) to the following:\n\n";
1413         for( $i=0; $i < scalar( @nm_ref ); $i++ )
1414         {
1415             print STDERR "  $nm_ref[ $i ]\n";
1416         }
1417     }
1420 #-------------------------------------------------------------------------------
1422 sub html_finishing {
1423     local($_) = @_;
1424     my $unt;
1425     s/\&/\&\#38\;/go; s/\</\&\#60\;/go; s/\>/\&\#62\;/go;
1426     s/$lt/</go; s/$gt/>/go; s/$amp/\&/go;   # convert markers to real symbols
1428     #-----------------------------------------------
1429     # This fixes the case where an untouchable 
1430     # string includes these special html characters.
1431     #-----------------------------------------------
1432     foreach $element ( @untouchable )
1433     {
1434         $element =~ s/\&/\&\#38\;/go;
1435         $element =~ s/\</\&\#60\;/go;
1436         $element =~ s/\>/\&\#62\;/go;
1437     }
1438     recover_extractions();
1439     $_;
1442 #-------------------------------------------------------------------------------
1444 sub html_hot_tt
1446     #--------------------------------------------------
1447     # After finding a hot-tt, substitute all underlines
1448     # with spaces and check to see if the hot-tt had
1449     # a corresponding hypertext reference. Flag it in
1450     # bright, bold red when no hypertext record found.
1451     #--------------------------------------------------
1452     s#$hot_tt#
1453         $h = $href{$1}; ($text = $1) =~ s,_, ,go;
1454         $h ? qq'${lt}A HREF="$h"${gt}$text${lt}/A${gt}' 
1455            : "${lt}B${gt}${lt}font color=red${gt}--> $text <-- NO HREF!!${lt}/font${gt}${lt}/B${gt}"; #eg;
1458 #-------------------------------------------------------------------------------
1460 sub html_indent { s/$indent_tt/$1/ } # get rid of indent-tt characters
1462 #-------------------------------------------------------------------------------
1464 sub html_init
1466     local $title;
1467     my    $target;
1468     
1469     #---------------------------------------
1470     # Variables needed for HTML conversions.
1471     #---------------------------------------
1472     $lt  = "\376"; # "<" marker
1473     $gt  = "\377"; # ">" marker
1474     $amp = "\373"; # "&" marker
1476     %state_change = (
1477         
1478         enter_list  => "html_enter_list",
1479         leave_list  => "html_leave_list",
1480         
1481         enter_pre   => "html_enter_pre",
1482         leave_pre   => "html_leave_pre",
1484         enter_quote => "html_enter_quote",
1485         leave_quote => "html_leave_quote",
1486     );
1487     
1488     $veryFirstTime = 1;   # used to force table of content header out
1490     print CONVERT "<HTML>\n<HEAD>\n";
1492     #------------------------------------------
1493     # Make a first pass over the data, looking 
1494     # for hypertext linking information.
1495     #------------------------------------------
1496     for ($i = 0; $i <= $#data; $i++) 
1497     {
1498         $_ = $data[$i];                 # $_ is default for searches
1500         #---------------------------------------------------------
1501         # This will pick out targets found in the setext not
1502         # hidden by a suppress-tt, that is, the href-tt below.
1503         # With this check, it is unnecessary to have to include
1504         # the href-tt which uses identical text for internal
1505         # document references. External references need href-tt.
1506         # Have to make sure the match does not pick up elements
1507         # inside a notouch-tt ( eg. `_do_not_want_this_as_target`)
1508         #---------------------------------------------------------
1509         if( /$target_tt/ && substr($`,length($`)-1,1) ne "`" && 
1510             (not /$suppress_tt/) )
1511         {
1512             $href{ $4 } = "$intHrefMrk$4";
1513             push @nm_ref, $4;
1514         }
1515         
1516         #-------------------------------------------------
1517         # Locate HREF's and save. When no target is given,
1518         # assume the target is internal, with same name.
1519         #-------------------------------------------------
1520         if( /$href_tt/  )
1521         {
1522             $hrefID = $1;
1523             $target = ($2) ? $2 : "$intHrefMrk$hrefID"; # assume internal href.
1524             $href{$hrefID} = $2; 
1525                 
1526             #------------------------------
1527             # Remember internal HREF's not 
1528             # already seen for target-tt.
1529             #------------------------------
1530             if( $target =~ /$internal_href/ ) {
1531                 if( not is_member( substr( $target, 1), \@nm_ref ) ) {
1532                     push @nm_ref, $1;
1533                 }
1534             }
1535             next; 
1536         } 
1538         #---------------------------------------------------------
1539         # The first title-tt or subhead-tt gets <TITLE>...</TITLE>
1540         #---------------------------------------------------------
1541         /$title_tt/    && do { html_init_title("H1", $i); next; };
1542         /$subtitle_tt/ && do { html_init_title("H2", $i); next; };
1543     }
1545     print CONVERT "</HEAD>\n";
1546     print CONVERT "<BODY>\n";
1547     
1548     #----------------------------------------------------
1549     # NOTE: changing original title-tt search pattern
1550     #       to match what was done in html_init_title.
1551     #----------------------------------------------------
1552     $title_tt = "^\\.\\.\\s+(<H.>)(.*)(<\\/H.>)";
1555 #-------------------------------------------------------------------------------
1557 sub html_init_title
1559     local($head, $i) = @_;
1560     my $hyper_ref;
1561     
1562     $data[$i--] = "..";      # suppress title indicator ( --- or === )
1563     $data[$i]   =~ s/^\s*//; # get rid of any leading space in actual title
1564     $this_title = $data[$i];
1565     
1566     # Have to fix title if it also happens to be a target-tt.
1567     $this_title =~ /$target_tt/ && do { ($tmp = $4) =~ s,_, ,go; $this_title = $tmp };
1568     
1569     #---------------------------------------------------
1570     # Are all titles automatically considered target-tt?
1571     #---------------------------------------------------
1572     if( $make_title_href )
1573     {
1574         $hyper_ref = $this_title;
1575         $hyper_ref =~ s/ /_/go;
1576         $externalReference  =
1577            ($separate_html_files) ? substr("$MenuNames{ $hyper_ref }.html", 1) : "";
1579         $href{ $hyper_ref } ="$externalReference$intHrefMrk$hyper_ref";
1581         #------------------------------
1582         # Remember internal HREF's not 
1583         # already seen for target-tt.
1584         #------------------------------
1585         if( not is_member( $hyper_ref, \@nm_ref ) ) {
1586             push @nm_ref, $hyper_ref;
1587         }
1588     }
1589     
1590     #-----------------------------------------------------------------
1591     # Put out the HTML title and then suppress it for later processing
1592     #-----------------------------------------------------------------
1593     print CONVERT "<TITLE>$this_title</TITLE>\n" unless $title++;
1594     $data[$i] = ".. <$head> " . $data[$i] . " </$head>";
1597 #-------------------------------------------------------------------------------
1599 sub html_italic_tt
1601     #---------------------------------------
1602     # Turn all "~text~" into "<I>text</I>"
1603     #---------------------------------------
1604     s#$italic_tt#${lt}I${gt}$1${lt}/I${gt}#g;
1607 #-------------------------------------------------------------------------------
1609 sub html_line_break
1611     my $fold = shift;
1612     print CONVERT "<P>\n" unless $fold++;
1613     return $fold;
1616 #-------------------------------------------------------------------------------
1618 sub html_line_tt
1620     s/$line_tt/${lt}P${gt}${lt}HR${gt}/;
1621     print CONVERT html_finishing( $_ ), "\n";
1624 #-------------------------------------------------------------------------------
1626 sub html_quote_tt
1628     s/$quote_tt\s*//;
1631 #-------------------------------------------------------------------------------
1633 sub html_section_tt
1635     my $hdr_level = shift;
1636     
1637     print CONVERT "<H$_</H$hdr_level>\n";
1640 #-------------------------------------------------------------------------------
1642 sub html_target_tt
1644     check_target_reference( $_ );
1645     /$target_tt/ && do { ($a = $4) =~ s,_, ,go; s/$target_tt/ $a/; };
1648 #-------------------------------------------------------------------------------
1650 #-----------------------------------------------------------------------------
1651 # sub html_title
1652 # {
1653 #     to_state( $FMT ); 
1654 #     check_target_reference( $_ ); 
1655 #     /$target_tt/ && do { ($a = $4) =~ s,_, ,go; s/$target_tt/$a/; };
1656 #     /$title_tt/i && do { print CONVERT $1, &html_finishing($2), $3, "\n"; };
1657 # }
1658 #-----------------------------------------------------------------------------
1659 sub html_title
1661     my $titleHolder = $_;
1662     
1663     to_state( $FMT ); 
1664     /$target_tt/ && do { ($a = $4) =~ s,_, ,go; s/$target_tt/$a/; };
1665     
1666     if( /$title_tt/i  ) # this is the new title-tt from html_init
1667     {
1668         $frontMrk = $1; $thisTitle = $2; $backMrk = $3;
1669         
1670         if( not $separate_html_files or $veryFirstTime )
1671         {
1672             check_target_reference( $titleHolder ); 
1673             print CONVERT $frontMrk, &html_finishing($thisTitle), $backMrk, "\n";
1674             $veryFirstTime = 0;
1675         }
1676         elsif( $frontMrk eq "<H1>" )
1677         {
1678             $savedTitle = $thisTitle;
1679             $savedTitleHolder = $titleHolder;
1680         }
1681         else
1682         {
1683             #--------------------------
1684             # Create another HTML file?
1685             #--------------------------
1686             $hyper_ref = $thisTitle;
1687             $hyper_ref =~ s/$trim_spaces/$2/o;
1688             $hyper_ref =~ s/ /_/go;
1689             $association = $MenuNames{ $hyper_ref };
1690             
1691             if( $association ne ""  )
1692             {
1693                 $assocLevel  = substr( $association, 0, 1 );
1694                 $association = substr( $association, 1 );
1695             
1696                 if( $converted_file ne "$association.html" )
1697                 {
1698                     #-----------------------------
1699                     # Finish off the current file.
1700                     #-----------------------------
1701                     print CONVERT "</BODY>\n</HTML>\n";
1702                     close CONVERT;
1704                     #-----------------------------------------------------
1705                     # This realigns title after nested sublevels complete.
1706                     #-----------------------------------------------------
1707                     if ( $assocLevel == 0 ) {
1708                         $savedTitle = $thisTitle;
1709                     }
1711                     $converted_file = "$association.html";
1712                     open  CONVERT, ">$converted_file" or die "Can't create $converted_file, $OS_ERROR";
1713                     print CONVERT "<HTML>\n<HEAD>\n";
1714                     print CONVERT "</HEAD>\n";
1715                     print CONVERT "<TITLE>$savedTitle</TITLE>\n";
1716                     print CONVERT "<BODY>\n";
1717                     
1718                     #--------------------------------------------
1719                     # This puts target reference in correct file.
1720                     #--------------------------------------------
1721                     if( $savedTitleHolder )
1722                     {
1723                         check_target_reference( $savedTitleHolder );
1724                         if( $savedTitleHolder =~ /$title_tt/i )
1725                         {
1726                             print CONVERT $1, &html_finishing($2), $3, "\n";
1727                         } 
1728                         $savedTitleHolder = "";
1729                     }
1730                 }
1731             }
1733             check_target_reference( $titleHolder ); 
1734             print CONVERT $frontMrk, &html_finishing($thisTitle), $backMrk, "\n";
1735         }
1736     }
1739 #-------------------------------------------------------------------------------
1741 sub html_underline_tt
1743     #--------------------------------------------
1744     # Turn all "_text_" into "<I><U>text</U></I>"
1745     # Remembering to substitute intervening 
1746     # underlines with spaces.
1747     #--------------------------------------------
1748     s#$underline_tt#
1749        ($text = $1) =~ s,_, ,go; 
1750        "${lt}I${gt}${lt}U${gt}$text${lt}/U${gt}${lt}/I${gt}"; #eg;
1753 #-------------------------------------------------------------------------------
1754 #                setext to NEdit HELP conversion call-back routines.
1755 #                         ( in alphabetical order )
1756 #-------------------------------------------------------------------------------
1758 sub help_bold_tt
1760     #----------------------------------------------------
1761     # Turn all "**text**" into "<stlMrk_B>text<stlMrk_B>"
1762     #----------------------------------------------------
1763     s#$bold_tt#${stlMrk}$TKN_BOLD$1${stlMrk}$TKN_BOLD$2#g;
1766 #-------------------------------------------------------------------------------
1768 sub help_bullet_tt  { s/$bullet_tt/    * $1/ }
1770 #-------------------------------------------------------------------------------
1772 sub help_emit_line  
1774     #------------------------------------------------------
1775     # The following is here to help us generate conditional
1776     # compilation elements for the 'C' compiler.
1777     #------------------------------------------------------
1778     if( /$passthru_tt/ )
1779     {
1780         s/$passthru_tt//o;  # remove typotag and pass line out as is.
1781         reclaim_escapes();
1782         print HELP "$_\n"
1783     }
1784     else
1785     {
1786         #-------------------------------------------------
1787         # This seems to be the only good place to take
1788         # care of style changes that have occurred between
1789         # usage of proportional and fixed font styles.
1790         #-------------------------------------------------
1791         if( $styleChanged )
1792         {
1793             $_ = $styleMark . get_style_name( $crntStyle ) . $_;
1794             $styleChanged = "";
1795         }
1797         my $finishedLine = help_finishing( $_ );
1799         print HELP "\"", $finishedLine, "\",\n";
1801         #----------------------------------------------------------------
1802         # To minimize newline output for the empty line elements,
1803         # the algorithm remembers if its last line had a newline emitted.
1804         #----------------------------------------------------------------
1805         $newLinePresentInLastLine = $finishedLine =~ /\\n$/;
1806     }
1809 #-------------------------------------------------------------------------------
1811 sub help_final  {}
1813 #-------------------------------------------------------------------------------
1815 sub help_finishing  
1817     local($_) = @_;
1819     #----------------------------
1820     # When finishing a heading...
1821     #----------------------------
1822     if( $headingLevel )
1823     {
1824         #--------------------------------------------------
1825         # ... destroy any styles inadvertantly placed there
1826         #--------------------------------------------------
1827         if( /$stlMrk/o )
1828         {
1829             my @line = split $stlMrk;
1830             $_ = join '', @line;
1831         }
1833         #------------------------------------
1834         # ... because only one style allowed.
1835         #------------------------------------
1836         $stlFront     = $styleMark . get_style_name( "" );
1837         $headingLevel = 0;
1838         $stlEnd       = $styleMark . get_style_name( $initialStyle );
1839         $stlFront     = "" if /^$styleToken/ ; # remove redundancy when present
1840         $_            = $stlFront . $_ .$stlEnd;
1841     }
1842     
1843     #---------------------------------------------
1844     # Any style markers found in the current line?
1845     #---------------------------------------------
1846     elsif( /$stlMrk/ )
1847     {
1848         #----------------------------------------
1849         # Break line up into style word elements.
1850         #----------------------------------------
1851         my $line = "";
1852         my @line = split $stlMrk;
1854         foreach $element ( @line )
1855         {
1856             #--------------------------------------------------
1857             # Extract word emphasis token and associated words.
1858             # Embed style marker into text line.
1859             #--------------------------------------------------
1860             $element =~ /^($aStyleToken)?(.*)$/o && do { 
1862                 $token = ($1) ? $1 : $TKN_TEXT;  # $TKN_xxx
1863                 $words = $2;
1864                 my $nextStyle = get_style( $crntStyle, $token );
1866                 if( $crntStyle eq $nextStyle )
1867                 {
1868                     $line .= $words;
1869                 }
1870                 else
1871                 {
1872                     $stlNm = get_style_name( $nextStyle );
1873                     $line .= "$styleMark$stlNm$words";
1874                     $crntStyle = $nextStyle;
1875                 }
1876             };
1877         }
1878         
1879         $_ = $line;
1880     }
1881     
1882     recover_extractions();
1883     fix_target_tt();
1884     
1885     #-------------------------------------------
1886     # Apply any initial style change introduced.
1887     #-------------------------------------------
1888     $_ = $newLeadStyle . $_;
1889     $newLeadStyle = "";
1891     #----------------------------------------------------------------
1892     # Add newline element to all lines which are not being currently
1893     # formatted into a flowing paragraph. It is done here because the
1894     # character also has to get included in the character counts.
1895     #----------------------------------------------------------------
1896     $_ .= get_newline( 1 ) if $crnt_state ne $FMT;
1897     
1898     #----------------------------------------------------------------------
1899     # Since 2 characters (\ and n) are occupying the space of one newline,
1900     # we need to subract out the number of new lines from the total offset.
1901     #----------------------------------------------------------------------
1902     my $styleCount     = count( $styleToken, $_ );
1903     my $newLineCount   = count( "\\\\n", $_ );
1904     my $quoteCount     = count( '"', $_ );
1905     my $backslashCount = count( "\\\\", $_ ) - $styleCount - 
1906                          $newLineCount - $quoteCount;
1907                          
1908     my $adjustment     = ($styleCount * $styleTokenSize) + 
1909                          ($backslashCount / 2) + $newLineCount + $quoteCount;
1910                          
1911     #-----------------------------------------------------------
1912     # Now keep a running total of how many characters to emit.
1913     # (Keep 2 forms, total number for compiler string length
1914     # considerations, and another for target-tt section offsets.
1915     #-----------------------------------------------------------
1916     $sectionCharacterCnt += length( $_ );
1917     $targetOffset        += length( $_ ) - $adjustment;
1918     
1919     $_;
1922 #-------------------------------------------------------------------------------
1924 sub help_fixed_styles
1926     #----------------------------------------------------------------
1927     # All proportional styles in the style state transition table
1928     # begin with the "_" character. If we are already in the
1929     # proportional styles arena, a link, or header, no change occurs.
1930     #----------------------------------------------------------------
1931     if( $crntStyle =~ /^_/ )
1932     {
1933         $crntStyle =~ s/^_//o;
1934         $styleChanged = $crntStyle unless $styleChanged;
1935     }
1938 #-------------------------------------------------------------------------------
1940 sub help_hot_tt
1942     my ( $text, $stlNm, $h );
1943     
1944     #--------------------------------------------------
1945     # After finding a hot-tt, substitute all underlines
1946     # with spaces and check to see if the hot-tt had
1947     # a corresponding hypertext reference. Make it 
1948     # unadorned text when no reference found.
1949     #--------------------------------------------------
1950     s#$hot_tt#
1951         ($text = $1) =~ s,_, ,go; 
1952         $h     = is_known_link( $text );
1953         $stlNm = get_style_name( $crntStyle );
1955         $h ? "$stlMrk$TKN_LINK$text$stlMrk$TKN_LINK"
1956            : $text; 
1957     #eg;
1960 #-------------------------------------------------------------------------------
1962 sub help_indent  
1964     if( /$indent_tt/ )
1965     {
1966         s/$indent_tt/$1/;            # get rid of indent-tt characters
1967         /\S$/ && do { $_ .= ' ' };   # make sure space available for remaining
1968     }                                #  text in this kind of paragraph
1971 #-------------------------------------------------------------------------------
1973 sub help_init
1975     %state_change = (
1976         
1977         enter_pre   => "help_fixed_styles",
1978         leave_pre   => "help_proportional_styles",
1980         enter_quote => "help_fixed_styles",
1981         leave_quote => "help_proportional_styles",
1982     );
1984     #--------------------------------------------
1985     # Global elements needed for making menu code
1986     #--------------------------------------------
1987     %href = ();
1989     $copy_right_holder = "Mark Edel";
1990     $hlptxt            = "help_data$helpSuffix.h";  # name of file holding help data structures
1991     $hlphdr            = "help_topic$helpSuffix.h"; # name of file holding help definitions
1992     $stlMrk            = "\01";          # this is the character code
1993     $styleMark         = '\01';          # this is the text string
1994     $styleToken        = "\\$styleMark"; # this for splitting strings on styleMark
1995     $styleTokenSize    = length( $styleToken ); # accounts for '\01A'
1996     $illegal_help      = "HELP_none";
1998     $menu_record       = "(.),(.*),(.*),(\\d)";
1999     $tgtIndx           = 0;  # target-tt index for hypertext reference array (@href)
2001     #-------------------------------------------------------------------
2002     # The following data is used to embed style data into the help text.
2003     #-------------------------------------------------------------------
2005     #                         TOKENS =>        text        bold        italic      underline
2006     %styles_stt = (
2008     # fixed font styles
2009     
2010       plain     => { style => "A", states => [ "plain",     "bold",      "italic",    "u_plain"    ] },
2011       bold      => { style => "B", states => [ "bold",      "plain",     "b_ital",    "u_bold"     ] },
2012       italic    => { style => "C", states => [ "italic",    "b_ital",    "plain",     "u_italic"   ] },
2013       b_ital    => { style => "D", states => [ "b_ital",    "italic",    "bold",      "u_b_ital"   ] },
2015       u_plain   => { style => "E", states => [ "u_plain",   "u_bold",    "u_italic",  "plain"      ] },
2016       u_bold    => { style => "F", states => [ "u_bold",    "u_plain",   "u_b_ital",  "bold"       ] },
2017       u_italic  => { style => "G", states => [ "u_italic",  "u_b_ital",  "u_plain",   "italic"     ] },
2018       u_b_ital  => { style => "H", states => [ "u_b_ital",  "u_italic",  "u_bold",    "bold_ital"  ] },
2020     #  proportional font styles
2021     
2022       _plain    => { style => "I", states => [ "_plain",    "_bold",     "_italic",   "_u_plain"   ] },
2023       _bold     => { style => "J", states => [ "_bold",     "_plain",    "_b_ital",   "_u_bold"    ] },
2024       _italic   => { style => "K", states => [ "_italic",   "_b_ital",   "_plain",    "_u_italic"  ] },
2025       _b_ital   => { style => "L", states => [ "_b_ital",   "_italic",   "_bold",     "_u_b_ital"  ] },
2027       _u_plain  => { style => "M", states => [ "_u_plain",  "_u_bold",   "_u_italic", "_plain"     ] },
2028       _u_bold   => { style => "N", states => [ "_u_bold",   "_u_plain",  "_u_b_ital", "_bold"      ] },
2029       _u_italic => { style => "O", states => [ "_u_italic", "_u_b_ital", "_u_plain",  "_italic"    ] },
2030       _u_b_ital => { style => "P", states => [ "_u_b_ital", "_u_italic", "_u_bold",   "_bold_ital" ] },
2032     #  hyperLink     style => "Q",
2033     
2034     #  header1       style => "R", --
2035     #  header2       style => "S",   |_ MAX_HEADER
2036     #  header3       style => "T", --
2037     );
2039     #-----------------------------------------------------------
2040     # The link index is the position in a font style table
2041     # where the linking font will reside. It appears immediately
2042     # after the styles from the table above.
2043     #-----------------------------------------------------------
2044     $linkIndex   = scalar( keys %styles_stt );
2045     $maxTokens   = scalar( @{ $styles_stt{plain}{states} } );
2047     $STYLE_PLAIN = $styles_stt{plain}{style};
2048     $STYLE_LINK  = "Q"; # link style marker, a continuation from style table
2049     $STYLE_HDR   = "R"; # beginning of header style markers
2050     $MAX_HEADER  = 3;   # the maximum number of header styles in use
2052     $TKN_TEXT    = 0;   # used in style state transition, order important
2053     $TKN_BOLD    = 1;   # used in style state transition, order important
2054     $TKN_ITALIC  = 2;   # used in style state transition, order important
2055     $TKN_ULINE   = 3;   # used in style state transition, order important
2056     $TKN_LINK    = 4;
2057     
2058     $aStyleToken = "[$TKN_TEXT$TKN_BOLD$TKN_ITALIC$TKN_ULINE$TKN_LINK]";
2060     $initialStyle = "_plain";  # the initial style for help text.
2061     $crntStyle    = $initialStyle;
2062     $headingLevel = 0;
2063     
2064     print_menu( $crntMenu, "" ) if $print_menu;  # sort of debug info
2066     #----------------------------------
2067     # Create help header (help_topic.h)
2068     #----------------------------------
2069     open HLPHDR, ">$hlphdr"  or die "Can't create $hlphdr,  $OS_ERROR";
2070     emit_help_header( HLPHDR, $crntMenu );
2071     close HLPHDR;
2072     
2073     #-------------------------------------------
2074     # Create help text data header (help_data.h)
2075     #-------------------------------------------
2076     open HELP,   ">$hlptxt"  or die "Can't create $hlptxt,  $OS_ERROR";
2077     emit_helpTitles( HELP, $crntMenu );
2079     collect_internal_hypertext_references( \@data );
2080     $whence = 0;
2081     emit_helpText( HELP, $crntMenu, \@data );
2084 #-------------------------------------------------------------------------------
2086 sub help_italic_tt
2088     s/$italic_tt/${stlMrk}$TKN_ITALIC$1${stlMrk}$TKN_ITALIC/g
2091 #-------------------------------------------------------------------------------
2093 sub help_line_break    
2095     my $fold = shift;
2096     $_ .= get_newline( 2 );
2097     help_emit_line() unless $fold++;
2098     return $fold;
2101 #-------------------------------------------------------------------------------
2103 sub help_line_tt       {}
2104 sub help_quote_tt      {}
2106 #-------------------------------------------------------------------------------
2108 sub help_proportional_styles
2110     #----------------------------------------------------------------
2111     # All proportional styles in the style state transition table
2112     # begin with the "_" character. If we are already in the
2113     # proportional styles arena, a link, or header, no change occurs.
2114     #----------------------------------------------------------------
2115     unless( $crntStyle =~ /^_/   or 
2116             $crntStyle eq "link" or 
2117             $crntStyle eq "header" ) {
2119         $crntStyle = "_$crntStyle";
2120         $newLeadStyle = $styleMark . get_style_name( $crntStyle );
2121     }
2124 #-------------------------------------------------------------------------------
2126 sub help_section_tt    
2128     $headingLevel = shift;
2129     #----------------------------------------------------------
2130     # Heading levels for sectioning are being required to start
2131     # at level 3 (considered the first level). This keeps the
2132     # X-resources down inside NEdit. So here is the mapping.
2133     #  1> level-1
2134     #  2> level-1
2135     #  3> level-1
2136     #  4> level-2
2137     #  5> level-3
2138     #----------------------------------------------------------
2139     $headingLevel = ($headingLevel > 2 ) ? $headingLevel - 2 : 1;
2140     $headingLevel = $MAX_HEADER if $headingLevel > $MAX_HEADER; #
2141     s/$section_tt//;
2142     &help_emit_line;
2143     $crntStyle = $initialStyle;
2147 #-------------------------------------------------------------------------------
2149 sub help_target_tt { } # cannot process target-tt at this time because
2150                        # calculation of the hypertext offset requires
2151                        # a fully expanded text line (see help_finishing).
2153 sub fix_target_tt
2155     if( /$target_tt/ and exists $href{ $4 } )
2156     {
2157         my ( $text, $tgtOffset, $originalLine );
2158         
2159         #---------------------------------------------------
2160         # Have to compute target's offset into help section.
2161         # Need actual text sans styling information. Assuming
2162         # all other text replacement has already occurred.
2163         #---------------------------------------------------
2164         $originalLine = $_;
2165         
2166         s/$styleToken.//g; # remove all styling markers
2167         
2168         #--------------------------------------------------------
2169         # Inside this special substitution, a computation of the
2170         # target's offset from the beginning of the section is
2171         # being computed and applied to the hyper-reference array
2172         # element which will be emitted after all text sections
2173         # have been processed.
2174         #--------------------------------------------------------
2175         s#$target_tt#
2176             ($text = $4) =~ s,_, ,go;
2177             $tgtOffset  = index( $_, $text ) + $targetOffset -1;
2178             $tgtOffset  = sprintf( "%6d", $tgtOffset );
2179             $href[ $tgtIndx++ ] =~ s /^0/$tgtOffset/o;
2180             " $text"; 
2181         #eg;
2182         
2183         #-------------------------------------------------------
2184         # Now fix hyper-references in actual line to be emitted.
2185         #-------------------------------------------------------
2186         $_ = $originalLine;
2187         
2188         s#$target_tt#
2189             ($text = $4) =~ s,_, ,go;
2190             " $text"; 
2191         #eg;
2192     }
2195 #-------------------------------------------------------------------------------
2197 sub help_title         {&help_emit_line}
2199 #-------------------------------------------------------------------------------
2201 sub help_underline_tt
2203     #--------------------------------------------------
2204     # Turn all "_text_" into "<stlMrk_U>text<stlMrk_U>"
2205     # Remembering to substitute intervening 
2206     # underlines with spaces.
2207     #--------------------------------------------------
2208     s#$underline_tt#
2209        ($text = $1) =~ s,_, ,go; 
2210        "${stlMrk}$TKN_ULINE$text${stlMrk}$TKN_ULINE";
2211     #eg;
2214 #-------------------------------------------------------------------------------
2216 sub get_newline
2218     $howMany = shift;
2219     
2220     $howMany-- if $newLinePresentInLastLine && $howMany > 1;
2221     return '\n' x $howMany;
2224 #-------------------------------------------------------------------------------
2226 sub is_known_link
2228     my $linkName = shift;
2229     
2230     for( $index = 0; $index < scalar( @hot_tt_links ); $index++ )
2231     {
2232         $element = $hot_tt_links[ $index ];
2233         return 1 if( $hot_tt_links[ $index ] eq $linkName );
2234     }
2235     
2236     return 0;
2239 #-------------------------------------------------------------------------------
2241 sub get_style
2243     my $crntStyle = shift;    # plain, bold, italic, etc.
2244     my $token     = shift;    # $TKN_xxx
2245     my $style     = "header"; # assume working on header
2246     
2247     if( $headingLevel == 0 )
2248     {
2249         if( $token == $TKN_LINK )
2250         {
2251             if( $crntStyle eq "link" )
2252             {
2253                 $style = $prevStyle;
2254             }
2255             else
2256             {
2257                 $prevStyle = $crntStyle;
2258                 $style = "link";
2259             }
2260         }
2261         else
2262         {
2263             @transitions = @{ $styles_stt{$crntStyle}{states} };
2264             $style = $transitions[ $token ];
2265         }
2266     }
2267     
2268     return $style;
2271 #-------------------------------------------------------------------------------
2273 sub get_style_name
2275     my $crntStyle = shift;    # plain, bold, italic, etc.
2276     my $styleName;
2277     
2278     if( $headingLevel )
2279     {
2280         $styleName = chr(ord( $STYLE_HDR )+$headingLevel-1);
2281     }
2282     elsif( $crntStyle eq "link" )
2283     {
2284         $styleName = $STYLE_LINK;
2285     }
2286     else
2287     {
2288         $styleName = $styles_stt{$crntStyle}{style};
2289     }
2290     
2291     return  $styleName;
2294 #-------------------------------------------------------------------------------
2296 sub get_menu_item
2298     my $setext = shift;
2299     my $line   = shift;
2301     
2302     while( $$line < scalar( @$setext ) )
2303     {
2304         $_ = $$setext[ $$line++ ];
2305         return $_               if s/$menu_element//o;
2306         return "$_, $help_code" if s/$help_element//o;
2307     }
2308     
2309     return "";
2312 #-------------------------------------------------------------------------------
2314 sub print_menu
2316     my $crnt_menu = shift;
2317     my $indent    = shift;
2318     my ( $menuTitle, $mneumonic, $helpName, $hideit, $type );
2319     
2320     foreach $menuItem ( @$crnt_menu )
2321     {
2322         if ( $menuItem =~ /$menu_record/o ) 
2323            { $mneumonic=$1; $menuTitle=$2; $helpName=$3; $hideit=($4) ? $4 : "" }
2324         
2325         if( $hideit eq $help_code ) {
2326             $hideit = ""; 
2327             $type = "Help"
2328         } 
2329         else { 
2330             $hideit = ", ($hideit)" if $hideit;
2331             $type = "Menu" 
2332         }
2333         
2334         print "$type: $indent$mneumonic, $menuTitle [$helpName]$hideit\n";
2335         
2336         if( $menuItem =~ /$subMenuIndicator/o )
2337         {
2338             ($menu = $menuTitle) =~ s/ /_/og;
2339             print_menu( \@$menu, "$indent  " );
2340         }
2341     }
2344 #-------------------------------------------------------------------------------
2346 sub collect_internal_hypertext_references
2348     my $setext = shift;
2349     my $line   = 0;
2350     my ($source, $destination );
2351     
2352     while( $line < scalar( @$setext ) )
2353     {
2354         $_ = $$setext[ $line++ ];
2355         
2356         if( /$href_tt/o )
2357         {
2358             $source      = $1;
2359             $destination = $2;
2360             if( $destination =~ /$internal_href/ )
2361             {
2362                 $href{ $1 } = $source;
2363             }
2364         }
2365     }
2368 #-------------------------------------------------------------------------------
2370 sub emit_helpText
2372     my $stream    = shift;
2373     my $crnt_menu = shift;
2374     my $setext    = shift;
2375     my $line      = 0;
2376     my $index     = 1;
2377     
2378     $helpNameList = "";
2380     emit_help_menu_text( $setext, $stream, $crnt_menu, \$line );
2382     print $stream "static char **HelpText[] = {\n$helpNameList\n};\n\n";
2384     print $stream "HelpMenu H_M [] =\n{\n";
2385     emit_help_menu( $stream, $crnt_menu, 0, 1 );
2386     print $stream "\n};\n";
2387     
2388     #------------------------------------
2389     # Emit internal hypertext references.
2390     #------------------------------------
2391     print $stream "\nHref H_R [] =\n{\n";
2392     $sep = "";
2393     for( $index = 0; $index < scalar( @href ); $index++ )
2394     {
2395         $element = $href[ $index ];
2396         $nextone = ( $index == $#href ) ? "NULL,    " : "&H_R[%2d],";
2397         printf $stream "$sep    { $nextone $element }", $index+1;
2398         $sep = ",\n"
2399     }
2400     print $stream "\n};\n";
2401     
2402     #-----------------------------
2403     # Emit program version string.
2404     #-----------------------------
2405     $pgmVersion = $variables{ version };
2406     $pgmVersion .= '\n' . date() if $pgmVersion !~ /$neditDefaultMarker/;
2407     print $stream "\nstatic const char * NEditVersion = \"$pgmVersion\\n\";\n";
2410 #-------------------------------------------------------------------------------
2412 sub emit_help_menu_text
2414     my $setext    = shift;
2415     my $stream    = shift;
2416     my $crnt_menu = shift;
2417     my $line      = shift;
2418     
2419     my ( $menuTitle, $mneumonic, $helpName, $prevLine );
2420     
2421     #----------------------------------------
2422     # For every node of the menu tree...
2423     #----------------------------------------
2424     foreach $menuItem ( @$crnt_menu )
2425     {
2426         if ( $menuItem =~ /$menu_record/ ) 
2427            {  $mneumonic=$1; $helpName=$3; ($menuTitle=$2) =~ s/_//; }
2428         
2429         #---------------------------------
2430         # ... recursively expand sub-menus
2431         #---------------------------------
2432         if( $menuItem =~ /$subMenuIndicator/ )
2433         {
2434             ($menu = $menuTitle) =~ s/ /_/g;
2435             emit_help_menu_text( $setext, $stream, \@$menu, $line );
2436         }
2437         
2438         elsif( $mneumonic ne $separator ) # ... and not a menu separator
2439         {
2440             locate_menu_text( $setext, $menuTitle, $line )  
2441               or die "Unable to find \"$menuTitle\" text!";
2443             $remainder = "";
2444             my @section = ();
2445             my $lineNbr = 0;
2446             $s_e_p = ($helpNameList) ? ",\n" : "";
2447             $helpNameList .=  $s_e_p . "    htxt_$helpName";
2448             $sectionCharacterCnt = 0;
2449             $targetOffset        = 0;
2450             
2451             #------------------------
2452             # ... emit help menu text
2453             #------------------------
2454             while( 1 )
2455             {
2456                 ($_,$remainder) = get_menu_text( $setext, $remainder, $line );
2457                 
2458                 last if $_ eq "";
2459                 $lineNbr++;
2460                 next if /$empty_line/ and $lineNbr == 1;
2461                 chomp;
2462                 
2463                 #--------------------------------------------------
2464                 # Save all hypertext targets found in current topic
2465                 #--------------------------------------------------
2466                 if( /$target_tt/ and exists $href{ $4 } )
2467                 {
2468                     $target = $4;
2469                     $href   = $href{$target};
2470                     $href   =~ s/_/ /go;
2471                     $target =~ s/_/ /go;
2472                     $topic  = "HELP_\U$helpName,";
2473                     $nl1    = $name_length+6;  # for HELP_ and comma
2475                     push @href, 
2476                        sprintf("0, %-${nl1}.${nl1}s \"$href\", \"$target\"", $topic );
2478                     push @hot_tt_links, $href;  # collect for later verification.
2479                 }
2480                 
2481                 s/\\/\\\\/go;  # escape backslash any where in text
2482                 s/"/\\"/go;    # escape embedded double quotes
2483                 s/^\s*$//;     # redefine whitespace as empty line
2485                 push @section, $_ ;
2486             }
2487             print $stream "static char * htxt_$helpName [] = {\n";
2488             $styleChanged = $initialStyle; # This forces initial style out
2489             $crntStyle    = $initialStyle;
2490             parse_setext( \@section );
2491             print $stream "NULL\n};\n\n";
2492         }
2493     }
2496 #-------------------------------------------------------------------------------
2498 sub locate_menu_text
2500     my $setext    = shift;
2501     my $menuTitle = shift;
2502     my $line      = shift;
2504     $menuTitle =~ s/_//go;   # removing drop key character markers
2505     $menuTitle =~ s/ /./go;  # spaces could be underlines in titles
2506     $menuTitle =~ s/\(/./go; # parens are special in regex searches...
2507     $menuTitle =~ s/\)/./go; #  ... here they should be ignored
2509     #-----------------------------------------------------
2510     # When the whence value is set to zero, the search
2511     # for the text that belongs with the given menu title
2512     # is started at the beginning of the file. This allows
2513     # the menu text to be in an order other than that
2514     # specified by the menu itself. This gives freedom
2515     # to the writer; inefficiency to the text processing.
2516     #-----------------------------------------------------
2517     $$line = 0 if ( $whence != 1 );
2519     while( $$line < scalar( @$setext ) )
2520     {
2521         if( $$setext[ $$line++ ] =~ /$menuTitle/ )
2522         {
2523             if ( $$setext[ $$line ] =~ /$subtitle_tt/  or
2524                  $$setext[ $$line ] =~ /$title_tt/ )
2525             {
2526                 $$line++;
2527                 return 1; # the first line after the setext title marker
2528             }
2529         }
2530     }
2531     
2532     return 0;
2535 #-------------------------------------------------------------------------------
2537 sub get_menu_text
2539     my $setext    = shift;
2540     my $crnt_line = shift;
2541     my $line      = shift;
2542     
2543     #-------------------------------------
2544     # Skip any setext comment lines found.
2545     #-------------------------------------
2546     while( $$setext[ $$line ] =~ /$suppress_tt/ ) { $$line ++ };
2548     $crnt_line = $$setext[ $$line++ ] if $crnt_line eq "";
2549     
2550     if( $crnt_line =~ /$twobuck_tt/ )  # end of setext document?
2551     {
2552         return ("", "");
2553     }
2554     else
2555     {
2556         #--------------------------------------------
2557         # Have to read ahead by one line to catch the
2558         # title of the next section, or the end of
2559         # the setext document.(Eat horizontal rulers)
2560         #--------------------------------------------
2561         do { $_ = $$setext[ $$line++ ] } until not /^   --/;
2563         #--------------------------------
2564         # Look ahead again, so that an
2565         # empty last line is not emitted.
2566         #--------------------------------
2567         if( $crnt_line =~ /^\s*$/ and
2568             ($$setext[ $$line ] =~ /$subtitle_tt/o or 
2569              $$setext[ $$line ] =~ /$title_tt/o or 
2570              $$setext[ $$line ] =~ /$twobuck_tt/o))
2571         {
2572             return ("", "");
2573         }
2574         
2575         if( /$subtitle_tt/o or /$twobuck_tt/o )
2576         {
2577             $$line = $$line - 2;
2578             return ("", "");
2579         }
2580     }
2581     
2582     return ( $crnt_line, $_ );
2585 #-------------------------------------------------------------------------------
2587 sub emit_help_menu
2589     my $stream    = shift;
2590     my $crnt_menu = shift;
2591     my $level     = shift;
2592     my $index     = shift;
2594     my ( $menuTitle, $mneumonic, $helpName, $hideIt );
2595     
2596     if( $level == 0 )
2597     {
2598         $sep = "";
2599         $end_index = scalar( @$crnt_menu );
2600     }
2601     
2602     $level++;
2603     $nl1 = $name_length+6;  # for HELP_ and comma
2604     $nl2 = $name_length+3;  # for 2 double quotes and comma
2605     
2606     #----------------------------------------
2607     # For every node of the menu tree...
2608     #----------------------------------------
2609     foreach $menuItem ( @$crnt_menu )
2610     {
2611         if ( $menuItem =~ /$menu_record/ ) 
2612         {
2613             $mneumonic = $1; 
2614             $helpName  = $3; 
2615             $hideIt    = $4; 
2616             ($menuTitle=$2) =~ s/_//; 
2617         }
2618         
2619         #---------------------------------
2620         # ... recursively expand sub-menus
2621         #---------------------------------
2622         if( $menuItem =~ /$subMenuIndicator/ )
2623         {
2624             ($menu = $menuTitle) =~ s/ /_/g;
2625             printf $stream "$sep    { &H_M[%2d], $level, %-${nl1}.${nl1}s %-${nl2}.${nl2}s $hideIt, '$mneumonic', \"$menuTitle\" }", 
2626                $index, "$illegal_help,", "\"$helpName\",";
2627             $index = emit_help_menu( $stream, \@$menu, $level, $index+1 );
2628         }
2629         
2630         else
2631         {
2632             $topic    = ( $mneumonic eq $separator ) ? "$illegal_help," : "HELP_\U$helpName,";
2633             $helpName = "\"$helpName\",";
2634             $nptr     = ( $end_index == 1 && $level == 1 ) ? "NULL" : "&H_M[%2d]";
2635             
2636             #---------------------------
2637             # are we at end of the menu?
2638             #---------------------------
2639             if( $end_index == 1 && $level == 1 ) {
2640                 print $stream "$sep    { NULL,     ";
2641             }
2642             else {
2643                 printf $stream "$sep    { &H_M[%2d], ", $index;
2644             }
2645             printf $stream "$level, %-${nl1}.${nl1}s %-${nl2}.${nl2}s $hideIt, '$mneumonic', NULL }", $topic, $helpName;
2646             $sep = ",\n";
2647             $index++;
2648         }
2649         
2650         $end_index-- if $level == 1;
2651     }
2652     
2653     return $index;
2656 #-------------------------------------------------------------------------------
2658 sub emit_helpTitles
2660     my $stream    = shift;
2661     my $crnt_menu = shift;
2662     
2663     emit_copyright( $stream, "$hlptxt --  Nirvana Editor help module data" );
2664     print $stream "char *HelpTitles[] = {\n";
2665     emit_help_label( $stream, $crnt_menu );
2666     print $stream "    NULL\n};\n\n";
2669 #-------------------------------------------------------------------------------
2671 sub emit_help_label
2673     my $stream    = shift;
2674     my $crnt_menu = shift;
2675     my ( $menuTitle, $mneumonic, $helpName );
2676     
2677     #-----------------------------------------------------------------
2678     # Emit help title/labels for only the leaf nodes of the menu tree.
2679     #-----------------------------------------------------------------
2680     foreach $menuItem ( @$crnt_menu )
2681     {
2682         if ( $menuItem =~ /$menu_record/ ) 
2683         {
2684             $mneumonic  = $1;
2685             $helpName   = $3; 
2686             ($menuTitle = $2) =~ s/_//go;
2687         }
2688           
2689         if( $menuItem =~ /$subMenuIndicator/ )
2690         {
2691             ($menu = $menuTitle) =~ s/ /_/go;
2692             emit_help_label( $stream, \@$menu );
2693         }
2694         elsif( $mneumonic ne $separator ) # ... and not a menu separator
2695         {
2696             print $stream "    \"$menuTitle\",\n";
2697             push @hot_tt_links, $menuTitle;  # collect for later verification.
2698         }
2699     }
2702 #-------------------------------------------------------------------------------
2704 sub emit_help_header          # populates NEdit's help_topic.h
2706     my $stream    = shift;
2707     my $crnt_menu = shift;
2708     
2709     emit_copyright( $stream, "$hlphdr --  Nirvana Editor help display" );
2710     print $stream "#define MAX_HEADING   $MAX_HEADER\n";
2711     print $stream "#define STL_HD        $linkIndex+1\n";
2712     print $stream "#define STL_LINK      $linkIndex\n";
2713     print $stream "#define STL_NM_HEADER '$STYLE_HDR'\n";
2714     print $stream "#define STL_NM_LINK   '$STYLE_LINK'\n";
2715     print $stream "#define STYLE_MARKER  '$styleMark'\n";
2716     print $stream "#define STYLE_PLAIN   '$STYLE_PLAIN'\n";
2717     print $stream "#define TKN_LIST_SIZE $maxTokens\n";
2718     print $stream "\n";
2719     print $stream "enum HelpTopic {\n";
2720     emit_help_topic( $stream, $crnt_menu );
2721     print $stream "    HELP_LAST_ENTRY,\n";
2722     print $stream "    $illegal_help = 0x7fffffff  /* Illegal topic */ \n";
2723     print $stream "};\n";
2724     print $stream "\n";
2725     print $stream "#define NUM_TOPICS HELP_LAST_ENTRY\n";
2726     print $stream "\n";
2729 #-------------------------------------------------------------------------------
2731 sub emit_help_topic
2733     my $stream    = shift;
2734     my $crnt_menu = shift;
2735     my ( $menuTitle, $mneumonic, $helpName );
2736     
2737     #-----------------------------------------------------------------
2738     # Emit help topic name for only the leaf nodes of the menu tree.
2739     #-----------------------------------------------------------------
2740     foreach $menuItem ( @$crnt_menu )
2741     {
2742         if ( $menuItem =~ /$menu_record/ ) 
2743         {
2744             $mneumonic  = $1;
2745             $helpName   = $3; 
2746             ($menuTitle = $2) =~ s/_//go;
2747         }
2748           
2749         if( $menuItem =~ /$subMenuIndicator/ )
2750         {
2751             ($menu = $menuTitle) =~ s/ /_/go;
2752             emit_help_topic( $stream, \@$menu );
2753         }
2754         elsif( $mneumonic ne $separator ) # ... and not a menu separator
2755         {
2756             print $stream "    HELP_\U$helpName,\n";
2757         }
2758     }
2761 #-------------------------------------------------------------------------------
2763 sub emit_copyright
2765     my $stream   = shift;
2766     my $filename = shift;
2767     
2768     my $year     = date("y");
2769     my $padlen1  = 76 - length( $filename );
2770     my $padlen2  = 52 - length( $copy_right_holder );
2771     my $blanks   = "                                                                                  ";
2772     my $pad1      = substr( $blanks, 0, $padlen1 );
2773     my $pad2      = substr( $blanks, 0, $padlen2 );
2774     
2775     print $stream "/*******************************************************************************\n";
2776     print $stream "*                                                                              *\n";
2777     print $stream "* $filename$pad1 *\n";
2778     print $stream "*                                                                              *\n";
2779     print $stream "                 Generated on " . date() . " (Do NOT edit!)\n";
2780     print $stream "                 Source of content from file $setext_file\n";
2781     print $stream "*                                                                              *\n";
2782     print $stream "* Copyright (c) 1999-$year $copy_right_holder$pad2 *\n";
2783     print $stream "*                                                                              *\n";
2784     print $stream "* This is free software; you can redistribute it and/or modify it under the    *\n";
2785     print $stream "* terms of the GNU General Public License as published by the Free Software    *\n";
2786     print $stream "* Foundation; either version 2 of the License, or (at your option) any later   *\n";
2787     print $stream "* version.                                                                     *\n";
2788     print $stream "*                                                                              *\n";
2789     print $stream "* This software is distributed in the hope that it will be useful, but WITHOUT *\n";
2790     print $stream "* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or        *\n";
2791     print $stream "* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License        *\n";
2792     print $stream "* for more details.                                                            *\n";
2793     print $stream "*                                                                              *\n";
2794     print $stream "* You should have received a copy of the GNU General Public License along with *\n";
2795     print $stream "* software; if not, write to the Free Software Foundation, Inc., 59 Temple     *\n";
2796     print $stream "* Place, Suite 330, Boston, MA  02111-1307 USA                                 *\n";
2797     print $stream "*                                                                              *\n";
2798     print $stream "* Nirvana Text Editor                                                          *\n";
2799     print $stream "* September 10, 1991                                                           *\n";
2800     print $stream "*                                                                              *\n";
2801     print $stream "* Written by $copy_right_holder                                                         *\n";
2802     print $stream "*                                                                              *\n";
2803     print $stream "*******************************************************************************/\n";
2804     print $stream "\n";
2808 #-------------------------------------------------------------------------------
2811 __END__
2813 =head1 NAME
2815 Setext - convert Structured Enhanced TEXT into HTML or plain text.
2817 =head1 SYNOPSIS
2819  Usage: setext [ -dhHStTV ][-c conditional]   \
2820                [-v name=value][setext_file [converted_file]]
2821                
2822         setext {-mp} [-c conditional][-M menuSuffix] \
2823                [-v name=value] setext_file
2825   The first form of setext is used to convert Structure Enhanced TEXT
2826   documents into HTML or simple text documents. The second form is 
2827   specific to generating the Nirvana Editor (NEdit) help menu code 
2828   from a setext document with Menu and Help directives.
2830   -c conditional text definitions, separated by commas.
2831   -d do not automatically make titles hypertext references (HTML only)
2832   -h show this usage clause.
2833   -H convert setext_file to HyperText Markup Language (HTML).
2834   -m generate NEdit help menu code files.
2835   -M name NEdit help menu code files using this suffix.
2836   -p do option -m and print out NEdit help elements.
2837   -S convert setext_file into separate HTML files.
2838   -t convert setext_file to simple text (default).
2839   -T emit setext typotag definitions in use.
2840   -v defines variable name and assigns it the given value.
2841      (more than one occurrence of -v can be made) The variables
2842      are made available for use within the setext document parsing.
2843   -V display the version of this setext script.
2845 =head1 DESCRIPTION
2847 This Structured Enhanced TEXT converter produces either HTML or plain
2848 text files from a given setext source. The HTML files produced can
2849 include hypertext references to within itself, or to external 
2850 destinations. The setext converter also has the capability of providing
2851 different content in the resulting output files through a conditional 
2852 text mechanism, and variable data definitions. All this allows a 
2853 publisher to maintain a single, very readable, source while producing
2854 varying content for different output formats and audiences.
2856 When the converted_file argument is missing, STDOUT is used.
2857 When the setext_file argument is missing, STDIN is used. This gives
2858 setext the capability of being a filter to other programs.
2860 To get conditional text within a setext document to be displayed,
2861 supply a definition tag through the -c option. For example,
2863         setext -c NEDITDOC help.etx nedit.doc
2865 Would generate a plain text document, nedit.doc, from the source
2866 help.etx, including/excluding text marked with 'NEDITDOC'
2867 conditional text markers, also known as 'maybe' typotags.
2869 Use the -T option to see the set of typotags supported by this
2870 converter. Further explanations of typotags occurs there.
2872 =head2 NEdit Help Menu
2874 When generating the NEdit help menu code, two files will be produced,
2875 help_data.h and help_topic.h (when the -M option is not used).
2876 These two files contain all the programmatic
2877 data needed to implement hypertext menus within the NEdit program.
2878 The following is an example of a setext invocation which assumes that
2879 the variable 'version' is being used within the help.etx file.
2881         setext -m -v "version=6.0" help.etx
2883 If the -M option is used, its value is appended to the root portion
2884 of the two generated files. For example,
2886         setext -m -c VMS -M _VMS help.etx
2888 will generate the files help_topic_VMS.h and help_data_VMS.h. The 
2889 conditional portion of the help menu specifically designated for VMS 
2890 will be extracted from the help.etx source.
2892 Below is what is used to guide the generation of 'C'-Motif menus.
2893 Indentation is SIGNIFICANT in the "Menu" directive lines below. It
2894 is used to determine under which menu element another item will belong.
2895 The number of spaces indented is not significant, but items to be placed
2896 in the same menu panel MUST line up at the same indent level.
2897 ALL nodes of this menu "tree" should have help name qualifiers.
2898 These are used to produce the internal lists used by NEdit help code.
2900 By default, the first character of the menu element will be used as a 
2901 menu mneumonic key. To use another character in the menu element for 
2902 this purpose, surround the character with underscores (eg. I w_a_nt 'a').
2904 The menu title MUST match the one found in the actual help text (sans
2905 special mneumonic key character marking). The help text title may include
2906 underlines (for spaces) when it is a hyperlink target.
2908 The Help-name is used to generate various data structure names. For
2909 instance, the 'start' help name will be used to generate the HelpTopic
2910 enumeration value HELP_START and the character array htxt_start which
2911 holds the actual help text used in the menu dialogs. Consequently, these
2912 names need to be unique and contain only the characters that a 'C'
2913 compiler can digest.
2915 Menu separator lines use a dash (-) character for the Menu Title. They
2916 should also have a unique Help-name.
2918 A numerical value following the Help-name (separated from the name by
2919 a comma and/or spaces) is part of a menu element hiding scheme implemented
2920 in buildHelpMenu (found in 'menu.c'). When the number matches the hideIt
2921 value found in the procedure, that element will effectively become invisible.
2922 This mechanism was created for particular menu features that are not
2923 available to all incarnations of NEdit (in this case, the VMS version).
2925 A "Help" directive is used for all other text used as NEdit help, but
2926 does not show up in the Help menu. The following is a sample of
2927 Menu and Help directives.
2929 ..       Menu Title                         # Help-name
2930 .. ------------------------------------------------------------
2931 .. Menu: Getting Started                    # start
2932 .. Menu: Basic Operation                    # basicOp
2933 .. Menu:   Selecting Text                   # select
2934 .. Menu:   Finding and Replacing Text       # search
2935 .. Menu:   Cut and Paste                    # clipboard
2936 .. Menu:   Using the Mouse                  # mouse
2937 .. Menu:   Keyboard Shortcuts               # keyboard
2938 .. Menu:   S_h_ifting and Filling           # fill
2939 .. Menu:   F_i_le Format                    # format
2941 .. Menu: Features for Programming           # features
2942 .. Menu:   Programming with NEdit           # programmer
2943 .. Menu:   Tabs/Emulated Tabs               # tabs
2944 .. Menu:   Auto/Smart Indent                # indent
2945 .. Menu:   Syntax Highlighting              # syntax
2946 .. Menu:   Finding Declarations (ctags)     # tags
2948 .. Menu: Regular Expressions                # regex
2949 .. Menu:   Basic Syntax                     # basicSyntax
2950 .. Menu:   Metacharacters                   # escapeSequences
2951 .. Menu:   Parenthetical Constructs         # parenConstructs
2952 .. Menu:   Advanced Topics                  # advancedTopics
2953 .. Menu:   Examples                         # examples
2955 .. Menu: Macro/Shell Extensions             # extensions
2956 .. Menu:   Shell Commands and Filters       # shell, 1
2957 .. Menu:   Learn/Replay                     # learn
2958 .. Menu:   Macro Language                   # macro_lang
2959 .. Menu:   M_a_cro Subroutines              # macro_subrs
2960 .. Menu:   Action Routines                  # actions
2962 .. Menu: Customizing                        # customizing
2963 .. Menu:   Customizing NEdit                # customize
2964 .. Menu:   Preferences                      # preferences
2965 .. Menu:   X Resources                      # resources
2966 .. Menu:   Key Binding                      # binding
2967 .. Menu:   Highlighting Patterns            # patterns
2968 .. Menu:   Smart Indent Macros              # smart_indent
2970 .. Menu: NEdit Command Line                 # command_line
2971 .. Menu: Client/Server Mode                 # server
2972 .. Menu: Cr_a_sh Recovery                   # recovery
2973 .. Menu: ---------------------------------- # separator1
2974 .. Menu: Version                            # version
2975 .. Menu: Distribution Policy                # distribution
2976 .. Menu: Mailing _L_ists                    # mailing_list
2977 .. Menu: Problems/Defects                   # defects
2978 .. ------------------------------------------------------------
2979 .. Help: Tabs Dialog                        # tabs_dialog
2981 =cut