#!/usr/bin/gawk -f # Add multilevel heading numbers to HTML headings. # Ian E. Gorman 2023 # This AWK program assumes that the input is valid HTML. # The program is written for GNU AWK and may not work in other versions of AWK. # The program has not been tested in POSIX AWK # AWK is often considered to be a line-oriented language that iterates over # the lines in a text file. AWK is actually a record-oriented language. # The default record separator is a platform-specific sequence of # characters: "\n", "\r\n". or "\r". # Splitting input lines on '<' instead of '\n' places each tag at the # beginning of a line, but ddrops the '<' character. A new '<" # character must be inserted in the corresponding output line. BEGIN { ORS = RS = "<" # Change record separators from default to '<' level = 0 # begin outside any headings LEVEL_MAX = 6 #

to

for (i = 1; i <= LEVEL_MAX; i++) { number[i] = 0 } } # Enter heading, output the start tag, set heading level match($0, /^[Hh]([1-6])[^>]*>/, part) != 0 { # heading start tag print "" # write the record separator (ORS = "<") printf("%s", substr($0, 1, RLENGTH)) # write the rest of the tag level = part[1] # entering heading, get the level from tag number[level]++ for (i = level + 1; i <= LEVEL_MAX; i++) number[i] = 0 printf("%d", number[1]) for (i = 2; i <= level; i++) printf(".%d", number[i]) printf(" ") printf(substr($0, RLENGTH + 1)) # output the remaining data next } # Exit heading: output end tag, unset heading level /^\/[Hh][1-6][^>]*>/ { # Heading end tag print "" # write the record separator (ORS = "<") printf("%s", $0) # write rest of tag and the following input data LEVEL = 0 # leaving heading next } # First record in file is not preceded by a record separator FNR == 1 { # No need to write a record separator (ORS = "<") printf("%s", $0) next } # All other input records are preded by a record separator { print "" # write the record separator (ORS = "<") printf("%s", $0) next }