diff options
author | Karl Berry <karl@freefriends.org> | 2008-03-11 00:11:19 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2008-03-11 00:11:19 +0000 |
commit | 4fc19da7bf2b940d88ea293c3675e7530a348648 (patch) | |
tree | d7c5df42eba823d1ff37a2d8a5f9d770d958e05a /Master | |
parent | 8017667ed3356ee00be78791ddd88d53283a440a (diff) |
texcount update, plus doc, plus symlink to scripts instead of building
git-svn-id: svn://tug.org/texlive/trunk@6936 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master')
l---------[-rwxr-xr-x] | Master/bin/i386-linux/texcount | 707 | ||||
-rw-r--r-- | Master/texmf-dist/doc/support/texcount/README | 8 | ||||
-rw-r--r-- | Master/texmf-dist/doc/support/texcount/TeXcount.pdf | bin | 0 -> 139639 bytes | |||
-rw-r--r-- | Master/texmf-dist/doc/support/texcount/TeXcount.tex | 252 | ||||
-rw-r--r-- | Master/texmf-dist/scripts/texcount/TeXcount.pl | 866 | ||||
-rwxr-xr-x | Master/tlpkg/bin/ctan2tds | 2 | ||||
-rw-r--r-- | Master/tlpkg/tlpsrc/texcount.tlpsrc | 2 |
7 files changed, 1131 insertions, 706 deletions
diff --git a/Master/bin/i386-linux/texcount b/Master/bin/i386-linux/texcount index 7e9168f3291..dedfa7d2c3e 100755..120000 --- a/Master/bin/i386-linux/texcount +++ b/Master/bin/i386-linux/texcount @@ -1,706 +1 @@ -#! /usr/bin/env perl -$^W = 1; -use strict; -use Term::ANSIColor; -use POSIX qw(locale_h); -use locale; -setlocale(LC_CTYPE,"no_NO"); - -my $versionnumber="1.9"; -my $versiondate="2008 Jan 10"; - - -### How many tokens to exclude from count after macro -# Macro name and first N tokens (or {...}) are -# ignored. Options [...] right after macro name are -# also ignored, as are options [...] between and after -# the excluded tokens. -# -# For macros not specified here, the default value is 0: i.e. -# no tokens are excluded, but [...] options are. Some macros -# have been included here with =>0 for completeness and as a -# reminder. -my %TeXexcl=('\documentclass'=>1,'\documentstyle'=>1,'\usepackage'=>1, '\hyphenation'=>1, - '\pagestyle'=>1,'\thispagestyle'=>1, '\pagenumbering'=>1,'\markboth'=>1, '\markright'=>1, - '\newcommand'=>2,'\renewcommand'=>2,'\newenvironment'=>3, 'renewenvironment'=>3, - '\newfont'=>2,'\newtheorem'=>2,'\bibliographystyle'=>1, '\bibliography'=>1, - '\parbox'=>1, '\marginpar'=>0,'\makebox'=>0, '\raisebox'=>1, '\framebox'=>0, - '\newsavebox'=>1, '\sbox'=>1, '\savebox'=>2, '\usebox'=>1,'\rule'=>2, - '\footnote'=>1,'\label'=>1, '\ref'=>1, '\pageref'=>1, '\bibitem'=>1, - '\cite'=>1, '\citep'=>1, '\citet'=>1, '\citeauthor'=>1, '\citealt'=>1, '\nocite'=>1, - '\eqlabel'=>1, '\eqref'=>1,'\hspace'=>1, '\vspace'=>1, '\addvspace'=>1, - '\input'=>1, '\include'=>1, '\includeonly'=>1,'\includegraphics'=>1, - '\newlength'=>1, '\setlength'=>2, '\addtolength'=>2,'\settodepth'=>2, - '\settoheight'=>2, '\settowidth'=>2,'\newcounter'=>1, '\setcounter'=>2, - '\addtocounter'=>2,'\stepcounter'=>1, '\refstepcounter'=>1, '\usecounter'=>1, - '\alph'=>1, '\arabic'=>1, '\fnsymbol'=>1, '\roman'=>1, '\value'=>1, - '\cline'=>1, '\multicolumn'=>3,'\typeout'=>1, '\typein'=>1, - 'beginlist'=>2, 'beginminipage'=>1, 'begintabular'=>1, - 'beginthebibliography'=>1,'beginlrbox'=>1 ); - -### Macros that should be counted as one or more words -# Macros that represent text may be declared here. The value gives -# the number of words the macro represents. -my %TeXmacroword=('\LaTeX'=>1); - -### Macros for headers -# Macros that identify headers: i.e. following token or -# {...} is counted as header. The =>2 indicates transition to -# state 2 which is used within headers. -my %TeXheader=('\title'=>2,'\part'=>2,'\chapter'=>2, - '\section'=>2,'\subsection'=>2,'\subsubsection'=>2, - '\paragraph'=>2,'\subparagraph'=>2); - -### Macros that are counted within the preamble -# The preamble is the text between \documentclass and \begin{document}. -# Text and macros in the preamble is ignored unless specified here. The -# value is the status (1=text, 2=header, etc.) they should be interpreted as. -# Note that only the first unit (token or {...} block) is counted. -my %TeXpreamble=('\title'=>2); - -### Begin-End groups -# Identified as begin-end groups, and define =>state. The -# states used corresponds to the elements of the count array, and -# are: -# 0: Not included -# 1: Text, word included in text count -# 2: Header, words included in header count -# 3: Float caption, words included in float caption count -# 6: Inline mathematics, words not counted -# 7: Displayed mathematics, words not counted -# -1: Float, not included, but looks for captions -# -# 4 and 5 are used to count number of headers and floats -# and are not used as states. -# -# By default, groups not specified are parsed as floats (-1) and only -# caption text is counted, and counted as float caption rather than -# as words in text. -# -# Note that some environments may only exist within math-mode, and -# therefore need not be defined here: in fact, they should not as it -# is not clear if they will be in inlined or displayed math. -# -my %TeXgroup=('document'=>1,'letter'=>1,'titlepage'=>0, - 'center'=>1,'flushleft'=>1,'flushright'=>1, - 'abstract'=>1,'quote'=>1,'quotation'=>1,'verse'=>1,'minipage'=>1,'verbatim'=>1, - 'description'=>1,'enumerate'=>1,'itemize'=>1,'list'=>1, - 'theorem'=>1,'lemma'=>1,'definition'=>1,'corollary'=>1,'example'=>1, - 'math'=>6,'displaymath'=>7,'equation'=>7,'eqnarray'=>7, - 'figure'=>-1,'float'=>-1,'picture'=>-1,'table'=>-1, - 'tabbing'=>0,'tabular'=>0,'thebibliography'=>0,'lrbox'=>0); - -### In floats: include only specific macros -# Macros used to identify caption text within floats. -my %TeXfloatinc=('\caption'=>1); - -### Count labels -# Labels used to describe the counts -my @countlabel=('Files','Words in text','Words in headers', - 'Words in float captions','Number of headers','Number of floats', - 'Number of math inlines','Number of math displayed'); - -# Styles -my @STYLES=(); -my %STYLE; -$STYLES[0]={}; -$STYLES[1]={'word1'=>'blue','word2'=>'bold blue','word3'=>'blue', - 'grouping'=>'red','mathgroup'=>'magenta','state'=>'cyan underline'}; -$STYLES[2]={%{$STYLES[1]}, - 'word0'=>'yellow','word-1'=>'yellow', - 'command'=>'green','exclgroup'=>'yellow','exclmath'=>'yellow', - 'ignore'=>'cyan'}; -$STYLES[3]={%{$STYLES[2]}, - 'comment'=>'yellow','option'=>'yellow'}; -$STYLES[4]={%{$STYLES[3]}}; - -# Options and states -my $verbose=0; -my $showstates=0; -my $htmlstyle=0; -my $blankline=0; - - -## SHORT HELP AND INFO -if (!defined @ARGV) { - print_version(); - print_syntax(); - print_reference(); - exit; -} elsif ($ARGV[0]=~/^(\-(h|\?|\-help)|\/\?)$/) { - print_help(); - exit; -} elsif ($ARGV[0]=~/^\-\-version$/) { - print_version(); - exit; -} elsif ($ARGV[0]=~/^\-\-licence$/) { - print_licence(); - exit; -} - -# PROCESS ARGUMENTS AND FILES -my $totalcount=new_count(); -foreach my $file (<@ARGV>) { - if ($file eq '-v') {$verbose=1; next;} - if ($file eq '-vv') {$verbose=2; next;} - if ($file eq '-vvv') {$verbose=3; next;} - if ($file eq '-vvvv') {$verbose=3; $showstates=1; next;} - if ($file =~ /^\-showstate/ ){$showstates=1; next;} - if ($file =~ /^\-html/ ) { - $ENV{'ANSI_COLORS_DISABLED'} = 1; - $htmlstyle = $file eq '-htmlcore' ? 1 : 2; - if ($htmlstyle>1) {html_head();} - next; - } - if ($file=~/^\-(nocol|nc$)/) { - $ENV{'ANSI_COLORS_DISABLED'} = 1; - next; - } - %STYLE=%{$STYLES[$verbose]}; - my $tex=TeXfile($file); - if (!defined $tex) { - print "File not found or not readable: ".$file."\n"; - next; - } - parse($tex); - print "\n"; - print_count($tex->{'count'},'FILE: '.$file); - print "\n"; - add_count($totalcount,$tex->{'count'}); -} -if (${$totalcount}[0]>1) { - formatprint('Total','h1'); - print_count($totalcount,'SUM'); -} -if ($htmlstyle>1) { - html_tail(); -} - - - -######### -######### Subroutines -######### - -sub TeXfile { - my $filename=shift @_; - my $file=read_file($filename) || return undef; - return TeXcode($file); -} - -sub TeXcode { - my $texcode=shift @_; - my %TeX=(); - $TeX{'line'}=$texcode; - $TeX{'next'}=undef; - $TeX{'type'}=undef; - $TeX{'style'}=undef; - $TeX{'printstate'}=undef; - $TeX{'eof'}=0; - $TeX{'count'}=new_count(); - $TeX{'count'}[0]++; - return \%TeX; -} - -sub set_style { - my ($tex,$style)=@_; - if (!(($tex->{'style'}) && ($tex->{'style'} eq '-'))) {$tex->{'style'}=$style;} -} - -sub flush_style { - my ($tex,$style)=@_; - set_style($tex,$style); - flush_next($tex); -} - -sub line_return { - my $blank=shift @_; - if ($blank>$blankline) { - if ($htmlstyle) {print "<br>\n";} else {print "\n";} - $blankline++; - } -} - -sub print_style { - my ($text,$style,$state)=@_; - (($verbose>0) && (defined $text) && (defined $style)) || return; - my $colour; - ($colour=$STYLE{$style}) || return; - if (($colour) && !($colour eq '-')) { - if ($htmlstyle) { - print "<span class='".$style."'>".$text."</span>"; - } else { - print Term::ANSIColor::colored($text,$colour); - #print $text; - } - if ($state) { - print_style($state,'state'); - } - $blankline=-1; - } -} - -sub formatprint { - my ($text,$tag,$class)=@_; - my $break=($text=~s/\n$//); - if ($htmlstyle && defined $tag) { - print '<'.$tag; - if ($class) {print " class='".$class."'";} - print '>'.$text.'</'.$tag.'>'; - } else { - print $text; - } - if ($break) {print "\n";} -} - -sub read_file { - my $filename=shift @_; - open(FH,"<".$filename."") || return undef; - if ($verbose) { - #line_return(1); - formatprint("File: ".$filename."\n",'h2'); - $blankline=0; - } - my @text=(); - while (my $line=<FH>) { - push @text,$line; - } - close(FH); - return join('',@text); -} - -sub next_token { - my $tex=shift @_; - my ($next,$type); - if (defined $tex->{'next'}) {print_style($tex->{'next'}.' ',$tex->{'style'});} - $tex->{'style'}=undef; - while (defined ($next=get_next_token($tex))) { - $type=$tex->{'type'}; - if ($type==0) { - print_style($next,'comment'); - } elsif ($type==9) { - if ($verbose) {line_return(1);} - } else { - return $next; - } - } - return $next; -} - -sub flush_next { - my $tex=shift @_; - if (defined $tex->{'next'}) { - print_style($tex->{'next'}.' ',$tex->{'style'},$tex->{'printstate'}); - } - $tex->{'printstate'}=undef; - $tex->{'style'}='-'; -} - -sub get_next_token { - my $tex=shift @_; - my $next; - (defined ($next=get_token($tex,'\%[^\n]*',0))) && return $next; - (defined ($next=get_token($tex,'\n',9))) && return $next; - (defined ($next=get_token($tex,'\\\\[\{\}]',1))) && return $next; - (defined ($next=get_token($tex,'\w+(\.\w+)+\.',1))) && return $next; - (defined ($next=get_token($tex,'\w+([\-\']\w+)*',1))) && return $next; - (defined ($next=get_token($tex,'[\"\'\`:\.,\(\)\[\]!\+\-\*=/\^\_\@\<\>\~\#\&]',2))) && return $next; - (defined ($next=get_token($tex,'\\\\([a-zA-Z_]+|[^a-zA-Z_])',3))) && return $next; - (defined ($next=get_token($tex,'[\{\}]',4))) && return $next; - (defined ($next=get_token($tex,'[\[\]]',5))) && return $next; - (defined ($next=get_token($tex,'\$\$',6))) && return $next; - (defined ($next=get_token($tex,'\$',6))) && return $next; - (defined ($next=get_token($tex,'.',999))) && return $next; - (defined ($next=get_token($tex,'[^\s]+',999))) && return $next; - $tex->{'eof'}=1; - return undef; -} - -sub get_token { - my ($tex,$regexp,$type)=@_; - if (!defined $regexp) {print "ERROR in get_token: undefined regex.";} - if (!defined $tex->{'line'}) {print "ERROR in get_token: undefined tex-line. ".$tex->{'next'}."\n";} - if ( $tex->{'line'} =~ s/^($regexp)[ \t\r\f]*// ) { - $tex->{'next'}=$1; - $tex->{'type'}=$type; - return $1; - } - return undef; -} - -sub new_count { - my @count=(0,0,0,0,0,0,0,0); - # files, text words, header words, float words, - # headers, floats, math-inline, math-display; - return \@count; -} - -sub count_word { - my ($count,$type,$word,$style,$verb)=@_; - ($word) || ($word=""); - ($style) || ($style=0); - ($verb) || ($verb=0); - if ($type>0) {${$count}[$type]++;} - if ($verb >= $verbose) { - } -} - -sub print_count { - my ($count,$header)=@_; - if ($htmlstyle) {print "<dl class='count'>\n";} - if (defined $header) { - formatprint($header."\n",'dt','header'); - } - for (my $i=1;$i<8;$i++) { - formatprint($countlabel[$i].': ','dt'); - formatprint(${$count}[$i]."\n",'dd'); - } - if ($htmlstyle) {print "</dl>\n";} -} - -sub add_count { - my ($a,$b)=@_; - for (my $i=0;$i<8;$i++) { - ${$a}[$i]+=${$b}[$i]; - } -} - -sub parse { - my ($tex)=@_; - if ($htmlstyle && $verbose) {print "<p class=parse>\n";} - while (!($tex->{'eof'})) { - parse_unit($tex,1); - } - if ($htmlstyle && $verbose) {print "</p>\n";} -} - -sub parse_unit { - # Status: - # 0 = exclude - # 1 = text - # 2 = header text - # 3 = float text - # -1 = float (exclude) - # -9 = preamble (between \documentclass and \begin{document}) - my ($tex,$status,$end)=@_; - my $count=$tex->{'count'}; - my $substat; - if ($showstates) { - if (defined $end) { - $tex->{'printstate'}=':'.$status.':'.$end.':'; - } else { - $tex->{'printstate'}=':'.$status.':'; - } - flush_next($tex); - } - while (defined (my $next=next_token($tex))) { - # parse next token; or tokens until match with $end - set_style($tex,"ignore"); - if (($end) && ($end eq $next)) { - # end of unit - return; - } elsif (!defined $next) { - exit "ERROR: End of file while waiting for ".$end."\n"; - } - if ($tex->{'type'}==1) { - # word - if ($status>0) { - ${$count}[$status]++; - set_style($tex,'word'.$status); - } - } elsif ($tex->{'type'}==9) { - #print "\n"; - } elsif ($next eq '{') { - # {...} - parse_unit($tex,$status,'}'); - } elsif ($tex->{'type'}==3) { - # macro call - set_style($tex,'command'); - if ($next eq '\documentclass') { - # starts preamble - gobble_option($tex); - gobble_macro_parms($tex,1); - while (!($tex->{'eof'})) { - parse_unit($tex,-9); - } - } elsif ($next eq '\begin') { - # \begin...\end - if ($status==-9 && $tex->{'line'}=~/^\{document\}/) { - $status=1; - } - my $localstyle=$status>0 ? 'grouping' : 'exclgroup'; - flush_style($tex,$localstyle); - gobble_option($tex); - if ($tex->{'line'} =~ s/^\{(\w+)\*?\}[ \t\r\f]*//) { - # gobble group type - print_style('{'.$1.'}',$localstyle); - $next='begin'.$1; - if (defined (my $i=$TeXexcl{$next})) { - gobble_macro_parms($tex,$i); - } - } else { - print "\nWarning: BEGIN group without type.\n"; - } - # find group status (or leave unchanged) - defined ($substat=$TeXgroup{$1}) || ($substat=$status); - if ($status<=0 && $status<$substat) {$substat=$status;} - if (($status>0) && ($substat==-1)) { - # Count float - ${$count}[5]++; - } - if ($status>0 and $substat>3) { - # count item, exclude contents - ${$count}[$substat]++; - $substat=0; - } - parse_unit($tex,$substat,'\end'); - if ($tex->{'line'} =~ s/^\{(\w+)\}[ \t\r\f]*//) { - # gobble group type - flush_style($tex,$localstyle); - print_style('{'.$1.'}',$localstyle); - } else { - print "\nWarning: END group without type.\n"; - } - } elsif ($next eq '\(') { - # math inline - my $localstyle=$status>0 ? 'mathgroup' : 'exclmath'; - if ($status>0) {${$count}[6]++;} - set_style($tex,$localstyle); - parse_unit($tex,0,'\)'); - set_style($tex,$localstyle); - } elsif ($next eq '\[') { - # math display - my $localstyle=$status>0 ? 'mathgroup' : 'exclmath'; - if ($status>0) {${$count}[7]++;} - set_style($tex,$localstyle); - parse_unit($tex,0,'\]'); - set_style($tex,$localstyle); - } elsif (defined (my $i=$TeXexcl{$next})) { - # macro: exclude options - gobble_macro_parms($tex,$i); - } elsif (defined ($i=$TeXmacroword{$next})) { - # count macro as word (or a given number of words) - if ($status>0) { - ${$count}[$status]+=$i; - set_style($tex,'word'.$status); - } - } elsif ($next eq '\def') { - # ignore \def... - $tex->{'line'} =~ s/^([^\{]*)\{/\{/; - flush_next($tex); - print_style($1.' ','ignore'); - parse_unit($tex,0); - } elsif ($next =~ /^\\[^\w\_]/) { - } else { - gobble_option($tex); - } - if (($status>0 || ($status==-9 && defined $TeXpreamble{$next})) && ($substat=$TeXheader{$next})) { - # headers - ${$count}[4]++; - gobble_macro_modifier($tex); - gobble_option($tex); - parse_unit($tex,$substat); - } elsif ($status==-9 && defined ($substat=$TeXpreamble{$next})) { - parse_unit($tex,$substat); - } - if (($status==-1) && ($substat=$TeXfloatinc{$next})) { - # text included from float - parse_unit($tex,3); - } - } elsif ($next eq '$') { - # math inline - my $localstyle=$status>0 ? 'mathgroup' : 'exclmath'; - if ($status>0) {${$count}[6]++;} - set_style($tex,$localstyle); - parse_unit($tex,0,$next); - set_style($tex,$localstyle); - } elsif ($next eq '$$') { - # math display - my $localstyle=$status>0 ? 'mathgroup' : 'exclmath'; - if ($status>0) {${$count}[7]++;} - set_style($tex,$localstyle); - parse_unit($tex,0,$next); - set_style($tex,$localstyle); - } - if (!defined $end) {return;} - } -} - -sub gobble_option { - my $tex=shift @_; - flush_next($tex); - if ($tex->{'line'} =~ s/^(\[(\w|[,\-\s\~\.\:\;\+\?\*\_\=])*\])//) { - print_style($1,'option'); - return $1; - } - return undef; -} - -sub gobble_options { - while (gobble_option(@_)) {} -} - -sub gobble_macro_modifier { - my $tex=shift @_; - flush_next($tex); - if ($tex->{'line'} =~ s/^\*//) { - print_style($1,'option'); - return $1; - } - return undef; -} - -sub gobble_macro_parms { - my ($tex,$i)=@_; - if ($i>0) {gobble_macro_modifier($tex);} - gobble_options($tex); - for (;$i-->0;) { - parse_unit($tex,0); - gobble_options($tex); - } -} - - -### HTML context - -sub html_head { - print ' -<html> -<head> -<style> -<!-- -.parse {font-size: 80%; background: #eef;} -.word1,.word2,.word3 {color: #009;} -.word2 {font-weight: 700;} -.word3 {font-style: italic;} -.word-1 {color: #66c;} -.command {color: #c00;} -.option {color: #cc0;} -.grouping {color: #900; font-weight: 700;} -.mathgroup {color: #090;} -.exclmath {color: #6c6;} -.ignore {color: #999;} -.comment {color: #999; font-style: italic;} -.state {color: #990; font-size: 70%;} -dl.count {width: 100%; background: #cfc; color: 009;} -dl.count dt.header {font-weight: 700; font-style: italic; float: none;} -dl.count dt {clear: both; float: left;} -dl.count dd {font-weight: 700;} -.warning {color: #c00; font-weight: 700;} -.parse, .count {border: solid 1px #999; margin: 0pt; padding: 4pt;} ---> -</style> -</head> -<body> -<h1>LaTeX word count</h1> -'; -} - -sub html_tail { - print '</body></html>'; -} - - -### HELP AND INFO - -sub print_version { - print "TeXcount version ".$versionnumber.", ".$versiondate.'.'; -} - -sub print_syntax { - print ' -Syntax: TeXcount.pl [options] files - -Options: - -v Verbose: print parsed words, mark formulae - -vv More verbose: also print ignored text - -vvv Even more verbose: include comments and options - -showstate Show internal states (with verbose) - -nc, -nocol No colours (colours require ANSI) - -html Output in HTML format - -htmlcore Only HTML body contents - -h, -?, --help, /? Help - --version Print version number - --licence Licence information -'; -} - -sub print_help { - print ' -*************************************************************** -* TeXcount.pl '.$versionnumber.', '.$versiondate.' -* - -Count words in TeX and LaTeX files, ignoring macros, tables, -formulae, etc. -'; - print_syntax(); - print ' -The script counts words as either words in the text, words in -headers/titles or words in floats (figure/table captions). -Macro options (i.e. \marco[...]) are ignored; macro parameters -(i.e. \macro{...}) are counted or ignored depending on the -macro, but by default counted. Begin-end groups are by default -ignored and treated as \'floats\', though some (e.g. center) are -counted. - -Unless -nocol (or -nc) has been specified, the output will be -colour coded. Counted text is coloured blue with headers are in -bold and in HTML output caption text is italicised. - -Mathematical formulae are not counted as words, but are instead -counted separately with separate counts for inlined formulae -and displayed formulae. Similarly, the number of headers and -the number of \'floats\' are counted. Note that \'float\' is used -here to describe anything defined in a begin-end group unless -explicitly recognized as text or mathematics. - -The verbose options (-v, -vv, -vvv, showstate) produces output -indicating how the text has been interpreted. Check this to -ensure that words in the text has been interpreted as such, -whereas mathematical formulae and text/non-text in begin-end -groups have been correctly interpreted. - -Unix hint: Use \'less -r\' instead of just \'less\' to view output: -the \'-r\' option makes less treat text formating codes properly. - -Windows hint: If your Windows interprets ANSI colour codes, lucky -you! Otherwise, use the -nocol (or -nc) option with the verbose -options or the output will be riddled with colour codes. Instead, -you can use -html to produce HTML code, write this to file and -view with your favourite browser. -'; - print_reference(); -} - -sub print_reference { - print ' -The TeXcount script is copyright of Einar Andreas Rødland (2008) -and published under the LaTeX Project Public Licence. - -For more information about the script, e.g. news, updates, help, -usage tips, known issues and short-comings, go to - http://folk.uio.no/einarro/Comp/texwordcount.html -or go to - http://folk.uio.no/einarro/Services/texcount.html -to access the script as a web service. Feedback such as problems -or errors can be reported to einarro@ifi.uio.no. -'; -} - -sub print_licence { - print 'TeXcount version '.$versionnumber.' - -Copyright 2008 Einar Andreas Rødland - -The TeXcount script is published under the LaTeX Project Public -Licence (LPPL) - http://www.latex-project.org/lppl.txt -which grants you, the user, the right to use, modify and distribute -the script. However, if the script is modified, you must change its -name or use other technical means to avoid confusion. - -The script has LPPL status "maintained" with Einar Andreas -Rødland being the current maintainer. -'; -} +../../texmf-dist/scripts/texcount/TeXcount.pl
\ No newline at end of file diff --git a/Master/texmf-dist/doc/support/texcount/README b/Master/texmf-dist/doc/support/texcount/README new file mode 100644 index 00000000000..fb8d53764fc --- /dev/null +++ b/Master/texmf-dist/doc/support/texcount/README @@ -0,0 +1,8 @@ +TeXcount.pl is a Perl script that counts the number of words in the +text of LaTeX files. It has rules for handling most of the common +macros and provides colour coded output indicating which parts have +been counted. Go to + http://folk.uio.no/einarro/Comp/texwordcount.html +for more information or to access the script online as a web service. + +The package is distributed under the LaTeX Project Public License. diff --git a/Master/texmf-dist/doc/support/texcount/TeXcount.pdf b/Master/texmf-dist/doc/support/texcount/TeXcount.pdf Binary files differnew file mode 100644 index 00000000000..c4dad88f01e --- /dev/null +++ b/Master/texmf-dist/doc/support/texcount/TeXcount.pdf diff --git a/Master/texmf-dist/doc/support/texcount/TeXcount.tex b/Master/texmf-dist/doc/support/texcount/TeXcount.tex new file mode 100644 index 00000000000..a460d8be924 --- /dev/null +++ b/Master/texmf-dist/doc/support/texcount/TeXcount.tex @@ -0,0 +1,252 @@ +\documentclass{article} +\usepackage[latin1]{inputenc} +\usepackage[T1]{fontenc} +\usepackage{a4wide} +\usepackage{times} + +\include{macros} + +%\parindent=0pt\parskip=8pt + +%TC:macroword \TeXcount 1 +\newcommand\TeXcount{{\TeX}count} + +\newcommand\code[1]{\texttt{\small#1}} +\newcommand\bigcode[1]{\texttt{#1}} +\newcommand\codeline[1]{\begin{quote}\code{#1}\end{quote}} +\newcommand\bs[1]{$\backslash$#1} +\newcommand\URL[1]{\texttt{\small #1}} + +%TC:macro NB 1 +\newcommand\NB[1]{\marginpar{\textsf{\tiny#1}}} + +\title{\TeXcount\footnote{Copyright 2008 Einar Andreas Rødland, distributed +under the \LaTeX{} Project Public Licence (LPPL).}\\ +Perl script for counting words in \LaTeX{} documents} +\author{Einar Andreas Rødland} + +\begin{document} + +\maketitle + +{\abstract% +\TeXcount{} is a Perl script for counting words in \LaTeX{} documents. It recognizes most of the common macros, and has rules for which parameters to count and not to count; the main text is counted separately from the words in headers and in captions of figures and tables. Finally, it produces a colour coded version of the parsed document, either as a text document or as HTML to be viewed in a browser, indicating which parts of the document have been included in the count. +% +} + +\tableofcontents + + +\section{What does \TeXcount{} do?} + +\TeXcount{} is a Perl script made for counting the words in a \LaTeX{} document. Since \LaTeX{} documents are formated using lots of macro instructions and often contain both mathematical formulae and floating tables and figures, this is no trivial task. + +Simple solutions to counting the words consists of detexing the documents, which often merely consisty of ignoring the \TeX{} and \LaTeX{} instructions. This is a bad solution since it will usually result in over-estimating the number of words as mathematical formulae, citations, labels and references are counted. + +A perfect solution, if such exists, needs to take into account how \LaTeX{} interprets each macro instruction. The simplest approach to taking this into account consisty of making the count based on the typeset document, but this too tends to over-estimate the word count as mathematical formulae, table contents and even page numbers may get counted. + +A simple but robust approach, which is the one I have taken with \TeXcount{}, is to parse the \LaTeX{} document using simple rules for how to interpret the different \TeX{} and \LaTeX{} instructions. Rules for most of the common macro instructions are included in \TeXcount{}, and it is possible to specify new rules in the \TeX{} document. + +The primary focus of \TeXcount{} is to: +\begin{itemize} + +\item provide an accurate count of the number of words in \LaTeX documents; + +\item exclude or count separately document elements which are not part of the main text such as figure captions; + +\item enable the user to, with relative ease, check how \TeXcount{} has parsed the document and which elements have been counted and which have not. + +\end{itemize} +The last point on this list is one of the most important. Having an accurate word count is of little value unless you know that it is accurate; conversly, trusting an inaccurate word count can be potentially harmful, e.g. if you are submitting a paper or a report which has a strict word limit. + +\TeXcount{} handles complete \LaTeX{} documents, i.e. that start with \code{\bs{documentclass}} and has the text between \code{\bs{begin}\{document\}} and \code{\bs{end}\{document\}}, as well as partial documents made to be included in another \LaTeX{} document. Automatic inclusion of included documents is possible, but is by default turned off. + +Since \TeXcount{} relies on a relatively simple rules for how to handle the different macros and only performs limited checks on the validity of the \LaTeX{} document, it is your responsibility to make sure the document actually typesets in \LaTeX{} before running it through \TeXcount{}. Also, \TeXcount{} relies on handling macros taking parameters enclosed with \{ and \}, and on ignoring options enclosed by [ and ]: macros with significantly different syntax such as \code{\bs{vskip}} cannot be handled. + +\subsection{What \TeXcount{} does not do} + +While an ideal solution should be able to expand the macro instructions, thus being able to handle new macros, that would at it's worst require reimplementing much of \TeX{}, something that is clearly unrealistic. While some limited methods for handling new macros based on definitions in the file might be done, I have opted for a simpler solution: to define rules stating which paramters to count and which to ignore. Thus, \TeXcount{} cannot handle macros that may take a variable number of parameters. Nor can it handle macros that takes parameters on forms other than \code{\{parameter\}}. + +In general, while \TeXcount{} does the parsing in some detail, it does not do it exacly as \TeX{} does it. In some respects there may therefore be critical difference: e.g. while \TeX{} reads one character at a time, \TeXcount{} reads one word at a time, so while \LaTeX{} would interpret \code{\bs{cite} me} as \code{\bs{}cite\{m\}e}, \TeXcount{} would interpret it like \code{\bs{cite}\{me\}}. + +Another issue is that, since \TeXcount{} does not know how to expand macros, it cannot handle macros like \code{\bs{maketitle}}. Instead, it will count \code{\bs{title}\{title text\}} when it occurs. + +For users of languages containing letters other than A to Z, there may be an additional challenge. The script relies on Perl to recognize words as sequence of letters, and must therefore know which characters are considered to be letters. The Perl locale may be changed (as of now this is hard-coded!) to accommodate this, but this does not work for special letters encoded using \TeX{} or \LaTeX{} macros or codes: e.g. \code{\bs{aa}} and \code{\bs{"}a} will not be understood to be letters in the present implementation, whereas \code{\aa} and \code{\"a} will. + + +\section{Syntax and options} + +\subsection{Running \TeXcount{}} + +The command to run \TeXcount{} may vary slightly depending on the operating system and the local settings. + +Under Linux/Unix, it should be sufficient to run \code{texcount.pl} provided it is in the PATH and has been made executable (\code{chmod u+x texcount.pl}). The first line of the file, the one starting with \code{\#!}, tells Linux/Unix which command to use to run the script. This may either direct to the \code{perl} command giving the full path to it (use \code{which perl} if you need to find out where \code{perl} is located) or, as is done in more recent versions of \TeXcount{}, contain the line \code{\#!/usr/bin/env perl} which should find the correct location for \code{perl} (provided the program \code{/usr/bin/env} is available). + +Under Windows, running \code{texcount} from the command line suffices if \code{texcount.pl} is in the path and pl-files are defined to run as Perl scripts. + +Alternatively, if the above methods do not work, you may have to execute it more exclicitly under Perl using \code{perl texcount.pl}. You then need to have the \code{perl} executable file in the path or give the explicit path. + +I will simply write \code{texcount} in this manual for the code to execute the script. Then, the syntax becomes +\codeline{texcount [options] [files]} +where the options may be amongst the following: +\begin{description}\def\option[#1]{\item[\quad\code{#1}]} +\option[-v]Verbose (same as -v3) +\option[-v0]No details (default) +\option[-v1]Prints counted text, marks formulae +\option[-v2]Also prints ignored text +\option[-v3]Also includes comments and options +\option[-v4]Same as \code{-v3 -showstate} +\option[-showstate]Show internal states (with verbose) +\option[-brief]Only prints a one line summary of the counts +\option[-nc, -nocol]No colours (colours require ANSI) +\option[-inc]Include tex files included in the document +\option[-noinc]Do not include included tex files (default) +\option[-html]Output in HTML format +\option[-htmlcore]Only HTML body contents +\option[-h, -?, --help, /?]Help +\option[--version]Print version number +\option[--license]License information +\end{description} + +If more than one file is given, \TeXcount{} will perform the count on each of them printing the results for each, then print the total sum at the end. + +\subsection{Details} + +By selecting one of the \code{-v} options, you can choose how much detail is printed. This is useful for checking what \TeXcount{} counts. + +The output is colour coded with counted text coloured blue, other colours for other contexts. The colour coding is made using ANSI colour codes. These should work when printed directly to Linux xterm window, but need not work if piped through \code{more} or \code{less}: with \code{less} you need to use the option \code{-r} for the colours to be shown correcly. Under Windows or other operating systems, the ANSI colour codes cannot be expected to work, in which case the option \code{-nocol} (\code{-nc}) may be used to turn off colour coding; instead I recommend using HTML output which can be viewed in a browser. + +To print the details encoded as HTML code, use the option \code{-html}; alternatively, with \code{-htmlcore} only the HTML body is printed. On Windows, I suggest using the options \code{-html -v} to get full detail, save this to a HTML file, e.g. using +\codeline{texcount -html -v texfile.tex > details.html} +and then view the details.html file in a browser. + +\subsection{Parsing options} + +If the option \code{-inc} is used, \TeXcount{} will automatically count documents that are included (using \code{\bs{input}} or \code{\bs{include}}. As when giving a list of files to count, it will print the sum per file and a total sum at the end. + +The default is \code{-noinc} indicating that included documents are not counted. + + +\section{What \TeXcount{} counts} + +The primary role is to count the words. It is not entirely clear what should be considered words, so I have had to make some decisions. A sequence of letters is certainly a word. I also count acronyms like `e.g.', dashed words like `over-all', and `it's' as one word. I have decided also to count numbers as words unless they are placed in a math environment. + +Mathematical formulae are not counted as words. Instead, \TeXcount{} counts the number of inline formulae (\code{\$maths\$}) and displayed formulae separately. + +Text in headers (\code{\bs{title}}, \code{\bs{section}}, etc.) are counted separately: it counts the number of headers as well as the number of words in headers. + +Floating environments (or potentially floating environments) such as tables and figures are not counted as text, even if the cells of a table may containt text. However, if they have captions, these will be counted separately much like headers were. By default, begin--end environments do not modify the parsing state: i.e. environments within the text are counted as text, etc. Rules for the most common environments, at least those that require non-default treatment, should be predefined, but you may have to add more rules if you use environments defined in packages or by yourself. + +Some macros are words by themselves: e.g. \code{\bs{LaTeX}}. These are counted as words, but you cannot expect \TeXcount{} to count something like \code{\bs{LaTeX}-word} or \code{\bs{\{}\bs{TeX}\bs{\}}count} as one word, although the above explanation inicates that it should: \TeXcount{} will in both cases evaluate the macro and the following text separately and thus count them as separate entities. + + +\section{Macro handling rules} + +A very few rules are hard-coded, e.g. that text between \code{\bs{documentclass}} and \code{\bs{begin}\{document\}} is the preamble of the \LaTeX{} document which should be default not be included in the count. However, most of the rules consists fall into a few general categories: + +\begin{description} + +\item[macro]In its simplest form, this type of rule just tells how many parameters to ignore following the macro. More generally, one may specify the number of parameters a macro takes and how each of these should be handled. Options enclosed in \code{[]} before, between and after parameters are also ignored; this also applies to macros not specified here, so for a macro with no rule, immediately following \code{[]}-options will be ignored. (This type of rule was called an exclude rule in older versions of +\TeXcount{}, the reason being that the rule originally only gave the number of +parameters to ignore following a given macro.) + +\item[header]Macros that are specified to be counted as headers. In fact, this only indicates that the macro should cause the number of headers to be increased by one; a rule is added to the macro-rule to count the following parameter as header text. + +\item[group]For groups enclosed by \code{\bs{begin}\{\textit{name}\}} and \code{\bs{end}\{\textit{name}\}}, there are rules specifying how the contents should be interpreted. A macro rule is added for \code{begin\textit{name}} (without the backslash!) which is \TeXcount{}'s internal representation of \code{\bs{begin}\{\textit{name}\}}. + +\item[macroword]This type of rule indicates that the macro itself represents one or more words. Initially, \code{\bs{LaTeX}} and \code{\bs{TeX}} are defined with values 1 indicating that each represents one word. + +\item[preamble]A few macros should be counted even if they are in the preamble. In particular, \code{\bs{title}\{title text\}} is counted as a header assuming it will later be used to produce a title. + +\item[float inclusion]Within floats (begin-end groups defined with parsing status $-1$) there may be texts that should still be counted: in particular captions. These are specified with the float inclusion rule. + +\item[file include]If \code{-inc} is specified, included files will also be parsed and the total presented at the end. Initially, \code{\bs{input}} and \code{\bs{include}} trigger file inclusion, but more macros may be added here. + +\end{description} + +A macro parameter is normally something on the form \code{\{something\}}; more generally it may be anything \TeXcount{} parses as a single unit (or token), e.g. a macro, but since \TeXcount{} parses word by word rather than character by character this may not always be correct if parameters are not \code{\{\}}-enclosed or macros. + +\subsection{Cautions!} + +Since the rules are of a relatively general nature, macros that have a great deal of flexibility are hard to deal with. In particular this applies to macros with a variable number of parameters or where the handling of the parameters are not constant. + +Also, \code{[]}-options following macros and macro parameters are always ignored, and \TeXcount{} gives no flexibility in over-ruling that. Since options are, by definition of the term, meant to be optional, extending \TeXcount{} to handle them would require extensive reprogramming as well as require much more detailed macro definition rules than what is now possible. + +More critically, since \TeXcount{} does not really know which macros take options or not, just assumes that options should never be included, there is some risk of misinterpreting as an option something that is not: e.g. \code{\bs{bf}[text]}. This is not likely to be a frequent problem. However, if something like \code{\bs{bf}[a lot of text]} gets ignored because it is considered an option, it can influence the word count substantially. I have therefore been somewhat restrictive with what (and how much) can go into an option. + +More advanced macros are not supported and can potentially confuse \TeXcount{}. In partcular, if you define macros that contain unbalanced begin--end groups, this will cause problems as \TeXcount{} needs to keep track of these to know where different groups start and end. + + +\section{Adding your own rules} + +Adding your own macro handling rules is relatively simple. Although editing the script is possible, and not too difficult, this has the disadvantage that the modifications will be lost if updating to a new version of \TeXcount. A better and more flexible solution is to include instructions to \TeXcount{} in the \LaTeX{} documents, alternatively to make a definition file in which new macro handling rules are defined. + +Comment lines on the form +\codeline{\%TC:\textit{instruction name parameters}} +encountered in the parsed document are used to add macro handling rules. The instruction states what kind of rule, the name specifies the macro or begin-end group, and parameters specify the rule. Be aware that these are not syntax checked and may produce either Perl errors or incorrect results if entered incorrectly. + +Macro names should be entered with their full name starting with backslash. Internally, begin-end groups are represented using macro names \code{begin\textit{name}} without backslash, but rules for begin-end groups are specified through a separate TC-instruction. + +Note that macro handling rules are added successively throughout the session: i.e. if more files are parsed, handling rules from previously parsed files still apply. This has advantages as well as disadvantages. If you give a list of files with the rules specified in the first file, these rules will be applied to all the documents. However, if you use the \code{-inc} option, included files will be parsed only after \TeXcount{} has finished parsing the file in which they are included, so any rules specified in these will not apply to the initial document. + +The instructions may be one of the following: +% +\begin{description}\def\option[#1]{\item[\bigcode{#1}]} + +\option[macro]Takes one parameter which is either an integer or a \code{[]}-enclosed array of integers (e.g. \code{[0,1,0]}). An integer value $n$ indicates that the $n$ first parameters to the macro should be ignored. An array of length $n$ indicates that the first $n$ parameters should be handled, and the numbers of the array specifies the parsing status (see below) with which they should be parsed. Giving the number $n$ as parameter is equivalent to giving an array of $n$ zeroes (\code{[0,\ldots,0]}) as zero is the parsing status for ignoring text. + +\option[header]This is specified much as the macro rule. The added effect is that the header counter is increase by 1. Note, however, that you should specify a parameter array, otherwise none of the parameters will be parsed as header text. The parser status for header text is 2, so a standard header macro that uses the first parameter as header should be given the parameter \code{[2]}. + +\option[group]This specifies a begin-end group with the given name (no backslash). It takes two further parameters. The first parameter speficies the macro rule following \code{\bs{begin}\{\textit{name}\}}. The second parameter specifies the parser status with which the contents should be parsed: e.g. $1$ for text (default rule), $0$ to ignore, $-1$ to specify a float (table, group, etc.) for which text should not be counted but captions should, $6$ and $7$ for inline or displated math. + +\option[floatinclude]This may be used to specify macros which should be counted when within float groups. The handling rules are spefified as for \code{macro}, but like with \code{header} an array parameter should be provided and parameters that should be counted as text in floats should be specified by parsing status 3. Thus, a macro that takes one parameter which should be counted as float/caption text should take the parameter \code{[3]}. + +\option[preambleinclude]The preamble, i.e. text between \code{\bs{documentclass}} and \code{\bs{begin}\{document\}}, if the document contains one, should generally not be included in the word count. However, there may be definitions, e.g. \code{\bs{title}\{title text\}}, that should still be counted. In order to be able to include these special cases, there is a preambleinclude rule in which one may speficy handling rules for macros within the preamble. Again, the rule is speficied like the \code{macro} rules, but since the default is to ignore text the only relevant rules to be specified require an array. + +\option[fileinclude]By default, \TeXcount{} does not automatically add files included in the document using \code{\bs{input}} or \code{\bs{include}}, but inclusion may be turned on by using the option \code{-inc}. If other macros are used to include files, these may be specifed by adding fileinclude rules for these macros. The specification takes one parameter: 1 if filetype \code{.tex} should be added if the file is without a filetype, 0 if it should not. + +\end{description} + +The parser status is used to dictat how each parameter should be parsed. E.g. if a macro has its parameter set defined by \code{[1,0,1]}, it means the first and third parameters are counted as text words (parser status $1$) whereas the second is ignored (parser status $0$). Another case is \code{\bs{renewcommand}} which is defined as \code{[-3,-2]}: the first parameter is to be read without interpreting the contents (which is going to be a macro name whose macro handling rules should not be applied here), and the second parameter should be ignored without requiring that begin--end groups be balanced. The different parsing states are: +% +\begin{description}\def\option[#1]{\item[\quad\textbf{#1}]} +\option[$0$:]ignore text, i.e. do not count, but will still parse the code; +\option[$1$:]count as text (i.e. count words); +\option[$2$:]count as header text; +\option[$3$:]count as float/caption text; +\option[$-1$:]float, ignore text but look for \code{floatinclude} macros; +\option[$-2$:]stronger ignore which ignore begin--end groups, e.g. to use in macro definitions where begin--end groups need not be balanced; +\option[$-3$:]even stronger ignore, handles macros as isolated tokens without handling their parameters, to use with macro definitions like \code{\bs{newcommand}} and \code{\bs{def}}; +\option[$-9$:]preamble, ignore text but look for \code{preambleinclude} macros. +\end{description} + +Here are some examples together with corresponding macro definitions: +% +\codeline{% +\%TC:macroword \bs{TeXcount} 1\\ +\bs{newcommand}\bs{TeXcount}\{\{\bs{TeX}\}count\} +\\[8pt] +\%TC:macro \bs{NB} 1\\ +\bs{newcommand}\bs{NB}[1]\{\bs{marginpar}\{\#1\}\} +\\[8pt] +\%TC:header \bs{newsection} [2,0]\\ +\bs{newcommand}\bs{newsection}[2]\{\bs{section}\{\#1\}\bs{label}\{sec:\#2\}\} +\\[8pt] +\%TC:group theorem 0 1\\ +\bs{newtheorem}\{theorem\}\{Theorem\} +} +% +The predefined rules can easily be read off the script file: they are hash maps defined at the beginning of the script with names \code{TeXmacro}, \code{TeXheader}, etc. + + +\section{License} + +The \TeXcount{} package---script and accompanying documents---is distributed +under the \LaTeX{} Project Public License (LPPL) +\codeline{http://www.latex-project.org/lppl.txt} +which grants you, the user, the right to use, modify and distribute +the script. However, if the script is modified, you must change its +name or use other technical means to avoid confusion with the original script. + + +\end{document} diff --git a/Master/texmf-dist/scripts/texcount/TeXcount.pl b/Master/texmf-dist/scripts/texcount/TeXcount.pl new file mode 100644 index 00000000000..1ed70fc8a56 --- /dev/null +++ b/Master/texmf-dist/scripts/texcount/TeXcount.pl @@ -0,0 +1,866 @@ +#! /usr/bin/env perl +use strict; +use warnings; +use Term::ANSIColor; +#--- --- ---# +use POSIX qw(locale_h); +use locale; +setlocale(LC_CTYPE,"no_NO"); + +my $versionnumber="2.0"; +my $versiondate="2008 Feb 10"; + +#--- --- ---# + +### Macros for headers +# Macros that identify headers: i.e. following token or +# {...} is counted as header. The =>[2] indicates transition to +# state 2 which is used within headers (although the value is +# actually never used). This is copied to %TeXmacro and the +# only role of defining it here is that the counter for the number +# of headers is incremented by one. +my %TeXheader=('\title'=>[2],'\part'=>[2],'\chapter'=>[2], + '\section'=>[2],'\subsection'=>[2],'\subsubsection'=>[2], + '\paragraph'=>[2],'\subparagraph'=>[2]); + +### How many tokens to gobble after macro +# Each macro is assumed to gobble up a given number of +# tokens (or {...} groups), as well as options [...] before, within +# and after. The %TeXmacro hash gives a link from a macro +# (or beginNAME for begin-end groups without the backslash) +# to either an integer giving the number of tokens to ignore +# or to an array (specified as [num,num,...]) of length N where +# N is the number of tokens to be read with the macro and the +# array values tell how each is to be interpreted (see the status +# values: 0=ignore, 1=count, etc.). Thus specifying a number N is +# equivalent to specifying an array [0,...,0] of N zeros. +# +# For macros not specified here, the default value is 0: i.e. +# no tokens are excluded, but [...] options are. Header macros +# specified in %TeXheader are automatically included here. +my %TeXmacro=(%TeXheader, + '\documentclass'=>1,'\documentstyle'=>1,'\usepackage'=>1, '\hyphenation'=>1, + '\pagestyle'=>1,'\thispagestyle'=>1, '\pagenumbering'=>1,'\markboth'=>1, '\markright'=>1, + '\newcommand'=>[-3,-3],'\renewcommand'=>[-3,-3], + '\newenvironment'=>[-3,-3,-3], 'renewenvironment'=>[-3,-3,-3], + '\newfont'=>2,'\newtheorem'=>2,'\bibliographystyle'=>1, '\bibliography'=>1, + '\parbox'=>1, '\marginpar'=>[3],'\makebox'=>0, '\raisebox'=>1, '\framebox'=>0, + '\newsavebox'=>1, '\sbox'=>1, '\savebox'=>2, '\usebox'=>1,'\rule'=>2, + '\footnote'=>[3],'\label'=>1, '\ref'=>1, '\pageref'=>1, '\bibitem'=>1, + '\cite'=>1, '\citep'=>1, '\citet'=>1, '\citeauthor'=>1, '\citealt'=>1, '\nocite'=>1, + '\eqlabel'=>1, '\eqref'=>1,'\hspace'=>1, '\vspace'=>1, '\addvspace'=>1, + '\input'=>1, '\include'=>1, '\includeonly'=>1,'\includegraphics'=>1, + '\newlength'=>1, '\setlength'=>2, '\addtolength'=>2,'\settodepth'=>2, + '\settoheight'=>2, '\settowidth'=>2,'\newcounter'=>1, '\setcounter'=>2, + '\addtocounter'=>2,'\stepcounter'=>1, '\refstepcounter'=>1, '\usecounter'=>1, + '\alph'=>1, '\arabic'=>1, '\fnsymbol'=>1, '\roman'=>1, '\value'=>1, + '\cline'=>1, '\multicolumn'=>3,'\typeout'=>1, '\typein'=>1, + 'beginlist'=>2, 'beginminipage'=>1, 'begintabular'=>1, + 'beginthebibliography'=>1,'beginlrbox'=>1, + '\begin'=>1,'\end'=>1,'\title'=>[2]); + +### Macros that should be counted as one or more words +# Macros that represent text may be declared here. The value gives +# the number of words the macro represents. +my %TeXmacroword=('\LaTeX'=>1,'\TeX'=>1); + +### Macros that are counted within the preamble +# The preamble is the text between \documentclass and \begin{document}. +# Text and macros in the preamble is ignored unless specified here. The +# value is the status (1=text, 2=header, etc.) they should be interpreted as. +# Note that only the first unit (token or {...} block) is counted. +my %TeXpreamble=('\title'=>[2], + '\newcommand'=>[-3,-3],'\renewcommand'=>[-3,-3], + '\newenvironment'=>[-3,-3,-3], 'renewenvironment'=>[-3,-3,-3], + ); + +### Begin-End groups +# Identified as begin-end groups, and define =>state. The +# states used corresponds to the elements of the count array, and +# are: +# 0: Not included +# 1: Text, word included in text count +# 2: Header, words included in header count +# 3: Float caption, words included in float caption count +# 6: Inline mathematics, words not counted +# 7: Displayed mathematics, words not counted +# -1: Float, not included, but looks for captions +# +# 4 and 5 are used to count number of headers and floats +# and are not used as states. +# +# Groups that are not defined will be counted as the surrounding text. +# +# Note that some environments may only exist within math-mode, and +# therefore need not be defined here: in fact, they should not as it +# is not clear if they will be in inlined or displayed math. +# +my %TeXgroup=('document'=>1,'letter'=>1,'titlepage'=>0, + 'center'=>1,'flushleft'=>1,'flushright'=>1, + 'abstract'=>1,'quote'=>1,'quotation'=>1,'verse'=>1,'minipage'=>1,'verbatim'=>1, + 'description'=>1,'enumerate'=>1,'itemize'=>1,'list'=>1, + 'theorem'=>1,'lemma'=>1,'definition'=>1,'corollary'=>1,'example'=>1, + 'math'=>6,'displaymath'=>7,'equation'=>7,'eqnarray'=>7, + 'figure'=>-1,'float'=>-1,'picture'=>-1,'table'=>-1, + 'tabbing'=>0,'tabular'=>0,'thebibliography'=>0,'lrbox'=>0); + +### In floats: include only specific macros +# Macros used to identify caption text within floats. +my %TeXfloatinc=('\caption'=>[3]); + +### Macros for including tex files +# Allows \macro{file} or \macro file. If the value is 1, the filetype .tex will +# be added if file is without a filetype; if the value is 0, this will not be +# done. +my %TeXfileinclude=('\input'=>0,'\include'=>1); + +### Count labels +# Labels used to describe the counts +my @countlabel=('Files','Words in text','Words in headers', + 'Words in float captions','Number of headers','Number of floats', + 'Number of math inlines','Number of math displayed'); + +# Styles +my @STYLES=(); +my %STYLE; +$STYLES[0]={'error'=>'bold red'}; +$STYLES[1]={%{$STYLES[0]}, + 'word1'=>'blue','word2'=>'bold blue','word3'=>'blue', + 'grouping'=>'red','document'=>'red','mathgroup'=>'magenta', + 'state'=>'cyan underline'}; +$STYLES[2]={%{$STYLES[1]}, + 'word0'=>'yellow','word-1'=>'yellow', + 'command'=>'green','exclgroup'=>'yellow','exclmath'=>'yellow', + 'ignore'=>'cyan'}; +$STYLES[3]={%{$STYLES[2]}, + 'tc'=>'bold yellow','comment'=>'yellow','option'=>'yellow','fileinclude'=>'bold green'}; +$STYLES[4]={%{$STYLES[3]}}; + +# Options and states +my $verbose=0; +my $showstates=0; +my $htmlstyle=0; +my $blankline=0; +my $includeTeX=0; +my $briefsum=0; + +#--- --- ---# + +## SHORT HELP AND INFO +if (!defined @ARGV) { + print_version(); + print_syntax(); + print_reference(); + exit; +} elsif ($ARGV[0]=~/^(\-(h|\?|\-?help)|\/\?)$/) { + print_help(); + exit; +} elsif ($ARGV[0]=~/^\-?\-version$/) { + print_version(); + exit; +} elsif ($ARGV[0]=~/^\-?\-license$/) { + print_license(); + exit; +} + +# PROCESS ARGUMENTS AND FILES +my $totalcount=new_count(); +my @toplevelfiles; +my @filelist; +foreach my $arg (@ARGV) { + if ($arg eq '-noinc') {$includeTeX=0; next;} + if ($arg eq '-inc') {$includeTeX=1; next;} + if ($arg eq '-brief') {$briefsum=1; next;} + if ($arg eq '-v0') {$verbose=0; next;} + if ($arg eq '-v1') {$verbose=1; next;} + if ($arg eq '-vv' || $arg eq '-v2') {$verbose=2; next;} + if ($arg eq '-vvv' || $arg eq '-v3' || $arg eq '-v') {$verbose=3; next;} + if ($arg eq '-vvvv' || $arg eq '-v4') {$verbose=3; $showstates=1; next;} + if ($arg =~ /^\-showstate/ ){$showstates=1; next;} + if ($arg =~ /^\-html/ ) { + $ENV{'ANSI_COLORS_DISABLED'} = 1; + $htmlstyle = $arg eq '-htmlcore' ? 1 : 2; + if ($htmlstyle>1) {html_head();} + next; + } + if ($arg=~/^\-(nocol|nc$)/) { + $ENV{'ANSI_COLORS_DISABLED'} = 1; + next; + } + if ($arg=~/^\-/) { + print 'Invalid opton '.$arg."\n"; + print_syntax(); + exit; + } + $arg=~s/\\/\//g; + push @toplevelfiles,$arg; +} +%STYLE=%{$STYLES[$verbose]}; +for my $file (<@toplevelfiles>) { + @filelist=($file); + foreach my $f (@filelist) { + my $tex=TeXfile($f); + my $fpath=$f; + $fpath=~s/^(.*[\\\/])[^\\\/]+/$1/; + if (!defined $tex) { + print "File not found or not readable: ".$f."\n"; + } else { + parse($tex); + print "\n"; + print_count($tex->{'count'},'FILE: '.$f); + print "\n"; + add_count($totalcount,$tex->{'count'}); + } + } +} +if (${$totalcount}[0]>1) { + print "\n"; + formatprint('Total','h1'); + print_count($totalcount,'SUM'); +} +if ($htmlstyle>1) { + html_tail(); +} + + + +######### +######### Subroutines +######### + +sub TeXfile { + my $filename=shift @_; + my $file=read_file($filename) || return undef; + return TeXcode($file,$filename); +} + +sub TeXcode { + my ($texcode,$filename)=@_; + my %TeX=(); + $TeX{'filename'}=$filename; + if (!defined $filename) { + $TeX{'filepath'}=''; + } elsif ($filename=~/^(.*[\\\/])[^\\\/]+$/) { + $TeX{'filepath'}=$1; + } else { + $TeX{'filepath'}=''; + } + $TeX{'line'}=$texcode; + $TeX{'next'}=undef; + $TeX{'type'}=undef; + $TeX{'style'}=undef; + $TeX{'printstate'}=undef; + $TeX{'eof'}=0; + $TeX{'count'}=new_count(); + $TeX{'count'}[0]++; + return \%TeX; +} + +sub set_style { + my ($tex,$style)=@_; + if (!(($tex->{'style'}) && ($tex->{'style'} eq '-'))) {$tex->{'style'}=$style;} +} + +sub flush_style { + my ($tex,$style)=@_; + set_style($tex,$style); + flush_next($tex); +} + +sub line_return { + my $blank=shift @_; + if ($blank>$blankline) { + if ($htmlstyle) {print "<br>\n";} else {print "\n";} + $blankline++; + } +} + +sub print_style { + my ($text,$style,$state)=@_; + (($verbose>=0) && (defined $text) && (defined $style)) || return; + my $colour; + ($colour=$STYLE{$style}) || return; + if (($colour) && !($colour eq '-')) { + if ($htmlstyle) { + print "<span class='".$style."'>".$text."</span>"; + } else { + print Term::ANSIColor::colored($text,$colour); + } + if ($state) { + print_style($state,'state'); + } + $blankline=-1; + } +} + +sub print_error { + my $text=shift @_; + line_return(1); + print_style("### ".$text." ###",'error'); + line_return(1); +} + +sub formatprint { + my ($text,$tag,$class)=@_; + my $break=($text=~s/\n$//); + if ($htmlstyle && defined $tag) { + print '<'.$tag; + if ($class) {print " class='".$class."'";} + print '>'.$text.'</'.$tag.'>'; + } else { + print $text; + } + if ($break) {print "\n";} +} + +sub read_file { + my $filename=shift @_; + open(FH,"<".$filename."") || return undef; + if ($verbose) { + #line_return(1); + formatprint("File: ".$filename."\n",'h2'); + $blankline=0; + } + my @text=(); + while (my $line=<FH>) { + push @text,$line; + } + close(FH); + return join('',@text); +} + +sub next_token { + my $tex=shift @_; + my ($next,$type); + if (defined $tex->{'next'}) {print_style($tex->{'next'}.' ',$tex->{'style'});} + $tex->{'style'}=undef; + while (defined ($next=get_next_token($tex))) { + $type=$tex->{'type'}; + if ($type==0) { + print_style($next,'comment'); + } elsif ($type==9) { + if ($verbose) {line_return(1);} + } else { + return $next; + } + } + return $next; +} + +sub flush_next { + my $tex=shift @_; + if (defined $tex->{'next'}) { + print_style($tex->{'next'}.' ',$tex->{'style'},$tex->{'printstate'}); + } + $tex->{'printstate'}=undef; + $tex->{'style'}='-'; +} + +sub get_next_token { + # Token (or token group) category: + # 0: comment + # 1: word (or other forms of text or text components) + # 2: symbol (not word, e.g. punctuation) + # 3: macro + # 4: curly braces {} + # 5: brackets [] + # 6: maths + # 999: end of line or blank line + # 666: TeXcount instruction (%TC:instruction) + my $tex=shift @_; + my $next; + (defined ($next=get_token($tex,'\%+TC:[^\n]*',666))) && return $next; + (defined ($next=get_token($tex,'\%[^\n]*',0))) && return $next; + (defined ($next=get_token($tex,'\n',9))) && return $next; + (defined ($next=get_token($tex,'\\\\[\{\}]',2))) && return $next; + (defined ($next=get_token($tex,'(\w+\.)+\w+\.?',1))) && return $next; + (defined ($next=get_token($tex,'\w+([\-\']\w+)*',1))) && return $next; + (defined ($next=get_token($tex,'[\"\'\`:\.,\(\)\[\]!\+\-\*=/\^\_\@\<\>\~\#\&]',2))) && return $next; + (defined ($next=get_token($tex,'\\\\([a-zA-Z_]+|[^a-zA-Z_])',3))) && return $next; + (defined ($next=get_token($tex,'[\{\}]',4))) && return $next; + (defined ($next=get_token($tex,'[\[\]]',5))) && return $next; + (defined ($next=get_token($tex,'\$\$',6))) && return $next; + (defined ($next=get_token($tex,'\$',6))) && return $next; + (defined ($next=get_token($tex,'.',999))) && return $next; + (defined ($next=get_token($tex,'[^\s]+',999))) && return $next; + $tex->{'eof'}=1; + return undef; +} + +sub get_token { + my ($tex,$regexp,$type)=@_; + if (!defined $regexp) {print_error("ERROR in get_token: undefined regex.");} + if (!defined $tex->{'line'}) {print_error("ERROR in get_token: undefined tex-line. ".$tex->{'next'});} + if ( $tex->{'line'} =~ s/^($regexp)[ \t\r\f]*// ) { + $tex->{'next'}=$1; + $tex->{'type'}=$type; + return $1; + } + return undef; +} + +sub new_count { + my @count=(0,0,0,0,0,0,0,0); + # files, text words, header words, float words, + # headers, floats, math-inline, math-display; + return \@count; +} + +sub count_word { + my ($count,$type,$word,$style,$verb)=@_; + ($word) || ($word=""); + ($style) || ($style=0); + ($verb) || ($verb=0); + if ($type>0) {${$count}[$type]++;} + if ($verb >= $verbose) { + } +} + +sub print_count { + my ($count,$header)=@_; + if ($briefsum) { + if ($htmlstyle) {print "<p class='count'>\n";} + print ${$count}[1]."+".${$count}[2]."+".${$count}[3]. + " (".${$count}[4]."/".${$count}[5]."/".${$count}[6]."/".${$count}[7].") ". + $header; + if ($htmlstyle) {print "</p>\n";} + return; + } + if ($htmlstyle) {print "<dl class='count'>\n";} + if (defined $header) { + formatprint($header."\n",'dt','header'); + } + for (my $i=1;$i<8;$i++) { + formatprint($countlabel[$i].': ','dt'); + formatprint(${$count}[$i]."\n",'dd'); + } + if ($htmlstyle) {print "</dl>\n";} +} + +sub add_count { + my ($a,$b)=@_; + for (my $i=0;$i<8;$i++) { + ${$a}[$i]+=${$b}[$i]; + } +} + +sub parse { + my ($tex)=@_; + if ($htmlstyle && $verbose) {print "<p class=parse>\n";} + while (!($tex->{'eof'})) { + parse_unit($tex,1); + } + if ($htmlstyle && $verbose) {print "</p>\n";} +} + +sub parse_unit { + # Status: + # 0 = exclude from count + # 1 = text + # 2 = header text + # 3 = float text + # -1 = float (exclude) + # -2 = strong exclude, ignore begin-end groups + # -3 = stronger exclude, do not parse macro parameters + # -9 = preamble (between \documentclass and \begin{document}) + my ($tex,$status,$end)=@_; + if (!defined $status) { + print_error("CRITICAL ERROR: Undefined parser status!"); + exit; + } elsif (ref($status) eq 'ARRAY') { + print_error("CRITICAL ERROR: Invalid parser status!"); + exit; + } + my $count=$tex->{'count'}; + my $substat; + if ($showstates) { + if (defined $end) { + $tex->{'printstate'}=':'.$status.':'.$end.':'; + } else { + $tex->{'printstate'}=':'.$status.':'; + } + flush_next($tex); + } + while (defined (my $next=next_token($tex))) { + # parse next token; or tokens until match with $end + set_style($tex,"ignore"); + if ((defined $end) && ($end eq $next)) { + # end of unit + return; + } elsif (!defined $next) { + print_error("ERROR: End of file while waiting for ".$end); + return; + } + if ($status==-9 && $next eq '\begin' && $tex->{'line'}=~/^\{\s*document\s*\}/) { + # \begin{document} + $status=1; + } + if ($next eq '\documentclass') { + # starts preamble + set_style($tex,'document'); + gobble_option($tex); + gobble_macro_parms($tex,1); + while (!($tex->{'eof'})) { + parse_unit($tex,-9); + } + } elsif ($tex->{'type'}==666) { + # parse TC instructions + parse_tc($tex); + } elsif ($tex->{'type'}==1) { + # word + if ($status>0) { + ${$count}[$status]++; + set_style($tex,'word'.$status); + } + } elsif ($next eq '{') { + # {...} + parse_unit($tex,$status,'}'); + } elsif ($tex->{'type'}==3 && $status==-3) { + set_style($tex,'ignore'); + } elsif ($tex->{'type'}==3) { + # macro call + set_style($tex,'command'); + if ($next eq '\begin' && $status!=-2) { + parse_begin_end($tex,$count,$status); + } elsif (($status==-1) && ($substat=$TeXfloatinc{$next})) { + # text included from float + gobble_macro_parms($tex,$substat); + } elsif ($status==-9 && defined ($substat=$TeXpreamble{$next})) { + # parse preamble include macros + if (defined $TeXheader{$next}) {${$count}[4]++;} + gobble_macro_parms($tex,$substat,1); + } elsif ($status<0) { + # ignore + gobble_option($tex); + } elsif ($next eq '\(') { + # math inline + parse_math($tex,$count,$status,6,'\)'); + } elsif ($next eq '\[') { + # math display + parse_math($tex,$count,$status,7,'\]'); + } elsif ($next eq '\def') { + # ignore \def... + $tex->{'line'} =~ s/^([^\{]*)\{/\{/; + flush_next($tex); + print_style($1.' ','ignore'); + parse_unit($tex,-2); + } elsif (defined (my $addsuffix=$TeXfileinclude{$next})) { + # include file: queue up for parsing + parse_include_file($tex,$count,$status,$addsuffix); + } elsif (defined ($substat=$TeXmacro{$next})) { + # macro: exclude options + if (defined $TeXheader{$next}) {${$count}[4]++;} + gobble_macro_parms($tex,$substat,$status); + } elsif (defined ($substat=$TeXmacroword{$next})) { + # count macro as word (or a given number of words) + ${$count}[$status]+=$substat; + set_style($tex,'word'.$status); + } elsif ($next =~ /^\\[^\w\_]/) { + } else { + gobble_option($tex); + } + } elsif ($next eq '$') { + # math inline + parse_math($tex,$count,$status,6,'$'); + } elsif ($next eq '$$') { + # math display (unless already in inlined math) + if (! $end eq '$') {parse_math($tex,$count,$status,7,'$$');} + } + if (!defined $end) {return;} + } +} + +sub gobble_option { + my $tex=shift @_; + flush_next($tex); + if ($tex->{'line'} =~ s/^(\[(\w|[,\-\s\~\.\:\;\+\?\*\_\=])*\])//) { + print_style($1,'option'); + return $1; + } + return undef; +} + +sub parse_tc { + my ($tex)=@_; + set_style($tex,'tc'); + if ($tex->{'next'}=~/^\%+TC:\s*(\w+)\s+([\\]*\w+)\s+([^\s\n]+)(\s+([0-9]+))?/) { + my $instr=$1; + my $macro=$2; + my $param=$3; + my $option=$5; + if ($param=~/^\[([0-9,]+)\]$/) {$param=[split(',',$1)];} + if (($instr eq 'macro') || ($instr eq 'exclude')) {$TeXmacro{$macro}=$param;} + elsif ($instr eq 'header') {$TeXheader{$macro}=$param;$TeXmacro{$macro}=$param;} + elsif ($instr eq 'macroword') {$TeXmacroword{$macro}=$param;} + elsif ($instr eq 'preambleinclude') {$TeXpreamble{$macro}=$param;} + elsif ($instr eq 'group') {$TeXmacro{'begin'.$macro}=$param;$TeXgroup{$macro}=$option;} + elsif ($instr eq 'floatinclude') {$TeXfloatinc{$macro}=$param;} + elsif ($instr eq 'fileinclude') {$TeXfileinclude{$macro}=$param;} + else {print_error("Warning: Unknown TC command: ".$instr);} + } elsif ($tex->{'next'}=~/^\%+TC:\s*(\w+)/) { + my $instr=$1; + print_error("Warning: Unknown TC command: ".$instr); + } +} + +sub parse_math { + my ($tex,$count,$status,$substat,$end)=@_; + my $localstyle=$status>0 ? 'mathgroup' : 'exclmath'; + if ($status>0) {${$count}[$substat]++;} + set_style($tex,$localstyle); + parse_unit($tex,0,$end); + set_style($tex,$localstyle); +} + +sub parse_begin_end { + my ($tex,$count,$status)=@_; + my $localstyle=$status>0 ? 'grouping' : 'exclgroup'; + flush_style($tex,$localstyle); + gobble_option($tex); + my $groupname; + if ($tex->{'line'} =~ s/^\{\s*([^\{\}]+)\s*\*?\}[ \t\r\f]*//) { + # gobble group type + $groupname=$1; + print_style('{'.$1.'}',$localstyle); + my $next='begin'.$1; + if (defined (my $substat=$TeXmacro{$next})) { + gobble_macro_parms($tex,$substat); + } + } else { + print_error("Warning: BEGIN group without type."); + } + # find group status (or leave unchanged) + my $substat; + defined ($substat=$TeXgroup{$1}) || ($substat=$status); + if ($status<=0 && $status<$substat) {$substat=$status;} + if (($status>0) && ($substat==-1)) { + # Count float + ${$count}[5]++; + } + if ($status>0 and $substat>3) { + # count item, exclude contents + ${$count}[$substat]++; + $substat=0; + } + parse_unit($tex,$substat,'\end'); + if ($tex->{'line'} =~ s/^\{\s*([^\{\}]+)\s*\}[ \t\r\f]*//) { + # gobble group type + flush_style($tex,$localstyle); + print_style('{'.$1.'}',$localstyle); + } else { + print_error("Warning: END group without type while waiting to end ".$groupname."."); + } +} + +sub parse_include_file { + my ($tex,$count,$status,$addsuffix)=@_; + $tex->{'line'} =~ s/^\{([^\{\}\s]+)\}// || + $tex->{'line'} =~ s/^\s*([^\{\}\%\\\s]+)// || + return; + flush_next($tex); + if ($status>0) { + print_style($&,'fileinclude'); + my $fname=$1; + if ($addsuffix && ($fname=~/^[^\.]+$/)) {$fname.='.tex';} + if ($includeTeX) {push @filelist,$tex->{'filepath'}.$fname;} + } else { + print_style($&,'ignored'); + } +} + +sub gobble_options { + while (gobble_option(@_)) {} +} + +sub gobble_macro_modifier { + my $tex=shift @_; + flush_next($tex); + if ($tex->{'line'} =~ s/^\*//) { + print_style($1,'option'); + return $1; + } + return undef; +} + +sub gobble_macro_parms { + my ($tex,$parm,$oldstat)=@_; + my $i; + if (ref($parm) eq 'ARRAY') { + $i=scalar @{$parm}; + } else { + $i=$parm; + $parm=[0,0,0,0,0,0,0,0,0]; + } + if ($i>0) {gobble_macro_modifier($tex);} + gobble_options($tex); + for (my $j=0;$j<$i;$j++) { + parse_unit($tex,new_status($parm->[$j],$oldstat)); + gobble_options($tex); + } +} + +sub new_status { + my ($substat,$old)=@_; + if (!defined $old) {return $substat;} + if ($old==-3 || $substat==-3) {return -3;} + if ($old==-2 || $substat==-2) {return -2;} + if ($old==0 || $substat==0) {return 0;} + if ($old==-9 || $substat==-9) {return -9;} + if ($old>$substat) {return $old;} + return $substat; +} + +### HTML context + +sub html_head { + print ' +<html> +<head> +<style> +<!-- +body {width:100%;padding:5;margin:5 10 5 5;} +.error {font-weight:bold;color:#f00;font-style:italic;} +.parse {font-size: 80%; background: #eef;} +.word1,.word2,.word3 {color: #009;} +.word2 {font-weight: 700;} +.word3 {font-style: italic;} +.word-1 {color: #66c;} +.command {color: #c00;} +.option {color: #cc0;} +.grouping, .document {color: #900; font-weight:bold;} +.mathgroup {color: #090;} +.exclmath {color: #6c6;} +.ignore {color: #999;} +.exclgroup {color:#c66;} +.tc {color: #999; font-weight:bold;} +.comment {color: #999; font-style: italic;} +.state {color: #990; font-size: 70%;} +.fileinclude {color: #696; font-weight:bold;} +dl.count {background: #cfc; color: 009;} +dl.count dt.header {font-weight: 700; font-style: italic; float: none;} +dl.count dt {clear: both; float: left;} +dl.count dd {font-weight: 700;} +.warning {color: #c00; font-weight: 700;} +.parse, .count {border: solid 1px #999; margin: 0pt; padding: 4pt;} +.parse {border-bottom:none;} +--> +</style> +</head> +<body> +<h1>LaTeX word count</h1> +'; +} + +sub html_tail { + print '</body></html>'; +} + + +### HELP AND INFO + +sub print_version { + print "TeXcount version ".$versionnumber.", ".$versiondate.'.'; +} + +sub print_syntax { + print ' +Syntax: TeXcount.pl [options] files + +Options: + -v Verbose (same as -v3) + -v0 Do not present parsing details + -v1 Verbose: print parsed words, mark formulae + -v2 More verbose: also print ignored text + -v3 Even more verbose: include comments and options + -showstate Show internal states (with verbose) + -brief Only prints a brief, one line summary of counts + -nc, -nocol No colours (colours require ANSI) + -inc Include tex files included in the document + -noinc Do not include included tex files (default) + -html Output in HTML format + -htmlcore Only HTML body contents + -h, -?, --help, /? Help + --version Print version number + --license License information +'; +} + +sub print_help { + print ' +*************************************************************** +* TeXcount.pl '.$versionnumber.', '.$versiondate.' +* + +Count words in TeX and LaTeX files, ignoring macros, tables, +formulae, etc. +'; + print_syntax(); + print ' +The script counts words as either words in the text, words in +headers/titles or words in floats (figure/table captions). +Macro options (i.e. \marco[...]) are ignored; macro parameters +(i.e. \macro{...}) are counted or ignored depending on the +macro, but by default counted. Begin-end groups are by default +ignored and treated as \'floats\', though some (e.g. center) are +counted. + +Unless -nocol (or -nc) has been specified, the output will be +colour coded. Counted text is coloured blue with headers are in +bold and in HTML output caption text is italicised. + +Mathematical formulae are not counted as words, but are instead +counted separately with separate counts for inlined formulae +and displayed formulae. Similarly, the number of headers and +the number of \'floats\' are counted. Note that \'float\' is used +here to describe anything defined in a begin-end group unless +explicitly recognized as text or mathematics. + +The verbose options (-v1, -v2, -v3, showstate) produces output +indicating how the text has been interpreted. Check this to +ensure that words in the text has been interpreted as such, +whereas mathematical formulae and text/non-text in begin-end +groups have been correctly interpreted. + +Unix hint: Use \'less -r\' instead of just \'less\' to view output: +the \'-r\' option makes less treat text formating codes properly. + +Windows hint: If your Windows interprets ANSI colour codes, lucky +you! Otherwise, use the -nocol (or -nc) option with the verbose +options or the output will be riddled with colour codes. Instead, +you can use -html to produce HTML code, write this to file and +view with your favourite browser. +'; + print_reference(); +} + +sub print_reference { + print ' +The TeXcount script is copyright of Einar Andreas Rødland (2008) +and published under the LaTeX Project Public License. + +For more information about the script, e.g. news, updates, help, +usage tips, known issues and short-comings, go to + http://folk.uio.no/einarro/Comp/texwordcount.html +or go to + http://folk.uio.no/einarro/Services/texcount.html +to access the script as a web service. Feedback such as problems +or errors can be reported to einarro@ifi.uio.no. +'; +} + +sub print_license { + print 'TeXcount version '.$versionnumber.' + +Copyright 2008 Einar Andreas Rødland + +The TeXcount script is published under the LaTeX Project Public +License (LPPL) + http://www.latex-project.org/lppl.txt +which grants you, the user, the right to use, modify and distribute +the script. However, if the script is modified, you must change its +name or use other technical means to avoid confusion. + +The script has LPPL status "maintained" with Einar Andreas +Rødland being the current maintainer. +'; +} diff --git a/Master/tlpkg/bin/ctan2tds b/Master/tlpkg/bin/ctan2tds index 539c6fd15a0..0aa2bd7fe59 100755 --- a/Master/tlpkg/bin/ctan2tds +++ b/Master/tlpkg/bin/ctan2tds @@ -740,6 +740,7 @@ $standardfmt='latex'; 'tamil-omega', 'omega', 'templates-fenn', 'german', 'templates-sommer', 'german', + 'texcount', 'support', 'texsis', 'texsis', 'textpath', 'metapost', 'thumbpdf', 'generic', @@ -1252,6 +1253,7 @@ $standardxmt='\.xmt'; 'a2ping' => '\.pl$', 'epstopdf' => 'epstopdf', 'perltex' => '\.pl$', + 'texcount' => '\.pl$', 'thumbpdf' => '\.pl$', 'vpe' => '\.pl$', ); diff --git a/Master/tlpkg/tlpsrc/texcount.tlpsrc b/Master/tlpkg/tlpsrc/texcount.tlpsrc new file mode 100644 index 00000000000..5cb154615df --- /dev/null +++ b/Master/tlpkg/tlpsrc/texcount.tlpsrc @@ -0,0 +1,2 @@ +name texcount +category Package |