# dbTeX.awk - a simple preprocessor for generating TeX output from
# 		database files
# Version 1.1.beta (1991-02-12) dr. w. kraml, KPMG Alpen-Treuhand Wien
# see dbTeX.tex for documentation!


BEGIN { console_msg("This is dbTeX Version 1.1.beta (1991-02-12)")
        printf("%% dbTeX (1.1.beta) Output generated " ctime() "\n")
													# ^ PolyAwk specific!
        printf("%% dbTeX       Input file: %s\n", ARGV[1])
# a number of initialisations and defs follow here:
        FieldS = FS
        RecordS = RS
        NRincluded = 0
        example_flag = 0                           
        buffer = ""
        STANDARD = 0
        STRING = 1
        TEMPLATE = 2
        ID = 3        
        USER = 1        
      }

      
# main loop - do this for each line in script

{       if ($0 ~ /^%!/) {					# embedded dbTeX-command
            in_template = 0
            buffer = substr($0,3)
            print $0						# output for reference
            dbTeX_command()
        }
        else if ($0 ~ /^%_/) {				# template contin. line
            print $0
            if (in_template) {				# start cont. with newlines
                nl = length(template[t_name]) ? "\n" : ""
                template[t_name] = template[t_name] nl substr($0,3)
            }
            else error_msg("INVALID CONTINUATION")
        }
        else if (example_flag) {			# embedded examples
            in_template = 0
            print "%" $0
        }
        else {
            in_template = 0
            print $0  						# original TeX line
        }
}

END {   s = NR " line(s) input, " NRincluded " record(s) included, "
        s = s (errors+0) " error(s)" 
        info_msg(s)
    }



# functions performing helpful tasks with various messages

function console_msg(s) { 					# output to console
    print s > "/dev/tty"
    }
    
function error_msg(msg,     s) {			# print error on console
    s = "% (dbTeX) Error: " msg "!"			# and in output file
    ++errors
    print s            
    console_msg(s " -> line " NR ":")
    console_msg($0)
}

function info_msg(msg,     s) {				# print info on console
    s = "% (dbTeX) Info: " msg "."			# and in output file
    print s            
    console_msg(s)
}


# dbTeX functions

function dbTeX_command() {					# the dbTeX main function
    advance(ID)
    example_flag = 0
    if (tok == "examples") example_flag = 1	# %! examples
    else if (tok == "record") { 			# %! record <id> <FS> [<RS>]
        if (advance(ID)) {
            if (tok ~ /^%[0-9]+%$/) {		# data-named template
                templ_typ = 1
                templ_field = substr(tok,2,length(tok)-2)
            }
            else {  						# script-named template
                templ_typ = 0
                templ_name = tok
            }
        }
        FieldS  = advance(STRING) ? tok : FS
        RecordS = advance(STRING) ? tok : RS
    }
    else if (tok=="template") {   			# %! template <id> <template>
        in_template = 1
        if (advance(ID))    				# get name
            t_name = tok
        if (advance(TEMPLATE)) 
            template[t_name] = tok
    }
    else if (tok=="break") { 				# %! break %f% <id>
        if (advance(ID)) {
            if (tok ~ /^%[0-9]+%$/)
                breakfield = substr(tok,2,length(tok)-2)
            else
                breakfield = tok
        }
        if (advance(ID))
            breaktemplate[breakfield] = tok
        if (advance(ID))
            breakmode[breakfield] = 1
        else breakmode[breakfield] = 0
    }
    else if (tok=="clearbreaks") { 			# %! clearbreaks
          for (i in oldvalue)
            delete oldvalue[i]  
          for (i in breaktemplate)
            delete breaktemplate[i]
          for (i in breakmode)
            delete breakmode[i]
    }
    else if (tok=="translate") { 			# %! translate <id>
        if (advance(ID))
            set_translation(tok)
    }
    else if (tok=="change") { 				# %! change <s1> <s2>
        add_trtbl(USER)
    }
    else if (tok=="include") { 				# %! include <filename>
        if (advance(ID))
            do_include(tok)
    }
    else error_msg("UNKNOWN COMMAND")
}


function advance(type,    sep,pos) { 		# get next token of type
    sub(/^[ \t]+/, "", buffer)  			# remove white space
    if (type == ID) {
        match(buffer, /^[^ \t]+/) 			# all up to white space
        tok = tolower(substr(buffer, 1, RLENGTH)) # tolower(): PolyAwk & GNU only!
        buffer = substr(buffer, RLENGTH+1)
        return RLENGTH
    }
    else if (type == TEMPLATE) { 			# rest of line
        tok = buffer
        buffer = ""
        return length(tok)
    }
    else if (type == STRING) { 				# string delimited by
        sep = substr(buffer,1,1) 			# unique character
        buffer = substr(buffer,2)
        pos = index(buffer, sep)
        if (pos)  {
            tok = substr(buffer,1,pos-1)
            buffer = substr(buffer, pos+1)
            return pos
        }
        else {
            tok = ""
            return 0
        }
    }
    else return 0
}


function add_trtbl(tbl) { 					# add an entry to tr table
    if (advance(STRING)) {
        tmp = tok
        if (advance(STRING))
          tbl==USER ? (usr_tbl[tmp] = tok) : (std_tbl[tmp] = tok)
        else 
          tbl==USER ? (usr_tbl[tmp] = "") : (std_tbl[tmp] = "")
    }
}


function set_translation(id) {				# install translation table
    if (toupper(id) == "OFF") {
        for (i in std_tbl)
            delete std_tbl[i]
        for (i in usr_tbl)
            delete usr_tbl[i]
    }
    else {									# read translation table
        while ((status = getline line < id) > 0) {
            buffer = line
            if (buffer !~ /^#/)
                add_trtbl(STANDARD)
        }        
        if (status == -1) 
            error_msg("TRANSLATION TABLE " id " NOT FOUND")
    }
}


function do_include(file) {					# include records of <file>
    old_FS = FS; old_RS = RS
    FS = FieldS; RS = RecordS
    inc = 0
    while (getline < file > 0) {
        for (i in breaktemplate)			# check for breaks
            if (oldvalue[i] != $i) {       
                oldvalue[i] = $i
                if (inc || breakmode[i])	# no break before 1st rec.,
                    incl_(template[breaktemplate[i]]) 
            } 								# if not explicitly wanted!

        if (templ_typ) 
            incl_(template[$templ_field])
        else incl_(template[templ_name])
        ++NRincluded; ++inc
    }
    FS = old_FS; RS = old_RS
    close(file)
    if (!inc) error_msg("FILE " file " NOT FOUND OR NOT ACCESSIBLE!")
    info_msg(inc " record(s) included from " file)
}


function incl_(t) {							# include record with template t
    s = ""
    while (match(t, /%[0-9]+%/)) {
        l = RSTART-1
        s = s substr(t,1,l)  txlate($(substr(t,RSTART+1,RLENGTH-2)))
											# translated data field
        t = substr(t,l+RLENGTH+1)
    }
    print s t                           
}


function txlate(s) {						# perform translations on string s
    for (target in std_tbl) 
        gsub(target, std_tbl[target], s)
    for (target in usr_tbl) 
        gsub(target, usr_tbl[target], s)
    return s
}