#!/bin/sh
#
# Contribution to "Sprachwahl" from Linux Magazin 2008/10
#
# Solution for script language TCL
#
# (c) Gerhard Reithofer,
# Techn. EDV Reithofer; 2008-09-07
#
# Usage: Usage: tclsh reorder [sortopt] [memopt] infile [outfile]
#
# sortopt: none .. footnotes are rebuild in order as they appear in
# footnote list (1..n)
# -t .... footnotes are renumbered as they appear in text,
# order of footnotes in list is preserved
# -f .... footnotes are renumbered as they appear in text,
# footnotes list is reordered also
# memopt: none .. file is preprocessed line by line
# -m .... complete file is read into memory at begin,
# no check for existing memory is done
# infile: ......... name of input file, not checked (exit, readable...)
# outfile: ........ name of output file, will be overwritten without
# confirmation, default is stdout
#
#
# starting tclsh \
exec tclsh $0 "$@"
### switch between file mode and memory mode
set file_mode_solution 1
### footnote begin marker
set fn(mark) "@footnote:"
### footnote counter
set fn(cntr) 0
### default - do not sort footnotes in text
set fn(sort) 0
### default - do not (re)sort footnotes
set fn(note) 0
### footnote data
array set fn_data {}
### default standard output
set ofd stdout
###
proc syntax {args} {
if {[llength $args]} { puts [lindex $args 0] }
puts "Usage: [file tail $::argv0] \[-t|-f\] \[-m\] infile \[outfile\]"
puts " -t .. sort footnotes in text (default: sort footnotes at end only)"
puts " -f .. sort footnotes in text and reorder footnotes at end"
puts " -m .. read complete file to memory (default: line by line file I/O)"
exit 1
}
### simple add & count note function
proc add_note id {
global fn_data fn
if {![info exists fn_data($id)]} {
set fn_data($id) [incr fn(cntr)]
}
return $fn_data($id)
}
###
### process text and reorder footnotes
### in text if ($reorder == 1)
###
proc process_text {fd ofd reorder} {
global fn fn_data
set cnt 0
next $fd line
while {$line ne $fn(mark)} {
set rres [regexp -indices {\[([0-9]+)\]} $line pos num]
if {!$rres} {
puts $ofd $line
next $fd line
continue
}
### process all footnotes in $line
###
set eidx 0
set rlin ""
while {$rres} {
set id [string range $line [lindex $num 0] [lindex $num 1]]
set s1 [string range $line $eidx [lindex $pos 0]]
append rlin $s1
if {$reorder} {
append rlin $fn_data($id)
} else {
set new [add_note $id]
append rlin $new
}
set eidx [lindex $pos 1]
set rres [regexp -indices -start $eidx {\[([0-9]+)\]} $line pos num]
}
set s2 [string range $line [lindex $pos 1] end]
append rlin $s2
### write out corrected line and read next...
###
puts $ofd $rlin
next $fd line
}
}
###
### process footnote section
###
proc write_notes {fd ofd reorder} {
global fn fn_data
puts $fn(mark)
next $fd line
while {![enddata $fd]} {
if {$line eq ""} {
if {![info exists data]} {puts $ofd ""}
next $fd line
continue
}
if {[string first {[} $line]>=0} {
set lc [string first {]} $line]
set id [string range $line 1 [incr lc -1]]
set line [string range $line [incr lc 2] end]
lappend data [list $fn_data($id) $line]
}
next $fd line
}
if {$reorder} {
set data [lsort -index 0 -integer $data]
}
foreach r $data {
set id [lindex $r 0]
puts $ofd "\[$id\][lindex $r 1]"
}
}
###
### read footnote section 1st, for
### determination of footnote order
proc preproc_notes fd {
global fn fn_data
# read over all text lines...
set line ""
while {$line ne $fn(mark)} {
next $fd line
}
while {![enddata $fd]} {
next $fd line
if {[string index $line 0] ne {[}} continue
set lc [string first {]} $line]
set id [string range $line 1 [incr lc -1]]
add_note $id
}
# rewind file
reset $fd
}
###
### commandline handling and opening of
### files - no further file checks are made!!!
###
if {$argc<1} { syntax }
foreach p $argv {
if {[string index $p 0] eq "-"} {
switch -- $p {
"-t" {set fn(sort) 1}
"-f" {set fn(sort) 1;set fn(note) 1}
"-m" {set file_mode_solution 0}
default {syntax "Invalid option: '$p'"}
}
} else {
if {[info exists ifd]} {
set ofd [open $p w+]
} else {
set ifd [open $p r]
}
}
}
##########################################################
### begin of dummy file functions
###
if {$file_mode_solution} {
proc next {dv rv} { upvar 1 $rv line ; gets $dv line }
proc enddata {dv} { return [eof $dv] }
proc reset {dv} { seek $dv 0 }
} else {
array set lines {cnt -1 max 0 mem {}}
proc next {dv rv} {
global lines ; upvar 1 $rv line
set line [lindex $lines(mem) [incr lines(cnt)]]
}
proc enddata {dv} {
global lines
return [expr {$lines(cnt)>=$lines(max)}]
}
proc reset {dv} { global lines ; set lines(cnt) -1}
}
###
### end of dummy file functions
##########################################################
if {![info exists ifd]} {
syntax "Syntax error: no inputfile given!"
}
###
### M A I N part starts here
###
if {!$file_mode_solution} {
set lines(mem) [split [read -nonewline $ifd] "\n"]
set lines(max) [llength $lines(mem)]
}