#!/usr/bin/perl
#
# Revision History:
# ----------------
# Revision 0: Implemented gremlins, hyphenation, sectioning,
#             initial stab at underscore-handling.
# Revision 1: Swapped \w for \S in underscore regexps and added 
#             checks to for punctuation and EOL-terminated underscores
# Revision 2: Initial attempt at underscores.
# Revision 3: Finished work on underscores.
#             Added URLs. Defined internal latex commands
# Revision 4: More work on URLs (brackets now added by latex commands)
#             Sketched out skeleton of remaining implementation
#             Adds latex header/footer and sets title
# Revision 5: Added itemization
# Revision 6: Smart quotes, hrules
#             Fixed (somewhat) the URL block situation (URL vs. inline URL
#                context now noted).
# Revision 7: URLs now separated from paragraphs and encapsulated in tabulars
# Revision 8: Cleaned up argument processing
#             Added -mdj option to grab `author'
#             Moved URL blocks back out of tables (now using \\ + \noindent 
#                to do grouping)
# Revision 9: Fixed (broken) argument processing from r8
#             Added -c flag for writing to stdout
#             Will also guess unspecified outfile name for .etx files
# Revision 10: Misc. cleanup, will do more guessing w/r/t filenames,
#              New symbol substitution for abbrevs, exponents
# Revision 11: Fixed end-of-line hyphens when word on next line
#                 terminates with punctuation
#              MDJ-mode tweaking for boilerplate and auto-activation
#                 based on document's title
#              Now handles backslashes in source text
# Revision 12: Added two special cases for (text_) and [text_] conditions
#              Further messes with URLs in boilerplate section
#
# Revision 13: Complete Reorganization. Now each pass dealt with within
#                 its own subroutine
# Revision 14:  Moved url display over to using url.sty, still not working...
#          14b: Moved back from url.sty to hyperref
#
# Revision 15: Completed switch to hyperref, modified url functions to allow
#                for easier line-wrapping
#
# Revision 16: Added switch to disable fancy footers, cleaned up defs for public use
# Revision 17: Fixed end-of-line hyphenation to look for \s(\w+-)+$ which 
#              now catches e.g., "multi-word-
#              hyphenation-chains"
#
# Revision 18: Now uses the relsize package for tag-related size changes.
#              Converts pgp signature to monospaced font
# Revision 19: Another hyphenation fix for words in the chain containing punctuation
#
# Revision 20: Added `next' calls to skip special formatting within \etxURL{} and \etxLink{} lines
# Revision 21: The manual-hyphenation code was grabbing ' -$' runs missing that they're supposed to be dashes
# Revision 22: Properly space "` and '" within-quotation quotes
# Revision 23: Redo manual hyphenation fix. Now requires that the first character in
#              a manually-hyphenated chain be a word char (so "--$" isn't considered
#              to be a hyphenated "word")
# Revision 24: `final' (?) change to hyphenation. Fixes spacing to turn "foo -$" into
#              "foo---bar$"
# Revision 25: Smart-quotes: now counts: {"  as an opening quote
# Revision 26: Use ~ for spacing after titles like: Mr. Dr. Ms. Mrs.
#              Use smallcaps in mdj for `US$'
#              Convert ... to ldots
# Revision 27: Undid first-char requirement from rev 23 b/c it was missing things like
#              `` (pre-$ '' and `` "under-$ ''. Besides, we have a special case now for
#              lines ending ``--$''
# Revision 28: Realized the much-tweaked hyphen rule wasn't correctly grabbing the
#              whitespace on the second line. Fixed now.
# Revision 29: Added Acronym-to-SmallCaps conversion
#              Changed \\[-1ex] to \\*[-1ex] for spacing after url lines
# Revision 30: SmallCaps bug fixes: avoids verbatim environments
#                                   catches things that start with only 2 caps (e.g., CD-ROM)
#              Substitutes textasciitilde for ~ in visible text (i.e., not hrefs)
# Revision 31: Changes to \parskip in itemize environments and linebreak size
#              after non-inline urls
# Revision 32: Smarter tex escape filtering when counting characters in potential 
#              section/subsection lines
# Revision 33: Cleaned up TLA regex code so we don't need duplicate lines anymore
#              Added switch to suppress TLA conversion and updated help message
# Revision 34: Since \emph{\textsc{ * }} doesn't exist, change to just \emph. Updated
#                .* in regexp to be non-greedy, so it catches the `}}' at the end.
# Revision 35: Add digits to TLA regex so things like MP3 and 32X get caught
#
# Revision 36: Major change to url-handling. Groups of urls now use the urlblock and linkblock
#              environments for formatting. This means better line-wrapping of long urls, more
#              reliable spacing, and fewer underfull-hbox warnings. Also, the itemize environment
#              has been changed to the briefs environment (to give us a bit more control over
#              line spacing). Relocated \parskip setting from doc body to brief environment.
# Revision 37: Fix to TLA+# regex behavior. Since it considers 3+digit numbers to be caps runs,
#              add check at end of conversions to convert-back numbers (e.g., \textsc{2002} -> 2002)
# Revision 38: Added multiples-handling to TLAs (e.g, `32X')
# Revision 39: Made smallcaps `1' fix look for multiple `1' chars within the \textsc{}
#              Improved(?) fix for smallcaps/italic conversion
# Revision 40: Undid smallcaps `1' fix and changed the bembo interpretation of SC 1 to suit my needs.
#              Had another go at fixing smallcaps/italic problems.
# Revision 41: Fixed custom acronyms conversion to deal with escapes proparly (e.g. `AT\&T')
#              Added warning when more than one hrule is found in an MDJ document
# Revision 42: Underscores now catch compound words where only the first portion is to be
#              emphasized (e.g. `_non-_PostScript')
#              Emboldens Q & A labels in ask-the-staff sections
# Revision 43: Fixes carets that aren't being used to denote exponents
# Revision 44: Added handlers for Vs. v. and Q&A
# Revision 45: Added quick & dirty line wrapping for long section titles (char counting)
# Revision 46: Cleaned up public frontmatter (so it actually compiles now)
# Revision 47: Removed requirement that vs. be followed by a cap for spacing.
# Revision 48: Added TidBITS mode for cleaning up ToC and erasing ads
# Revision 49: Now distinguishes between 1/2 columns and landscape/portrait orientation
#              via separate switches. Adjusts column spacing for portrait 2-col mode.
# Revision 50: In non-mxj docs, looks for double-dollar tag (meaning end-of-doc) and sets all
#              following lines as boilerplate text
# Revision 51: Tweaks to the margin sizes in the two-column portrait layout
# Revision 52: Fixed bug in backslash handling that could introduce spaces and newlines(!)
# Revision 53: Fixed quoted-backslash bug in preprogrammed acronyms
# Revision 54: Fixed a typo in the gremlin zapping that missed '\{'
# Revision 55: Migrated doc output into its own subroutine (for neatness's sake)
#              Made footer start on first page rather than second
# Revision 56: Updated the hyphenation behavior in URLs, now tries to break at
#              slashes or various other punctuation chars rather than at every char
# Revision 57: Disregard the [9] in [9][X] when checking for URL refs
# Revision 58: Misc. tweaks to the hyphenation changes
# Revision 59: Now correctly calls \textdollaroldstyle for dollar signs in OsF
# Revision 60: Changed the layout to make margins smaller
# Revision 61: Fixed exponentiation (added braces and switched to superior numerals)
# Revision 62: Added custom hyphenation for words with InterCapping
# Revision 63: Added margin-kerning for non-public mode
# Revision 64: Added boxing of [9] and [X] in product showcase
# Revision 65: Added switch to select placing the version boxes inline w/i title
# Revision 66: Fixed bug where the first line of the input file was being discarded
#              Switched textoldstyledollar back to a smallcap dollar (since nobody includes it)
# Revision 67: Broke up latex frontmatter-creation into separate subroutines
#              Smart-rewrapping of \section titles now actually compiles the latex
#              code and measures the resulting text rather than just counting chars.
#              Fixed handling of nested quote: "' (was previously looking for "`)
#              Fixed one of the isPublic latex headers which was missing
# Revision 68: Updated the \section breaking to split lines on ; and - as well as :
# Revision 69: Added + to legal dividers in small cap blocks (in addition to - and / )
# Revision 70: Changed -scan option to just print the table of contents, not produce output
# Revision 71: Fixed a condition where a line ending with `-' would have the last word 
#              removed, but not re-added if the next line was totally empty.
#              Updated the non-public headers to reflect texmf changes
# Revision 72: Added a (hopefully) temporary hack to smallcap (not italicize) MDJ_ 
#              Also fixed quote-education for "s at the beginnings of lines
# Revision 73: Now filters out blanks at the end of section- or article-title lines
#              so it doesn't misidentify --- as an hrule
# Revision 74: The hack from rev72 was modifying a temporary string instead of the real one...
# Revision 75: Fixed side-effect of using \, as space around em-dashes. Now consider \, as 
#              white-space in quote-education phase
# Revision 76: Massively sped-up the small-capification of custom acronyms by breaking it out
#              of its loop and pattern-matching using s///gm. Turned off smart-testing of line-
#              breaking of title text if this is a public version (since other users may not
#              have TeX in a working state when they run the script).
# Revision 77: Streamlined the rest of the small-capping code. 
# Revision 78: Fix to undo small-capping within URLs
# Revision 79: Some text-size tweaks.
# Revision 80: Did some reformatting of the MDJ boilerplate section and added [D] symbol
#              Now reads .txt files as well as .etx
# Revision 81: Added table of contents and fixed urlblock problem choking on urls on the 
#              last line of text
# Revision 82: Changed the period spacing after a `vs.' ToDo: update the others too
# Revision 83: Added period spacing for `Inc.'
#              Changed Paragraphs starting with **subhead** -- to use \topicpar{}
#              Fixed the [9] and [X] boxes for product showcase entries
#              Tightened spacing in link/urlblocks (for non-public version)
# Revision 84: Made the [9] and [X] boxes not appear in TOC lines (latex didn't like that)
# $$
$SetexRevisionNumber=84;
#
# Tag Equivalence:
#       bold-tt        *text*     \etxBold
#       underline-tt   _text_     \etxUline
#       hot-tt         text_      \etxEmph
#       title-tt       =====      \etxTitle
#       ??             -----      \section
#                      **\w**     \subsection
#                      [\d]       \etxRef
#                      <*>        \etx(Inline)URL
#                      [\d] <*>   \etxLink
#
##########################################################################

