aboutsummaryrefslogblamecommitdiff
path: root/bin/mi5.awk
blob: 0a00d1d7c58f2aab01957c9491e541538e52286b (plain) (tree)
1
2
3
4
5
6
7
8
                       
       



                                                                               

               


                                                                              


                 


                                



                      


                                         
           
 

                                      
                              

        

                                  

        

                                 


        

                                                                               

                         
                
 

                                                
       
 
                                            


            


                                             

                                                                         
                                     
 
                                           

                                                          
                                                               
 

                                
 






                                                                              
                                    




                                                                
                                                           



                         
 









                                                                               
 


                                                             

                                                                             







                                                                             
                                     




                                                                             
                                          
                  
                                          

                 

 



                                                                             
                                         


                         
# Crude m4 preprocessor
BEGIN {
    self = "mi5"

    # You can change any of these, but while changing these is still relatively
    # sane...
    open = "<%"
    shut = "%>"

    # ... changing these probably isn't, and should compel you to rethink your
    # code, or quite possibly your entire life thus far.
    quote = "`"
    unquote = "'"
    dnl = "dnl"

    # We do not start in a block
    bmac = 0
}

# Fatal error function
function fatal(str) {
    stderr = "cat >&2"
    printf "%s: %s\n", self, str | stderr
    close(stderr)
    exit(1)
}

# Print an m4 opener as the first byte
NR == 1 { printf "%s", quote }

# Blocks
NF == 1 && $1 == open && !bmac++ {
    printf "%s", unquote
    next
}
NF == 1 && $1 == shut && bmac-- {
    printf "%s", quote
    next
}

# If in a block, print each line with any content on it after stripping leading
# and trailing whitespace
bmac && NF {
    gsub(/(^ +| +$)/, "")
    print $0 dnl
}

# If not in a block, look for inlines to process
!bmac {

    # We'll parse one variable into another.
    src = $0
    dst = ""

    # Start off neither quoting nor macroing.
    iquo = imac = 0

    # Crude and slow, clansman.  Your parser was no better than that of a
    # clumsy child.
    for (i = 1; i <= length(src); ) {

        # Inline macro expansion: commented
        # Look for end of comment and tip flag accordingly
        if (iquo)
            iquo = (substr(src, i, length(unquote)) != unquote)

        # Inline macro expansion
        else if (imac) {

            # Close the current inline macro expansion if a close tag is found
            # (in m4 terms: open a new quote), looking ahead past any spaces
            # from this point first
            for (j = i; substr(src, j, 1) ~ /[ \t]/; j++)
                continue
            if (substr(src, j, length(shut)) == shut) {
                dst = dst quote
                i = j + length(shut)
                imac = 0
                continue
            }

            # Look for start of comment and tip flag accordingly
            iquo = (substr(src, i, length(quote)) == quote)
        }

        # Plain text mode
        else {

            # Open a new inline macro expansion if an open tag is found (in m4
            # terms: close the quote), and then look ahead past any spaces from
            # that point afterward
            if (substr(src, i, length(open)) == open) {
                dst = dst unquote
                imac = 1
                for (i += length(open); substr(src, i, 1) ~ /[ \t]/; i++)
                    continue
                continue
            }

            # Escape quote terminators
            if (substr(src, i, length(unquote)) == unquote) {

                # Dear Mr. President.  There are too many variables nowadays.
                # Please eliminate three.  I am NOT a crackpot.
                dst = dst unquote unquote quote

                i += length(unquote)
                continue
            }
        }

        # If we got down here, we can just add the next character and move on
        dst = dst substr(src, i++, 1)
    }

    # If we're still in a macro expansion or quote by this point, something's
    # wrong; say so and stop, rather than print anything silly.
    if (iquo)
        fatal("Unterminated inline quote")
    else if (imac)
        fatal("Unterminated inline macro")
    else
        print dst
}

# Print an m4 closer and newline deleter as the last bytes if we've correctly
# stopped all our blocks
END {
    if (bmac)
        fatal("Unterminated block macro")
    else
        print unquote dnl
}