$isPublic=1; # If 0, output is dependent on my local setup

my(@data, # The contents of the input file
   $filename, # The file we'll write our output to
   $opt_twoup,    # Flag for 2up layout
   $opt_numCols,  # Number of columns (by default: 2 for landscape, 1 for portrait)
   $opt_nofooter, # Flag to suppress printing fancy footer
   $opt_nosmallcaps, # Flag to suppress converting caps words to smallcaps
   $opt_mdj,      # Flag for special mdj-handling
   $opt_tidbits,  # Flag for special tidbits-handling
   $opt_printToC, # Flag to print a table of contents as file is processed
   $opt_verbose); # Flag to be chatty
my($title_linenum, $title_text, @customHyphenations);

&readInputFile; ## Parse Command Line & read in file
&zapGremlins;   ## Escape all problematic special-characters
                #  and set up custom \hyphenation patterns
&doTidbitsPreprocessing;
&doSectioning;  ## Find document title (set $title_linenum/text)
                #  and divide into sections based on --- and ===
                #  tags
&doHyphenation; ## Extend `-' chars as needed and do line-wrapping
&doMdjConversions;
&doSmallCapping;# Convert TLAs to small caps
&processStars;  # Convert ** tag to embolden 
&processUnderscores; # Try to infer _italicization_by_underscore_
&processLinks;  # Convert <url> to use \etxUrl{} or \etxLink{}
&doItemization; # Convert lines with leading `*'s to \item bullets
&doCleanup;

&packageDocument; # Piece together the latex header, footer, body, etc.
&outputDocument;  # Write the text to file


exit(0);
## Done






#########################################################
#
# readInputFile()
#
# Parses command line options and reads in the input file
#
#  Reads Variables: @ARGV
#  Sets  Variables: $opt_mdj    Boolean: Mdj-optimization
#                   $opt_twoup  Boolean: Twoup layout
#                   $filename   String:  Name of file to write output to
#                   @data       Array:   The lines of the input file
sub readInputFile{
    my($in_filename,$out_filename);

    # Process args (setting flags, etc.)
    for(@ARGV){

	if (m/^-/){
	    if    (m/^-1/){ $opt_numCols=1; }
	    elsif (m/^-2/){ $opt_numCols=2; }
	    elsif (m/^-l/){ $opt_twoup=1; if($numCols==0){ $numCols=2; }}
	    elsif (m/^-m/){ $opt_mdj=1; }	    
	    elsif (m/^-t/){ $opt_tidbits=1; } #elsif (m/^-t/){ $opt_printToC=1; }
	    elsif (m/^-c/){ $out_filename="__StdOut__"; }
	    elsif (m/^-nof/) { $opt_nofooter=1; }
	    elsif (m/^-nos/) { $opt_nosmallcaps=1; }
	    elsif (m/^-v/){ $opt_verbose=1; }
	    elsif (m/^-s/){ $opt_printToC=1; }
	    elsif (m/^--v/){ die "seTeX version $SetexRevisionNumber\n"; }
	    elsif (m/^--h/){
		print "Convert setext-formatted documents to latex markup.\n\n";
		print "Usage: setex [--help] [-c] [-2] [-landscape] [-mxj | -tidbits] [-nofoot] [-nosc] [-v] [-scan] <input file> [output file]\n\n";
		print "Options:\n";
		print "    -c         Write to stdout\n";
		print "    -2         Print in two-column layout\n";
		print "    -landscape Print in landscape orientation\n";
		print "    -mxj       Use special MDJ/MWJ-handling\n";
		print "    -tidbits   Use special TidBITS-handling\n";
		print "    -nofoot    Don't print a footer\n";
		print "    -nosc      Don't convert CAPS to smallcaps\n";
		print "    -scan      Print out a table of contents listing\n";
		exit;
	    }
	}
	elsif(! $in_filename){ $in_filename=$_; }
	elsif (! $out_filename){ $out_filename=$_; }
	else{
	    print "Mystery argument: $_\n";
	}
    }

    ## Verify existence of input file
    if ($in_filename eq ""){
	die("Usage: setex [--help] [-c] [-2] [-landscape] [-mxj | -tidbits] [-nofoot] [-nosc] [-v] [-scan] <input file> [output file]\n");
    }elsif(! -f $in_filename){
	my $alt_filename = join('',$in_filename,".etx");
	if (! -f $alt_filename){
	    die("File: $in_filename doesn't exist\n");
	}else{
	    $in_filename = $alt_filename;
	}
    }
    
    ## Deal with undefined $out_filename
    if(! $out_filename && $in_filename =~ m/[[:print:]]*.etx/){
	$out_filename = `basename $in_filename .etx`;
	chomp($out_filename);
	$out_filename = "$out_filename.tex";
    }elsif(! $out_filename && $in_filename =~ m/[[:print:]]*.txt/){
	$out_filename = `basename $in_filename .txt`;
	chomp($out_filename);
	$out_filename = "$out_filename.tex";
    }elsif(! $out_filename){
	die("No output file specified.\n");
    }

    ## Deal with potentially clobbering output file
    if ($out_filename ne "__StdOut__" && -f $out_filename){
	print STDERR "File \"$out_filename\" exists. Overwrite? (Y/n) ";
	$_=<STDIN>;
	if ( !(m/[Yy]/ || length($_)==1) ){
	    die("Okay, quitting.\n");
	}
    }

    ## Read in the input file
    open(INFILE, "<$in_filename") || die("Can't open input file: $!");
    while (<INFILE>){
	push @data, $_;
    }
    close(INFILE);
    chomp(@data);

    ## Return our values
    $filename = $out_filename;
    push @retlist, $opt_twoup;
    push @retlist, $opt_mdj;
    push @retlist, $out_filename;
    return @retlist
}


###################################################################
#
# zapGremlins()
#
#   Escapes all the special laTeX characters
#
#   Modifies: @data
#             @customHyphenations
#
sub zapGremlins{
    $opt_verbose && print STDERR "zapGremlins";
    my(%hyphHash);

    # Assumes @data is the text we're working on
    for ($i=0; $i<= $#data; $i++){
	$_ = $data[$i];			# $_ is default for m//

	# zap $
	s/\$/\\\$/g;
	s/\{/\\\{/g; $data[$i] = $_; # zap {
	s/\}/\\\}/g; $data[$i] = $_; # zap }
	
	# zap any \ we didn't create in the `$', `{', or `}' steps
	s/\\(?![\$\}\{])/\\textbackslash{}/g; $data[$i] = $_; 

	# Zap remaining gremlins
	s/\%/\\\%/g; $data[$i] = $_; # zap %
	s/\#/\\\#/g; $data[$i] = $_; # zap #
	s/\&/\\\&/g; $data[$i] = $_; # zap &
	
	# zap ~
	if(m/~\s/ && ($` !~ /</) && ($' !~ />/) ){
           s/~\s/\\textasciitilde\\ /g;
           $data[$i] = $_; 
	}elsif (m/~.*(?!\>)/ && ($` !~ /</) && ($' !~ />/) ){           
           s/~/\\textasciitilde /g;
           $data[$i] = $_;
        }


	## Find words with InterCapping for custom hyphenizations
	while ($data[$i] =~ m/([A-Za-z]+[a-z][A-Z][A-Za-z]+)/g){
	    $theWord = $1;
	    $hyphenatedWord = $1;
	    $hyphenatedWord =~ s/([a-z])([A-Z])/$1-$2/g;

	    # Store it in a hash so we can weed out duplicates
	    $hyphHash{"$theWord"} = $hyphenatedWord; 
	};

    }
    # Save all the unique interCapped words we found for later...
    @customHyphenations = values %hyphHash;

    $opt_verbose && print STDERR ".\n";    
}

###################################################################
#
# doHyphenation()
#
#   Translates ascii `-' characters to proper dash lengths based on
#   line context
#
#   Modifies: @data
#
sub doHyphenation{
    $opt_verbose && print STDERR "doHyphenation";
    my ($carried_word);
    for ($i = 0; $i <= $#data; $i++) {
	$_ = $data[$i];			# $_ is default for m//

	# There are 4 different conditions under which we
	# need to deal with dashes:
	# a) long dividers:  " -- "  ->  " ---"
	# b) short dividers: " - "   ->  " -- "
	# c) end-of-line:    " -$"   ->  " --$"
	# d) manually hyphenated words:  "\w-$"
	
	## Case a:
	s/ -- / --- /g; # Usually a spacer, so leave the whitespace
	## Case b:
	s/ - /---/g; # Typically used midsentence as a dash
	## Case c:
	s/ -$/---/g; # then use rule D to reflow the lines
	$data[$i] = $_;
	
  
	# Make sure we ignore things that aren't hyphens/dashes
	# (i.e., bail out if we shouldn't handle case D and rewrap)
	next if ( m/----+$/ || m/ -+$/); 

	## Case d:
	###s/\s((\w[\w[:punct:]]+-)+)$// && do{  ## clip out hyphenated baseword 
	###       ^__ At lease first char must be alphanum
	if($data[$i+1] =~ m/^(\s*)(\w*)(\W)/){
	    # ^-- make sure there's text on the next line, since otherwise this is
	    #     probably not a hypenation and we should probably leave it as is
	    s/\s(([\w[:punct:]]+-)+)$// && do{  ## clip out hyphenated baseword 
		#print "$filename $i:\t\"$data[$i]\"\n";
		$data[$i] = $_;   ## save clipped line
		$carried_word=$1;
		#print "$filename $i:\t\"$_\": \"$carried_word\"\n";
		#print "\t\t\"$_\"\n";
		$_ = $data[$i+1];
		# insert baseword at front of next line:
		s/^(\s*)(\w*)(\W)/$1$carried_word$2$3/;
		#print "\t\t\"$_\"\n";
		$data[$i+1] = $_; ## save next line
	    };
	}
    }
    $opt_verbose && print STDERR ".\n";
}

###################################################################
#
# doSectioning()
#
#   Looks for lines of --- or === characters marking section or
#   document titles respectively. Also, catch text flanked by
#   **double stars** as being a subsection.
#
#   Modifies: @data
#   Sets Variables: $title_linenum # The line with the document title
#                   $title_text    # The Text of the document title
#
#   Note: may set $opt_mdj to 1 if the document title looks like an MDJ issue
sub doSectioning{
    $opt_verbose && print STDERR "doSectioning";
    my ($title_len, $sect_len, $prev_len, $prev_line, $new_line,@table_of_contents);
    $title_linenum = -1;

    for ($i = 0; $i <= $#data; $i++) {
	$_ = $data[$i];			# $_ is default for m//
	
	## Find Document Title (single line with `====' on following line)
	/(^==+)[\s]*$/ && do{	
	    ## If the number of `='s is same as num chars on prev line,
	    #  this is the title. But first screen out any `\' escapes
	    #  before calculating the previous line's length
	    $title_len=length($1);

	    # filter tex commands/escapes
	    $prev_line = $data[$i-1];
	    $prev_line =~ s/(?:\\[a-z]+\{)+(.*)/$1/g;
	    $prev_line =~ s/(?<!\\)\}//g;
	    $prev_line =~ s/\\//g;
	    $prev_line =~ s/([\s]*)$//;
	    $prev_len=length($prev_line);
	    
	    if ($title_len == $prev_len){
		# The lines correspond, so this must be the title
		$new_line="\\etxTitle{$data[$i-1]}";
		$title_text=$data[$i-1];
		@data[$i-1,$i] = $new_line;
		$i--;

		# The title begins with the telltale MDJ, so pretend the -mdj opt is present
		if ($new_line =~ m/MDJ\s\d/){
		    $opt_mdj=1;
		}
	    }

	    if($title_linenum==-1){
		$title_linenum = $i; ## Note where the first valid line in file is
	    }else{
		print STDERR "Found another `Title' line at $i (original at line $title_linenum)\n";
	    }
	};
	

	## Find Sections (lines with `-----' on following line)
	/(^--+)[\s]*$/ && do{
	    $sect_len=length($1);

	    # filter tex commands/escapes
	    $prev_line = $data[$i-1];
	    $prev_line =~ s/(?:\\[a-z]+\{)+(.*)/$1/g;
	    $prev_line =~ s/(?<!\\)\}//g;
	    $prev_line =~ s/\\//g;
	    $prev_line =~ s/([\s]*)$//;
	    $prev_len=length($prev_line);

	    if ($sect_len == $prev_len){
		$new_line="\\section{$data[$i-1]}";

		# Check for section titles that run over multiple lines
		if (length($data[$i-1]) >= 22 && &checkLineBreak('section',"$data[$i-1]")){
		    $opt_verbose && print STDERR "o";
		    $new_line =~ s/(:|;| - )/$1\\\\/; # If title too long, wrap at first colon
		    $new_line =~ s/section{/section[$data[$i-1]]{/;
		}else{
		    $opt_verbose && print STDERR ".";		    
		}

		if ($opt_printToC && $data[$i-1] !~ m/Top of the Day/i){
		    #print STDERR "$data[$i-1]\n";
		    push @table_of_contents,"$data[$i-1]\n";
		}
		@data[$i-1,$i] = $new_line;
		$i--;
	    }
	};

	## Find Subections (lines starting & ending with `**')
	/^\*\*(.+)\*\*\s*$/ && do{
	    $new_line="\\subsection\{$1}";

	    ## Special case, check for ** tags within subsection title
	    if ($new_line =~ m/^(.*)\*\*(.+)\*\*(.*)$/){
		$new_line = "$1\\etxBold\{$2\}$3\n";
	    }
	    if ($opt_printToC){ 
		#print STDERR " - $1\n"; 
		push @table_of_contents," - $1\n";
	    }
	    $data[$i]=$new_line; # Update line in doc

	};
	
        ## Find SubSubsections (lines starting with a '** **' complex,
        #                       but continuing on into a paragraph)
		
	if (! $isPublic){
	    $data[$i] =~ s/^\*\*(.+)\*\*\s*?--(.*)$/\\topicpar\{$1\}  $2/;
	}
        $data[$i] =~ s/^\*\*(.+)\*\*(\s.*)$/\\topicpar\{$1\}$2/;
    }
    $opt_verbose && print STDERR ".\n";

    # Dump the listing to stderr
    if (@table_of_contents){
	unshift @table_of_contents, "$title_text\n";
	print STDERR "\n@table_of_contents\n";
	exit(0);
    }
}


###################################################################
#
# doTidbitsPreprocessing()
#
#   Reads: $opt_tidbits
#   Modifies: @data
sub doTidbitsPreprocessing{
    if ($opt_tidbits){
	$opt_verbose && print STDERR "doTidbitsConversions";

	# Strip out the ads
	my($begin_ads,$end_ads,$begin_clip);
	$begin_ads=-1,$end_ads=-1,$begin_clip=-1;
	for ($i = 0; $i <= $#data; $i++) {
	    if ($begin_clip==-1 && $data[$i] =~ m|^<http://www.tidbits.com|){
		$begin_clip=$i;
	    }
	    if ($data[$i] =~ m/   ---+$/){
		if ($begin_ads==-1){
		    $begin_ads=$i;
		}else{
		    $end_ads=$i;
		    last;
		}
	    }
	}
	@data = @data[0 .. $begin_clip-1,$end_ads+1 .. $#data];


	#
	# Do special layout for Topics list
	#

	# First find the lines in the list
	my($begin_topics,$end_topics);
	$begin_topics=-1,$end_topics=-1;
	for ($i = 0; $i <= $#data; $i++) {
	    if ($begin_topics==-1 && $data[$i] =~ m/^Topics:\s*$/){
		$begin_topics=$i;
	    }elsif($begin_topics!=-1 && $data[$i] =~ m/^\s*$/){
		$end_topics=$i-1;
		last;
	    }
	}

	# Do the markup
	$data[$begin_topics] = "\\vspace{2ex} \\noindent $data[$begin_topics]\\\\";
	for ($i=$begin_topics+1; $i<=$end_topics; $i++){
	    $data[$i] =~ s/^(\s*)(.*)$/$1\\indent $2\\\\/;
	}

	$opt_verbose && print STDERR ".\n";
    }
}


###################################################################
#
# doMdjConversions()
#
#   Reads: $opt_mdj
#   Modifies: @data
#
#   Makes some MDJ-specific modifications including:
#     o Cleaning up trailing v's before url lines
#     o Setting the copyright notice as the `author'
#     o Converting [symbol] strings
#     o Setting PGP signature blocks to {verbatim}
#     o Converting ALL-CAPS words to smallcaps
sub doMdjConversions{
    if ($opt_mdj){
	$opt_verbose && print STDERR "doMdjConversions";
	my $have_set_author=0;
	
	# The boxed 9 & X commands
	my $localopt_inlineVersions=1;
	my $boxed9X='\versionNineAndTenBox{}';
	my $boxed9='\versionNineBox{}';
	my $boxedX='\versionTenBox{}';

	## Find PGP signature blocks and convert them to be verbatim
	my $blockstart=-1, $blockend=-1;
	for ($i = 0; $i <= $#data; $i++) {
	    # find signature blocks
	    $_ = $data[$i];			# $_ is default for m//
	    if (m/-+BEGIN PGP SIGNATURE-+/ && $blockstart==-1){$blockstart=$i; }
	    elsif (m/-+END PGP SIGNATURE-+/ && $blockstart!=-1){ $blockend=$i; }
	    
	    ## Deal with (PGP) Signature Blocks
	    if ($blockstart>0 && $blockstart<$blockend && 
		($blockend-$blockstart)<16){
		$data[$blockend] = join('',"$data[$blockend]","\\end{verbatim}");
		$data[$blockstart] = join('',"\\begin{verbatim}","$data[$blockstart]");
		$blockstart=-1, $blockend=-1;
	    }	    
	}

	## Find Q & A blocks
	for ($i = 0; $i <= $#data; $i++) {
	    $data[$i] =~ s/^Q/\\noindent\\textsb{Q}/;
	    $data[$i] =~ s/^A/\\vspace{2ex plus0ex minus2ex}\\noindent\\textsb{A}/;
	}	

	## Do misc. MDJ tweaks
	for ($i = 0; $i <= $#data; $i++) {
	    $_ = $data[$i];			# $_ is default for m//
	    
	    # Make copyright line the `author' for beauty's sake
	    if (!$have_set_author && m/^\s*(Copyright.*)$/){
		$data[$i]="\\etxAuthor{$1}";
		$have_set_author=1;
	    }
	    
	    # Clip out their weird pasting artifacts
	    if (m/ v$/ && $data[$i+1] =~ m/^(\W)*\</ ){
		$data[$i] =~ s/ v$//;
	    }

            ## Replace currency refs, etc. with symbols
	    $data[$i] =~ s/\[gbp\]/\\pounds /gi;
	    $data[$i] =~ s/\[yen\]/\\textyen /gi;
	    $data[$i] =~ s/\[euro\]/\\texteuro /gi;
	    $data[$i] =~ s/\[tm\]/\\texttrademark\\ /gi;
	    $data[$i] =~ s/\[deg\]/\\textdegree\\ /gi;

	    ## Use smallcaps for dollar expressions
	    $data[$i] =~ s/US\\\$/\\textsc{us\\\$}/gi;

	    ## Convert the [9] and [X] in product showcase into boxed chars
	    if ($localopt_inlineVersions){
		# Place chars in subsection name
		if ($data[$i] =~ m/^\s*\[9\]\[X\]/){
		    # Handle [9] [X]
		    if ($data[$i-1] =~ s/(^\s*\\(?:sub)*section)\{(.*(?=\}))/$1\[$2\]{$2 $boxed9X/){
			$data[$i] =~ s/\[9\]\[X\] //g;
		    }elsif($data[$i-2] =~ s/(^\s*\\(?:sub)*section)\{(.*(?=\}))/$1\[$2\]{$2 $boxed9X/){
			$data[$i] =~ s/\[9\]\[X\] //g;
		    }
		}elsif ($data[$i] =~ m/^\s*\[9\]/){
		    # Handle [9]
		    if ($data[$i-1] =~ s/(^\s*\\(?:sub)*section)\{(.*(?=\}))/$1\[$2\]{$2 $boxed9/){
			$data[$i] =~ s/\[9\] //g;
		    }elsif($data[$i-2] =~ s/(^\s*\\(?:sub)*section)\{(.*(?=\}))/$1\[$2\]{$2 $boxed9/){
			$data[$i] =~ s/\[9\] //g;
		    }
		}elsif ($data[$i] =~ m/^\s*\[X\]/){
		    # Handle [X]
		    if ($data[$i-1] =~ s/(^\s*\\(?:sub)*section)\{(.*(?=\}))/$1\[$2\]{$2 $boxedX/){
			$data[$i] =~ s/\[X\] //g;
		    }elsif($data[$i-2] =~ s/(^\s*\\(?:sub)*section)\{(.*(?=\}))/$1\[$2\]{$2 $boxedX/){
			$data[$i] =~ s/\[X\] //g;
		    }
		}
	    }else{
		# Place chars within review
		$data[$i] =~ s/\[9\]\[X\]/$boxed9X/g;
		
		if ($data[$i] =~ m/^\s*\[9\]/){
		    if ($data[$i-2] =~ m/^\s*\\(sub)*section/ ||
			$data[$i-1] =~ m/^\s*\\(sub)*section/){
			$data[$i] =~ s/\[9\]/$boxed9/g;
		    }
		}elsif($data[$i] =~ m/^\s*\[X\]/){
		    if ($data[$i-2] =~ m/^\s*\\(sub)*section/ ||
			$data[$i-1] =~ m/^\s*\\(sub)*section/){
			$data[$i] =~ s/\[X\]/$boxedX/g;
		    }
		}
	    }
           
	}
	$opt_verbose && print STDERR ".\n";
    }
}


###################################################################
#
# doSmallCapping()
#
#   Reads: $opt_nosmallcaps
#   Modifies: @data
#
#   Converts ALL-CAPS words to smallcaps
sub doSmallCapping{
    if ($opt_nosmallcaps){
	return;
    }
    $opt_verbose && print STDERR "doSmallCapping";
    my $isVerb=0; # A flag for when we're in a verbatim environment

    ##-----------------------------------
    ## Find TLAs and make them small-caps
    for ($i = 0; $i <= $#data; $i++) {
	# This is the first line of a verbatim section, so set flag
	if ($isVerb==0 && $data[$i] =~ m/\\begin\{verbatim\}/){  $isVerb=1;  }
	# This is the last verbatim line, set flag that next line is okay
	if( $isVerb==1 && $data[$i] =~ m/\\end\{verbatim\}/){    $isVerb=2;  }
	# last line closed verb section, this line is okay
	if ($isVerb==2){                                         $isVerb=0;  }

	next if ( $data[$i] =~ m/^\s*\[(\d+)\]\s+\<([[:print:]]+?)\>\s*$/ ||  # skip links
		  $data[$i] =~ m/^\s*\<([[:print:]]+?)\>\s*/ ||               # skip urls
		  $data[$i] =~ m/^\\etxTitle/ ||                              # skip title line (in sans)
		  $data[$i] =~ m/-{4,}/ ||
		  $isVerb != 0);
	
	# If we didn't skip, then it's okay to apply smallcaps operation on this line
	$data[$i] =~ s/\b([A-Z0-9\-\+\/\\&]{3,})s\b/\\textsc{\L$1}s/g; # Catch caps words ending with `s'
	$data[$i] =~ s/\b([A-Z0-9\-\+\/\\&]{3,})\b/\\textsc{\L$1}/g;   # Catch caps words

	$data[$i] =~ s/\b([A-Z][0-9])\b/\\textsc{\L$1$2}/g; # Catch 2-char strings like 3D 
	$data[$i] =~ s/\b([0-9][A-Z])\b/\\textsc{\L$1$2}/g; # Catch 2-char strings like G4 

	# Handle underscored caps too
	$data[$i] =~ s/(?<=[_ [:punct:]])([A-Z0-9\-\+\/&\\]{3,})(?=[_ [:punct:]])/\\textsc{\L$1}/g;

	### Undo side-effect of...
	{
	    #...small-capping 3+digit numbers
	    while ($data[$i] =~ m/\\textsc{([0-9\-\\\/]+)}/){
		$data[$i] =~ s/\\textsc{([0-9\-\\\/]+)}/$1/g;
	    }
	    #...single caps near dashes
	    $data[$i] =~ s/\\textsc{(-+[a-z])}/\U$1/g;
	    $data[$i] =~ s/\\textsc{([a-z]-+)}/\U$1/g;
	    #...smallcapping 68K (which looks bad)
	    $data[$i] =~ s/\\textsc{68k}/68K/;
	}
    }

    # Catch any 2-letter abbrevs specified in the @acronyms array
    my @acronyms = qw(CD XP IP TV ID PC US AM PM MX GX VP HP AG);
    my $wholeDoc = join("\n",@data);
    my $bspace='(?<=[ [:punct:]])'; # matches a divider char Before pattern
    my $fspace='(?=[ [:punct:]])';  # matches a divider char Following pattern

    foreach $ac (@acronyms){
	my $lc_ac = lc $ac; # Downcase the acronym
	$lc_ac =~ s/\\\\/\\/g; # Deal with quoting of backslash chars
	$wholeDoc =~ s/$bspace${ac}$fspace/\\textsc{$lc_ac}/mg;
	$wholeDoc =~ s/$bspace${ac}s$fspace/\\textsc{$lc_ac}s/mg;
	$wholeDoc =~ s/$bspace${ac}$/\\textsc{$lc_ac}/mg;
	$wholeDoc =~ s/$bspace${ac}s$/\\textsc{$lc_ac}s/mg;
    }
    
    ### Undo side-effect of small-capping within a URL
    $wholeDoc =~ s/(<.*?)\\textsc\{(.*?)\}(.*>)/$1\U$2$3/mg;

    # Commit changes
    @data = split(/\n/,$wholeDoc);

    $opt_verbose && print STDERR ".\n";
}


###################################################################
#
# processStars()
#
#   Modifies: @data
#
#   Emboldens words with bold-tt tags (e.g., *bold words*)
sub processStars{
    $opt_verbose && print STDERR "processStars";
    my ($new_line);
    for ($i = 0; $i <= $#data; $i++) {
	$_ = $data[$i];			# $_ is default for m//

	# It's unlikely we'll see an asterisk in a url, but just 
	# to be on the safe side we'll skip the line...
        next if ( m/^\s*\[(\d+)\]\s+\<([[:print:]]+?)\>\s*$/ ||
                  m/^\s*\<([[:print:]]+?)\>\s*/ );

	## Process Double-Stars
	while ( m/(^.*\s)(\*\*)([\w\s[:punct:]]*)(\*\*)(.*)$/g ){ 
	    # $2 and $4 are the junk *'s
	    $new_line = join('',$1,"\\etxBold{",$3,"}",$5);
	    $_ = $new_line;
	    $data[$i] = $_;
	}

	## Process Stars
	while ( m/(^.*\s)(\*)([\w\s[:punct:]]*)(\*)(.*)$/g ){ 
	    # $2 and $4 are the junk *'s
	    $new_line = join('',$1,"\\etxBold{",$3,"}",$5);
	    $_ = $new_line;
	    $data[$i] = $_;
	}
    }
    $opt_verbose && print STDERR ".\n";
}

###################################################################
#
# processUnderscores()
#
#   Modifies: @data
#
#   Converts underscores representing hot-tt or underline-tt, or
#   escapes them if they're embedded in the middle of a_word.
#
sub processUnderscores{
    $opt_verbose && print STDERR "processUnderscores";
    my($pre, $post, $clipping, $new_line);
    for ($i = 0; $i <= $#data; $i++) {
	$_ = $data[$i];			# $_ is default for m//

	# We want to leave underscores untouched in urls, so bail out
        # if this line is either an \extLink{} or \etxURL{} respectively.
        next if ( m/^\s*\[(\d+)\]\s+\<([[:print:]]+?)\>\s*$/ ||
                  m/^\s*\<([[:print:]]+?)\>\s*/ );

	#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	# This is a nasty hack that should probably be moved somewhere
        # more appropriate (that or hot_ tags should be set properly
	# to begin with). In any case, we want to prevent MDJ_ from
	# being italicized instead of smallcapped.
	s/\\textsc\{mdj\}_/\\textsc\{mdj\}/g;
	s/\\textsc\{mwj\}_/\\textsc\{mwj\}/g;
	#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

	## Process underscores
	#
	# There are two varieties of underscore tag:
	#   a) Underlining: _the_text_
	#   b) Emphasizing:  the_text_
	#
	#   c) Degenerate underlining(?): _the_text
	#

	####################
	## Case a:
	while ( m/(^.*\s)(_(?:\S+_)+)([\s[:punct:]].*)$/g  ){
	    # look for whitespace_text_whitespace
	    $pre=$1; $post=$3;
	    $clipping = substr($2,1,length($2)-2);
	    $clipping =~ s/_/ /g;
	    $clipping = join('',"\\etxUline{",$clipping,"}");
	    $new_line = join('',$pre,$clipping,$post);
	    $_=$new_line;
	    $data[$i] = $_;
	}
	while ( m/(^.*[\s[:punct:]])(_(?:\S+_)+)([\s[:punct:]].*)$/g  ){
	    # As above but consider punctuation to be whitespace too
	    $pre=$1; $post=$3;
	    $clipping = substr($2,1,length($2)-2);
	    $clipping =~ s/_/ /g;
	    $clipping = join('',"\\etxUline{",$clipping,"}");
	    $new_line = join('',$pre,$clipping,$post);
	    $_=$new_line;
	    $data[$i] = $_;
	}
	while ( m/(^.*\s)(_(?:\S+_)+)$/g  ){  
	    ## look for _text[eol]
	    $pre=$1; $post=$3;
	    $clipping = substr($2,1,length($2)-2);
	    $clipping =~ s/_/ /g;
	    $clipping = join('',"\\etxUline{",$clipping,"}");
	    $new_line = join('',$pre,$clipping,$post);
	    $_=$new_line;
	    $data[$i] = $_;
	}
	
	####################
	## Case b:
	while (m/(^.*\\\w+\{)((?:\S+_)+)(\s.*)$/g){
	    # look for \word{text_WHITESPACE  (b/c we need to make sure we're not stepping over previously applied latex commands
	    $pre=$1; $post=$3;
	    $clipping = substr($2,0,length($2)-1);
	    $clipping =~ s/_/ /g;
	    $clipping = join('',"\\etxEmph{",$clipping,"}");
	    $new_line = join('',$pre,$clipping,$post);
	    $_=$new_line;
	    $data[$i] = $_;
	}

	while (m/(^.*[\s\(\'\"])((?:\S+_)+)(\s.*)$/g){
	    # look for whitespace|text_whitespace
	    $pre=$1; $post=$3;
	    $clipping = substr($2,0,length($2)-1);
	    $clipping =~ s/_/ /g;
	    $clipping = join('',"\\etxEmph{",$clipping,"}");
	    $new_line = join('',$pre,$clipping,$post);
	    $_=$new_line;
	    $data[$i] = $_;
	}
	
	while (m/(^.*\()((?:\S+_)+)(\).*)$/g){
	    ## Catch punctuation terminator (but look for pairs of parens)
	    ## i.e.,  look for (text_)
	    $pre=$1; $post=$3;
	    $clipping = substr($2,0,length($2)-1);
	    $clipping =~ s/_/ /g;
	    $clipping = join('',"\\etxEmph{",$clipping,"}");
	    $new_line = join('',$pre,$clipping,$post);
	    $_=$new_line;
	    $data[$i] = $_;
	}
	
	while (m/(^.*\[)((?:\S+_)+)(\].*)$/g){
	    ## Catch punctuation terminator (but look for pairs of brackets)
	    ## i.e.,  look for [text_]
	    $pre=$1; $post=$3;
	    $clipping = substr($2,0,length($2)-1);
	    $clipping =~ s/_/ /g;
	    $clipping = join('',"\\etxEmph{",$clipping,"}");
	    $new_line = join('',$pre,$clipping,$post);
	    $_=$new_line;
	    $data[$i] = $_;
	}
	
	while (m/(^.*[\s\(\'\"])((?:\S+_)+)([\s[:punct:]].*)$/g){ ## Catch punctuation terminator
	    # As above but consider general punctuation to be whitespace too
	    $pre=$1; $post=$3;
	    $clipping = substr($2,0,length($2)-1);
	    $clipping =~ s/_/ /g;
	    $clipping = join('',"\\etxEmph{",$clipping,"}");
	    $new_line = join('',$pre,$clipping,$post);
	    $_=$new_line;
	    $data[$i] = $_;
	}
	
	while (m/(^.*[\s\(\'\"])((?:\S+_)+)$/g){ 
	    ## look for whitespace|text_[eol]
	    $pre=$1;
	    $clipping = substr($2,0,length($2)-1);
	    $clipping =~ s/_/ /g;
	    $clipping = join('',"\\etxEmph{",$clipping,"}");
	    $new_line = join('',$pre,$clipping);
	    $_=$new_line;
	    $data[$i] = $_;
	}

	while (m/(?<=\s)(_(?:\S+_)+)/g){
	    $pre="$`";
	    $post="$'";
	    $clipping = substr($1,1,length($2)-1);
	    $clipping =~ s/_/ /g;
	    $clipping = join('',"\\etxEmph{",$clipping,"}");
	    $new_line = join('',$pre,$clipping,$post);
	    $_=$new_line;
	    $data[$i]  = $_;
	}

	## Zap remaining (gremlin) underscores
	s/_/\\_/g; # Escape each _
	$data[$i] = $_;

	# (But then unzap anything within a URL)
	#while (m/^(.*\<.*)\\(.*\>.*)$/){
	#    $_ = "$1$2";
	#}
	#$data[$i] = $_;
    }
    $opt_verbose && print STDERR ".\n";
}

###################################################################
#
# processLinks()
#
#   Modifies: @data
#
#   Deals with hyperlinks and footnotes within the document. URLs
#   are defined by being between <angle brackets> and footnote 
#   references are digits within square brackets (e.g., [2])
#
sub processLinks{
    $opt_verbose && print STDERR "processLinks";
    for ($i = 0; $i <= $#data; $i++) {
	$_ = $data[$i];			# $_ is default for m//

	## There are four types of URL/Reference linking
	#
	# Alone:      The only non-whitespace characters on the    \etxUrl{}
	#             line are between the angle brackets
	# Referenced: Angle bracket-enclosed text is preceded by   \etxLink{}
	#             a hard-bracketed reference number
	#
	# Inline Ref: Hard-bracketed number with non-whitespace    \etxRef{}
	#             characters on one or more sides
	# Inline URL: Angle-bracketed text with non-whitespace     \etxInlineUrl{}
	#             characters on one or more sides

	# Check for paired URL
	if ( m/^\s*\[(\d+)\]\s+\<([[:print:]]+?)\>\s*$/ ){
	    ## Referenced URL
	    # $1: the ref
	    # $2: the URL
	    my ($ref_number, $plain_url, $padded_url);
	    $ref_number=$1;
	    $plain_url=$padded_url=$2;
	    #$padded_url =~ s/(?<!\\)(.)/\\-$1/g; # Puts a hypenation point at every char
	    $padded_url =~ s/(?<!\\)(\/)(?!\/)/$1\\-/g; # Hypenates at single-/
	    $padded_url =~ s/(\\%|\\&|_|,|=|\?|\.)(?!\/)/\\-$1/g; # hyphenates at % & _ or ,
	    $padded_url =~ s/^\\-//;
	    $padded_url =~ s/~/\\textasciitilde /g;

	    $_="\\etxLink{$ref_number}{$plain_url}{$padded_url}";
	    # Add trailing linebreaks as needed
#	    if (!  ($data[$i+1] =~ m/^(\W)*$/ || $data[$i+1] =~ m/^$/) ){
#		$_ = "$_ \\\\\* ";
#	    }else{$_ = "$_ \\\\\*[-1.5ex] "; }
	    $data[$i] = $_;
	}else{
	    ## Isn't a referenced URL line, so replace refs
	    #  and URLs individually as needed

	    ## Replace refs
	    #s/\[(\d+)\]/\\etxRef{$1}/g;          # All [#]s are refs
	    s/\[(\d+)\](?!\[X\])/\\etxRef{$1}/g;  # Disregard the [9] in `[9][X]'
	    $data[$i] = $_;

	    ## Replace URLs
	    if (m/^\s*\<([[:print:]]+?)\>\s*$/){
		my ($plain_url, $padded_url);

		# Convert to \etxUrl{}
		$plain_url=$padded_url=$1;		
		#$padded_url =~ s/(?<!\\)(.)/\\-$1/g; # Puts a hypenation point at every char
		$padded_url =~ s/(?<!\\)(\/)(?!\/)/$1\\-/g; # Hypenates at single-/
		$padded_url =~ s/(\\%|\\&|_|,|=|\?|\.)(?!\/)/\\-$1/g;	# hyphenates at % & _ or ,
		$padded_url =~ s/^\\-//;		
		$padded_url =~ s/~/\\textasciitilde /g;
		s/^\s*\<([[:print:]]+?)\>\s*/\\etxUrl{$plain_url}{$padded_url}/g;

		# Add trailing linebreaks as needed
#		if (!  ($data[$i+1] =~ m/^(\W)*$/   || $data[$i+1] =~ m/^$/) ){
#		#if (!($data[$i+1] =~ m/\^(\W)*$/)){
#		    $_ = "$_ \\\\* ";
#		}else{$_ = "$_ \\\\*[-1.5ex] ";}
	    }
	    $data[$i] = $_;

	    ## Replace inline URLs
	    if (m/\<([[:print:]]+?)\>/){
		my ($plain_url, $padded_url);
		$plain_url=$padded_url=$1;
		
		#$padded_url =~ s/(?<!\\)(.)/\\-$1/g;
		#$padded_url =~ s/^\\-//;
		s/\<([[:print:]]+?)\>/\\etxInlineUrl{$plain_url}{$padded_url}/g;		
	    }
	    $data[$i] = $_;
	}       
    }
    $opt_verbose && print STDERR ".";

    ## Walk through doc finding blocks of URLs
    my(@url_begin, @url_end, $in_url_region);
    $in_url_region = 0; # (i.e., not in an itemize region)
    for ($i = 0; $i <= $#data; $i++) {    
	$_ = $data[$i];			# $_ is default for m//
	
	if (m/\\etxUrl/ || m/\\etxLink/){
	    if (! $in_url_region){
		## This is the beginning of a region
		push @url_begin, $i;
		$in_url_region=1;

		# If this is the last line, it's also the end of the region
		if ($i == $#data){
		    push @url_end,$i+1;
		}
	    }
	}else{
	    if ($in_url_region){
		## This is the end of the region
		push @url_end, $i;
		$in_url_region=0;
	    }
	}
    }
    $opt_verbose && print STDERR ".";

    ## Encapsulate all url blocks in {tabular} environments
    my($this_begin, $this_end, @beg_text, @end_text);
    @beg_text = ();
    @end_text = ();
    while ($#url_begin >= 0){
	# Figure out which type of marker we're adding
	$this_begin=pop @url_begin;
	$this_end=pop @url_end;

	if($this_begin>$this_end){
	    ## Do Beginning first
	    if ($data[$this_begin] =~ m/etxLink/){
		@data = (@data[0 .. $this_begin-1],'\noindent \begin{linkblock}', @data[$this_begin .. $#data]);
		## Do End
		@data = (@data[0 .. $this_end-1], '\end{linkblock}', @data[$this_end .. $#data]);
	    }elsif($data[$this_begin] =~ m/etxUrl/){
		@data = (@data[0 .. $this_begin-1],'\noindent \begin{urlblock}', @data[$this_begin .. $#data]);
		## Do End
		@data = (@data[0 .. $this_end-1], '\end{urlblock}', @data[$this_end .. $#data]);
	    }
#	    print "begin: $data[$this_begin]\n";
#	    if ($data[$this_begin-1] =~ m/\S/){
#		$data[$this_begin-1] = "$data[$this_begin-1] \\\\\*";
#		@data = (@data[0 .. $this_begin-1],'\noindent \begin{urlblock}', @data[$this_begin .. $#data]);
#	    }else{
#		@data = (@data[0 .. $this_begin-1], '\noindent \begin{urlblock}', @data[$this_begin .. $#data]);
#	    }

#	    ## Do End
#	    @data = (@data[0 .. $this_end-1], '\end{urlblock}', @data[$this_end .. $#data]);
	}else{
#	    ## Do End first
#	    @data = (@data[0 .. $this_end-1], '\end{urlblock}', @data[$this_end .. $#data]);

	    if ($data[$this_begin] =~ m/etxLink/){
		## Do End first
		@data = (@data[0 .. $this_end-1], '\end{linkblock}', @data[$this_end .. $#data]);
		## Do Beginning
		@data = (@data[0 .. $this_begin-1],'\noindent \begin{linkblock}', @data[$this_begin .. $#data]);
	    }elsif ($data[$this_begin] =~ m/etxUrl/){
		## Do End first
		@data = (@data[0 .. $this_end-1], '\end{urlblock}', @data[$this_end .. $#data]);
		## Do Beginning
		@data = (@data[0 .. $this_begin-1],'\noindent \begin{urlblock}', @data[$this_begin .. $#data]);
	    }
#	    if ($data[$this_begin-1] =~ m/\S/){
#		$data[$this_begin-1] = "$data[$this_begin-1] \\\\\*";
#		@data = (@data[0 .. $this_begin-1], '\noindent \begin{urlblock}',  @data[$this_begin .. $#data]);
#	    }else{
#		@data = (@data[0 .. $this_begin-1], '\noindent \begin{urlblock}', @data[$this_begin .. $#data]);
#	    }
	}
    }
    $opt_verbose && print STDERR ".\n";
}

###################################################################
#
# doItemization()
#
#   Modifies: @data
#
#   Converts paragraph-starting astrisks into bullet marks and groups
#   sequential bulleted lines into {briefs} environments
#
sub doItemization{
    $opt_verbose && print STDERR "doItemization";
    for ($i = 0; $i <= $#data; $i++) {
	## Convert ^* to \item 
	$data[$i] =~ s/^\*(\s)/\\item$1/;
    }

    # Walk through doc finding itemize regions
    my(@item_begin, @item_end, $in_item_region);
    $in_item_region = 0; # (i.e., not in an itemize region)
    for ($i = 0; $i <= $#data; $i++) {    
	$_ = $data[$i];			# $_ is default for m//
	
	if (m/^\\item/ && ! $in_item_region){
	    ## This is the beginning of a region
	    push @item_begin, $i;
	    $in_item_region=1;
	}

	if ($in_item_region && (m/^\\(sub)*section/ || 
				m/^(\W)*\-+(\W)*$/ ||
				m/^(\W)*\\etxBold\{.*\}\s+--/)){
	    ## This is the end of a region
	    push @item_end, $i;
	    $in_item_region=0;
	}
    }

    # Catch itemize regions that terminate with the end of the file
    if ($#item_begin > $#item_end){ push @item_end, $#data;}
    # Alternately could just see if ($in_item_region==1)
    if ($#item_begin != $#item_end){ 
	print STDERR "begins:  @item_begin\n";
	print STDERR "ends:    @item_end\n";
	die("unmatched \\begin{briefs}");
    }

    #Add \begin and \end{briefs} to mark the regions we found
    while ($#item_begin >= 0){
	# Figure out which type of marker we're adding
	$this_begin=pop @item_begin;
	$this_end=pop @item_end;

	if($this_begin>$this_end){
	    print STDERR "\n$data[$this_begin]\nSTART ITEMIZE\n$data[$this_begin+1]\n";
	    #@data = (@data[0 .. $this_begin-1], '\begin{briefs}\setlength{\parskip}{0.8ex plus0.2ex minus0.1ex}', @data[$this_begin .. $#data]);
	    @data = (@data[0 .. $this_begin-1], '\begin{briefs}', @data[$this_begin .. $#data]);
	    @data = (@data[0 .. $this_end-1], '\end{briefs}', @data[$this_end .. $#data]);
	}else{
	    @data = (@data[0 .. $this_end-1], '\end{briefs}', @data[$this_end .. $#data]);
	    #@data = (@data[0 .. $this_begin-1], '\begin{briefs}\setlength{\parskip}{0.8ex plus0.2ex minus0.1ex}', @data[$this_begin .. $#data]);
	    @data = (@data[0 .. $this_begin-1], '\begin{briefs}', @data[$this_begin .. $#data]);
	}
    }
    $opt_verbose && print STDERR ".\n";
}

###################################################################
#
# doCleanup()
#
#   Modifies: @data
#
#   Performs a few miscellaneous conversions:
#     o Smart quotes
#     o Converting -------'s to \hrule's
#     o Substituting copyright symbol for (c)
#     o Placing exponents (e.g., FutureBasic^3) within a math/superscript environment
#     o Constraining spaces after titles (Mr. Mrs. etc.) not to be inter-sentence spaces
#     o Unsmallcapify italic smallcaps (which don't exist under latex)
#     o Makes boilerplate text at end of MDJ issue/after double-dollar really tiny
#
sub doCleanup{
    $opt_verbose && print STDERR "doCleanup";
    for ($i = 0; $i <= $#data; $i++) {
	$_ = $data[$i];			# $_ is default for m//

	# As before, skip lines that are just URLs
        next if ( m/^\s*\[(\d+)\]\s+\<([[:print:]]+?)\>\s*$/ ||
                  m/^\s*\<([[:print:]]+?)\>\s*/ );

	## Educate single quotes	
	s/(\s)\'/$1\`/g;
	s/\\,\'/\\,\`/g;
	s/([\(\[])\'/$1\`/g;
	s/^\'/\`/g;

	## Educate nested single-double/double-single quotes
	s/\'\"/\'\\,\'\'/g;
	s/\"\'/\`\`\\,\`/g;

	## Educate double quotes
	s/(\s)\"/$1\`\`/g;      #  [whitespace]["]
	s/\\,\"/\\,\`\`/g;      #  [smallspace]["]
	s/([\(\[\{])\"/$1\`\`/g;  #  [opening paren/bracket/brace]["]
	s/^\"/\`\`/g;           #  [newline]["]
	s/\"/\'\'/g; # (remaining quotes should all be closers)

	
	## Substitute \hrules for ---- strings that aren't sections
	s/^(\s)*\-\-\-(\-)*(\s)*$/\\vspace\{2ex\}\\hrule\\vspace\{2ex\}/;
	
	## Replace (c) with copyright symbol
	s/\([Cc]\)/\\textcopyright /g;

	# Render the `disclaimer' symbol differently
	s/\\etxBold\{\[D\]\}/\\etxBold\{\\textsc\{\[d\]\}\}/g;

	$data[$i] = $_; # Retain our changes

	

	## Handle exponents
	if ($isPublic){
	    $data[$i] =~ s/(\^)(\d+)(W*)/\$$1\{$2\}\$$3/g;
	}else{
	    if ($data[$i] =~ m/etxLink\{/){
		$data[$i] =~ s/\^/\^\{\}/g;
	    }else{
		$data[$i] =~ s/(\^)(\d+)(W*)/\\superior\{$2\}$3/g;
	    }
	}
	$data[$i] =~ s/(\^)(?!\{\d)/\\\^{}/g;

	# Fix spacing after personal titles...
	$data[$i] =~ s/(\s)(Mr\. )([A-Z])/$1Mr.~$3/;
	$data[$i] =~ s/(\s)(Mrs\. )([A-Z])/$1Mrs.~$3/;
	$data[$i] =~ s/(\s)(Ms\. )([A-Z])/$1Ms.~$3/;
	$data[$i] =~ s/(\s)(Dr\. )([A-Z])/$1Dr.~$3/;
	$data[$i] =~ s/(\s)(Vs\. )(\w)/$1Vs.~$3/;
	$data[$i] =~ s/(\s)(v\. )(\w)/$1v.~$3/;
	$data[$i] =~ s/(\s)(Inc\. )([a-z0-9\$])/$1Inc.~$3/;

#	$data[$i] =~ s/(\s)(vs\. )(\w)/$1vs.~$3/;
	$data[$i] =~ s/(\s)(vs\.)(\z|\s)/$1$2\\\@$3/g;


	# ..and dates
	$data[$i] =~ s/(\s)(Jan\.) ([0-9])/$1$2~$3/;
	$data[$i] =~ s/(\s)(Feb\.) ([0-9])/$1$2~$3/;
	$data[$i] =~ s/(\s)(Mar\.) ([0-9])/$1$2~$3/;
	$data[$i] =~ s/(\s)(Apr\.) ([0-9])/$1$2~$3/;
	$data[$i] =~ s/(\s)(Jun\.) ([0-9])/$1$2~$3/;
	$data[$i] =~ s/(\s)(Jul\.) ([0-9])/$1$2~$3/;
	$data[$i] =~ s/(\s)(Aug\.) ([0-9])/$1$2~$3/;
	$data[$i] =~ s/(\s)(Sept\.) ([0-9])/$1$2~$3/;
	$data[$i] =~ s/(\s)(Oct\.) ([0-9])/$1$2~$3/;
	$data[$i] =~ s/(\s)(Nov\.) ([0-9])/$1$2~$3/;
	$data[$i] =~ s/(\s)(Dec\.) ([0-9])/$1$2~$3/;

	# Convert ... to \ldots
	$data[$i] =~ s/\.\.\.+(\s)/\\ldots\\$1/gi;
	$data[$i] =~ s/\.\.\.+/\\ldots /gi;	   

	#
	# Correct for italic smallcaps not existing
	#
#        $data[$i] =~ s/(\\etxEmph\{\\textsc\{)(.*?)(\}\})/\\etxEmph{\U$2}/g;
#        $data[$i] =~ s/(\\textsc\{\\etxEmph\{)(.*?)(\}\})/\\etxEmph{\U$2}/g;

	#  -or-  #

	#$nop="[^\{]*?"; # Non-Opeining Paren chars
	$ncp="[^\}]*?"; # Non-Closing Paren chars

	if ($data[$i] =~ m/\\textsc/ && 
	    ($data[$i] =~ m/\\etxEmph/ || 
	     $data[$i] =~ m/\\etxUline/))
	{
	    while ($data[$i] =~ m/(\\textsc\{)($ncp)(\})/g){
		$pre="$`";
		$post="$'";
		$thetag="$&";
		if ($thetag =~ m/\\etxEmph/ || $thetag =~ m/\\etxUline/){
		    # catch \textsc{\etxEmph{
		    $thetag =~ s/\\textsc\{(\\.*?\{)($ncp)\}/$1\U$2/;
		    $data[$i] = "$pre$thetag$post";
		}elsif($pre =~ m/\\etxEmph\{$/s || $pre =~ m/\\etxUline\{$/s ){
		    # catch \etxEmph{\textsc{
		    $thetag =~ s/\\textsc\{([^\\]$ncp)\}/\U$1/;
		    $data[$i] = "$pre$thetag$post";
		}else{
		    # catch \etxEmph{some other words \textsc{capword}}
		    $lastopen  = rindex $pre, '\etxEmph';
		    if ($lastopen == -1){$lastopen = rindex $pre, '\etxUline';}
		    $lastclose = index $pre, '}'; 

		    if ($lastclose==-1 && $lastopen != -1){
			$thetag =~ s/\\textsc\{([^\\]$ncp)\}/\U$1/;
			$data[$i] = "$pre$thetag$post";
		    }
		}
	    }   
	}

    }

    # Shrink setext bolierplate text (after the $$ end-of-doc tag)
    if(!$opt_mdj){
       	for ($i = 0; $i <= $#data; $i++) {
	    if ($data[$i] =~ m/^\\\$\\\$/){
		$data[$i] = '\vspace{2ex}\hrule\vspace{2ex} \relsize{-2}';
		last;
	    }
	}    
    }

    ## Make the MDJ boilerplate more like boilerplate
    if($opt_mdj){
	my $final_hrule=0;
	for ($i = 0; $i <= $#data; $i++) {
	    $_ = $data[$i];			# $_ is default for m//

	    # find final hrule
	    if (m/\\hrule/){
		# If there's more than one `hrule' in an MDJ issue,
		# it's probably a typo in a Section tag. So complain:
		if ($final_hrule != 0){
		    print STDERR "Suspicious hrule:\n";
		    print STDERR "  $data[$final_hrule-2]\n  $data[$final_hrule-1]\n  $data[$final_hrule]\n\n";
		}
		$final_hrule = $i;
	    }
	}

	if ($final_hrule){
	    # Shrink boilerplate text
	    $data[$final_hrule] = join('',"$data[$final_hrule]",' \\relsize{-2}','\setlength{\parskip}{2ex}','\raggedright');


	    ###################################
	    # Make the staff listing look nicer
            ###################################
	    my $staff_begins=-1;
	    my $staff_ends=-1;

	    # Find the block of text
	    for ($i = $final_hrule; $i <= $#data; $i++) {
		$_ = $data[$i];
		if (m/^\s*?Publisher/){
		    if ($staff_begins != -1){
			print STDERR "Suspicious mdj publisher line:\n";
			print STDERR "  $data[$staff_begins-2]\n  $data[$staff_begins-1]\n  $data[$staff_begins]\n\n";
		    }
		    $staff_begins = $i;
		}

		if ($staff_begins != -1 and m/^\s*$/){
		    $staff_ends = $i-1;
		    last;
		}
	    }

	    # Put the block contents into a tabular
	    if ($staff_begins < $staff_ends and $staff_ends != -1){

		@staff_table = @data[$staff_begins..$staff_ends];

		for ($i = 0; $i <= $#staff_table; $i++) {
		    $newline = $staff_table[$i];
		    if ($newline =~ /:/){
			$newline =~ s/:/:&/;			
		    }else{
			$newline = "&$newline";
		    }
		    $newline =~ s/(\\etxInline.*)$/& $1\\\\/;
		    
		    
		    $staff_table[$i] = $newline;
		}

		@staff_table = ('\begin{tabular}{rll}',
				@staff_table,
				'\end{tabular}',
				'');


		#@data[$staff_begins..$staff_ends] = @staff_table;
		@data = (@data[0..$staff_begins-1],
			 @staff_table,
			 @data[$staff_ends+1..$#data]);
		
	    }


	}
    }


    $opt_verbose && print STDERR ".\n";
}



###################################################################
#
# packageDocument()
#
#   Calls: getLatexFrontmatter, getLatexDocBegin
#   Modifies: @data
#
#   Packages up lines in @data by adding the proper laTeX preamble,
#   definitions, and closing.
#
sub packageDocument{
    $opt_verbose && print STDERR "newPackageDocument";

    ## PrepareLaTeX header preamble and command declarations
    my(@latex_header, @latex_begin, @latex_end);
    @latex_header = &getLatexFrontmatter;
    @latex_begin = &getLatexDocBegin;
    @latex_end=('\end{document}',
		'% Local Variables:',
		'% TeX-command-default: "PDFLaTeX"',
		'% End:');	       


    ################################################################
    ## Finish Packaging:
    my @discardedLinesBeforeTitle = @data[0 .. $title_linenum-1];
    @data = @data[$title_linenum .. $#data];

    # Assemble bulk of output document
    @data = (@latex_header, @data, @latex_end);

    # Find proper beginning point for body of document
    my $author_linenum=-1, $date_linenum=-1;
    for ($i = $#data; $i >= 0; $i--) {
	$_ = $data[$i];			# $_ is default for m//

	## Look for \title{} \author{} or \date{}
	if ( ( m/\\author\{.*\}/ || m/\\etxAuthor\{.*\}/)   && $author_linenum==-1 ){
	    $author_linenum = $i;
	}

	if ( m/\\date\{.*\}/ && $date_linenum==-1){
	    $date_linenum = $i;
	}

	if ( m/\\etxTitle\{.*\}/ || m/\\author\{.*\}/ || m/\\etxAuthor\{.*\}/ || m/\\date\{.*\}/ ){
	    # Find latest point in document where a \maketitle
	    # param is defined. This will be the place to put \begin{document}
	    if ($i>$begin_point){
		$begin_point=$i;
	    }
	}
    }


    ## Fill in missing \author and \data
    my(@title_extras);
    if ($author_linenum==-1){ push @title_extras, '\author{}';}
    if ($date_linenum==-1){ push @title_extras, '\date{}';}


    ## Assemble the various parts of the document
    @data = (@data[0 .. $begin_point], @title_extras, @latex_begin, 
		     @data[$begin_point+1 .. $#data]);

    $opt_verbose && print STDERR ".\n";
}


###################################################################
#
# outputDocument()
#
#   Reads: $filename
#
#   Write the assembled text to the output file
#   
#
sub outputDocument{

    ## Dump latex document to file/stdout	
    if ($filename eq "__StdOut__"){
	for ($i = 0; $i <= $#data; $i++) {print "$data[$i]\n";}
    }elsif (! $filename eq ""){
	open(OUTFILE, ">$filename") || die("Can't write to file: $!");
	for ($i = 0; $i <= $#data; $i++) {print OUTFILE "$data[$i]\n";}
	close(OUTFILE);
    }else{
	die("No output file specified. (This should have been caught earlier though.)");
    }
}


###################################################################
#
# getLatexFrontmatter()
#
#   Reads: $isPublic, $opt_twoup, $opt_numCols, $opt_nofooter
#   Returns: @_ contains the lines in the LaTeX preamble
#
sub getLatexFrontmatter{
    my(@etx_defs, @latex_header,@latex_normal_header,@latex_twocol_header,@latex_twoup_header);

    if($isPublic){
	## For public consumption
	@latex_normal_header=('\documentclass{article}',
			      '\usepackage[pdfpagemode=None,colorlinks,urlcolor=blue,breaklinks=true]{hyperref}',
			      '\usepackage[T1]{fontenc}',
			      '\usepackage{textcomp}',
			      '\usepackage{times}',
			      '\usepackage{relsize}','');

	@latex_twocol_header=('\documentclass[twocolumn]{article}',
			      '\usepackage[pdfpagemode=None,colorlinks,urlcolor=blue,breaklinks=true]{hyperref}',
			      '\usepackage[T1]{fontenc}',
			      '\usepackage{textcomp}',
			      '\usepackage{times}',
			      '\usepackage{relsize}','',
			      '%Refine page layout',
			      '\setlength{\columnsep}{0.43in}',
			      '\setlength{\textheight}{9.4in}',
			      '\setlength{\voffset}{-1.15in}',
			      '\setlength{\textwidth}{7.5in}',
			      '\setlength{\hoffset}{-0.5in}',
			      '\setlength{\footskip}{0.5in}',
			      '');

	@latex_twoup_header=('\documentclass[twocolumn,landscape]{article}',
			     '\usepackage[pdfpagemode=None,breaklinks=true]{hyperref}',
			     '\usepackage[T1]{fontenc}',
			     '\usepackage{textcomp}',
			     '\usepackage{times}',
			     '\usepackage{relsize}','',
			     '%Resize text to fit landscape-oriented page',
			     '\setlength{\columnsep}{0.7in}',
			     '\setlength{\textheight}{6.6in}',
			     '\setlength{\voffset}{-0.9in}',
			     '\setlength{\footskip}{35pt}','' );

	## Mess w/ font shortcut names
	@etx_defs=('%setex.pl-specific font aliases',
		   '\newcommand{\textsfc}[1]{\textsf{\fontseries{m}\selectfont #1}}',
		   '\newcommand{\textsfbc}[1]{\textsf{\fontseries{b}\selectfont #1}}',
		   '\newcommand{\textsb}[1]{\textsf{\fontseries{b}\selectfont #1}}','',
		   '%setex.pl-specific formatting commands',
		   '\newcommand{\etxTitle}[1]{\title{\textsfbc{#1}}}',
		   '\newcommand{\etxAuthor}[1]{\author{\textsc{#1}}}',
		   '\newcommand{\etxRef}[1]{{\smaller \textsfbc{[#1]}}}',
		   '\newcommand{\etxInlineUrl}[2]{\noindent {\textsfc{$<$\href{#1}{#2}$>$}}}',
		   '\newcommand{\etxUrl}[2]{\item \textsfc{$<$\href{#1}{#2}$>$}}',
		   '\newcommand{\etxLink}[3]{\item[#1] \textsfc{$<$\smaller\href{#2}{#3}$>$}}',
		   '\newcommand{\etxUline}[1]{\emph{#1}}',
		   '\newcommand{\etxEmph}[1]{\emph{#1}}',
		   '\newcommand{\etxBold}[1]{\textbf{#1}}','',
		   '\newcommand{\topicpar}[1]{\bigskip\noindent\textsf{\bfseries\larger#1}}',
		   '%setex.pl-specific text environments',
		   '\newenvironment{briefs}{\begin{list}{\textbullet}{\setlength{\topsep}{1.0ex plus0.2ex minus0.1ex}\setlength{\itemsep}{0.2ex plus0.2ex minus0.2ex}\setlength{\parskip}{0.8ex plus0.2ex minus0.1ex}\setlength{\parsep}{0.8ex plus0.2ex minus0.2ex}}}{\end{list}}',
		   '\newenvironment{linkblock}[1][1]{\begin{list}{}{\sffamily\fontseries{mc}\selectfont\setlength{\labelsep}{0em}\setlength{\labelwidth}{1.8em}\setlength{\itemindent}{-0.4em}\setlength{\topsep}{-0.3ex plus0.0ex minus0.1ex}\setlength{\itemsep}{0.0ex}\setlength{\parsep}{0.0ex}}\renewcommand{\makelabel}[1]{\smaller\textsfbc{[##1]}}}{\end{list}\vspace{2ex}}',
		   #'\newenvironment{linkblock}[1][1]{\begin{list}{}{\setlength{\labelsep}{0.8ex}\setlength{\labelwidth}{2ex}\setlength{\topsep}{-0.3ex plus0.0ex minus0.1ex}\setlength{\itemsep}{0.0ex}\setlength{\parsep}{0.0ex}\setlength{\itemindent}{-2.3ex}}\renewcommand{\makelabel}[1]{\smaller\textsfbc{[##1]}}}{\end{list}\vspace{2ex}}',
                   '\newenvironment{urlblock}[1][1]{\begin{list}{}{\sffamily\fontseries{mc}\selectfont\setlength{\labelsep}{0.0em}\setlength{\labelwidth}{0em}\setlength{\topsep}{-0.3ex plus0.0ex minus0.1ex}\setlength{\itemsep}{0.0ex}\setlength{\parsep}{0.0ex}\setlength{\itemindent}{-2em}}}{\end{list}\vspace{2ex}}',
		   #'\newenvironment{urlblock}[1][1]{\begin{list}{}{\setlength{\labelsep}{0.0ex}\setlength{\labelwidth}{0ex}\setlength{\topsep}{-0.3ex plus0.0ex minus0.1ex}\setlength{\itemsep}{0.0ex}\setlength{\parsep}{0.0ex}\setlength{\itemindent}{-5.4ex}}}{\end{list}\vspace{2ex}}','',
		   '%catcode to allow `_\' character so URLs will work',
		   '\catcode`\_=12\relax','');
    }else{
	## My personal settings
	@latex_normal_header=('\documentclass[marginkerning,rich,nonums]{article}',
			      '\usepackage{mystyle}',
			      '');

	@latex_twocol_header=('\documentclass[marginkerning,twocolumn,wide,rich,nonums]{article}',
			      '\usepackage{mystyle}','',
			      '%Refine page layout',
			      '\setlength{\textheight}{9.4in}',
			      '\setlength{\voffset}{-1.15in}',
			      '\setlength{\textwidth}{7.5in}',
			      '\setlength{\hoffset}{-0.5in}',
			      '\setlength{\footskip}{0.5in}',
			      '');

	@latex_twoup_header=('\documentclass[marginkerning,twocolumn,landscape,rich,nonums]{article}',
			     '\usepackage{mystyle}','');

	@etx_defs=('%setex.pl-specific formatting commands',
		   '\newcommand{\etxTitle}[1]{\title{\textsfbc{#1}}}',
		   '\newcommand{\etxAuthor}[1]{\author{\textsc{#1}}}',
		   '\newcommand{\etxRef}[1]{{\textsfbc{[#1]}}}',
		   '\newcommand{\etxInlineUrl}[2]{\noindent {\textsfc{<\href{#1}{#2}>}}}',
		   '\newcommand{\etxUrl}[2]{\item \textsfc{<\href{#1}{#2}>}}',
		   '\newcommand{\etxLink}[3]{\item[#1] \textsfc{<\href{#2}{#3}>}}',
		   '\newcommand{\etxUline}[1]{\emph{#1}}',
		   '\newcommand{\etxEmph}[1]{\emph{#1}}',
		   '\newcommand{\etxBold}[1]{\textbf{#1}}','',
		   '\newcommand{\topicpar}[1]{\bigskip\noindent\textsf{\bfseries\larger#1}\\\\[1ex]}',
		   '%setex.pl-specific text environments',
		   '\newenvironment{briefs}{\begin{list}{\textbullet}{\setlength{\topsep}{1.0ex plus0.2ex minus0.1ex}\setlength{\itemsep}{0.2ex plus0.2ex minus0.2ex}\setlength{\parskip}{0.8ex plus0.2ex minus0.1ex}\setlength{\parsep}{0.8ex plus0.2ex minus0.2ex}}}{\end{list}}',
		   '\newenvironment{linkblock}[1][1]{\begin{list}{}{\sffamily\fontseries{mc}\selectfont\setlength{\labelsep}{0em}\setlength{\labelwidth}{1.8em}\setlength{\itemindent}{-0.4em}\setlength{\topsep}{-0.3ex plus0.0ex minus0.1ex}\setlength{\itemsep}{0.0ex}\setlength{\parsep}{0.0ex}}\renewcommand{\makelabel}[1]{\smaller\textsfbc{[##1]}}}{\end{list}\vspace{1ex}}',
		   '\newenvironment{urlblock}[1][1]{\begin{list}{}{\sffamily\fontseries{mc}\selectfont\setlength{\labelsep}{0.0em}\setlength{\labelwidth}{0em}\setlength{\topsep}{-0.3ex plus0.0ex minus0.1ex}\setlength{\itemsep}{0.0ex}\setlength{\parsep}{0.0ex}\setlength{\itemindent}{-2em}}}{\end{list}\vspace{1ex}}'
		   );

    }


    # Choose proper header based on command line args
    if ($opt_twoup){
	@latex_header = @latex_twoup_header;
    }elsif ($opt_numCols==2){
	@latex_header = @latex_twocol_header;
    }else{
	@latex_header = @latex_normal_header;
    }
    

    # Add our custom hyphenations & version boxes
    if ( 1 ){
	my (@hyphenationCommads);
	@hyphenationCommads=("%Custom hyphenation patterns for words with \`interCapping\'",
			     "\\hyphenation\{@customHyphenations\}",'');
	push @latex_header, @hyphenationCommads;

	my (@versionboxes);
	@versionboxes=('%Define shortcuts for drawing boxed 9s and Xs',
		       '\usepackage{color}',
		       '\setlength{\fboxsep}{0.4ex}',
		       '\setlength{\fboxrule}{1.2pt}',
		       '\newcommand{\ninebox}{{\setlength{\unitlength}{1ex}\begin{picture}(2,2)\thicklines\color[gray]{0.5}\put(-.1,-.1){\framebox(1.645,2){}}\color[rgb]{0.8,0.3,0.1}\put(0.2,0.5){9}\end{picture}}\xspace}',
		       '\newcommand{\tenbox}{{\setlength{\unitlength}{1ex}\begin{picture}(2,2)\thicklines\color[gray]{0.5}\put(-.1,-.1){\framebox(1.645,2){}}\color[rgb]{0.4,0.4,0.6}\put(0.1,0.1){\textsfb{X}}\end{picture}}\xspace}',
		       '\newcommand{\versionNineBox}{\ninebox}',
		       '\newcommand{\versionTenBox}{\tenbox}',
		       '\newcommand{\versionNineAndTenBox}{\ninebox \tenbox}',
 		       '\renewcommand{\versionNineBox}{\raisebox{0.2ex}{{\relsize{-3}\parbox{1.4em}{\color[gray]{0.5}\fbox{\textsfbc{9}}}}}}',
 		       '\renewcommand{\versionTenBox}{\raisebox{0.2ex}{{\relsize{-3}\raisebox{-0.01ex}{\parbox{1.4em}{\color[gray]{0.5}\fbox{\textsfbc{X\parbox[b][1.48ex]{0em}{}}}}}}}}',
 		       '\renewcommand{\versionNineAndTenBox}{\versionNineBox{}\versionTenBox{}}',
		      );
	push @latex_header, @versionboxes;

    }

    # Add footer if requested
    if (! $opt_nofooter){
	my (@fancy_footer);
	@fancy_footer=('%Add a footer with the document title to the bottom of each page',
		       '\usepackage{fancyheadings}',
		       '\pagestyle{fancy}',
		       "\\lfoot{\\textsfc{$title_text}}",
		       '\rfoot{\thepage}',
		       '\setlength{\footrulewidth}{0.4pt}',
		       '\lhead{}\rhead{}\chead{}\cfoot{}',
		       '\setlength{\headrulewidth}{0pt}','');
	push @latex_header, @fancy_footer;
    }

    push @latex_header, @etx_defs;
    return @latex_header;
}



###################################################################
#
# getLatexDocBegin()
#
#   Reads: $isPublic, $opt_nofooter
#   Returns: @_ contains the lines beginning the document body
#
sub getLatexDocBegin{
    my(@latex_begin);

    ## Unchanged fragments
    @latex_begin=('','\begin{document}',
		  '\raggedbottom',
		  '\small',
		  '\maketitle');

    if (! $opt_nofooter){
	# Draw the complicated footer even on the title page
	push @latex_begin, '\thispagestyle{fancy}';
    }

    if (! $isPublic){
	# Don't assume that protcode.tex was included in other people's default configs
	push @latex_begin, '\marginkern{}';
	push @latex_begin, '\tableofcontents';
    }

    return @latex_begin;
}




###################################################################
#
# checkLineBreak()
#
# Calls: getLatexFrontmater
# Args: @_  [0]: The type of section (\section, \subsection, \subsubsection)
#           [1]: The text to be typeset
# Returns: 1 if text has a line break in it (given font for section type)
#          0 if text fits on a single line
#
sub checkLineBreak{
    my ($title_text, $section_tag, @test_doc, $return_value, $i);

    $section_tag= shift;
    $title_text = shift;

    # We don't want to presume that other people have their TeX system set up already,
    # so just count characters instead of actually typesetting the line
    if ($isPublic){ 
	$line_length = length "$title_text";

	if ($opt_twoup || $opt_numCols == 1){ 
	    # Wide column
	    if ($line_length >= 43){
		return 1;
	    }else{
		return 0;
	    }
	}else{ 
	    # Narrow column
	    if ($line_length >= 23){
		return 1;
	    }else{
		return 0;
	    }	    
	}
    }

    push @test_doc, (&getLatexFrontmatter,
		     '\usepackage{ifthen}',
		     '\newlength{\\titleWidth}',
		     '\begin{document}');

    if ($section_tag =~ m/subsubsection/){
	push @test_doc, '\normalfont\normalsize\fontseries{sb}\selectfont';
    }elsif($section_tag =~ m/subsection/){
	push @test_doc, '\normalfont\large\fontseries{sb}\selectfont';
    }elsif($section_tag =~ m/section/){
	push @test_doc, '\normalfont\Large\bfseries';
    }else{
	return 0;
    }

    
    push @test_doc, ("\\settowidth\{\\titleWidth\}\{$title_text\}",
		     '\ifthenelse{\lengthtest{\titleWidth > \columnwidth}}{\typeout{SeTeX_OVERFLOW_ERROR}}{}',
		     "$title_text",
		     '\end{document}');

    $tempdir = `tempfile -d /tmp/`;
    chomp $tempdir;
    system("rm $tempdir && mkdir $tempdir");
    open(MYTEST, ">$tempdir/wtest.tex");
    for ($i=0; $i<=$#test_doc; $i++){
	print MYTEST "$test_doc[$i]\n";
    }
    close(MYTEST);

    open (TESTOUTPUT, "cd $tempdir && pdflatex $tempdir/wtest |");
    while (<TESTOUTPUT>){
	if (m/SeTeX_OVERFLOW_ERROR/g){
	    $return_value=1;
	}
    }
    system("rm -rf $tempdir");

    return $return_value;
}
