Home > Software engineering >  problem with my custom function `json_stringify` in `awk`
problem with my custom function `json_stringify` in `awk`

Time:09-20

I've written a shell function that converts an UTF-8 encoded string to a JSON string, using awk:

json_stringify() {

    LANG=C awk '

        BEGIN {
            for ( i = 1; i < ARGC; i   )
                print json_stringify(ARGV[i])
        }

        function json_stringify( str, _str, _out ) {

            if( ! ("\\" in _ESC_) )
                for ( i = 1; i <= 127; i   )
                    _ESC_[ sprintf( "%c", i) ] = sprintf( "\\ux", i )

            _str = str
            _out = "\""

            while ( match( _str, /[\"\\[:cntrl:]]/ ) ) {
                _out = _out substr(_str,1,RSTART-1) _ESC_[substr(_str,RSTART,RLENGTH)]
                _str = substr( _str, RSTART   RLENGTH )
            }

            return _out _str "\""
        }
    ' "$@"
}

It feels like I missed something trivial, because when I run (in bash):

json_stringify 'A"B' 'C\D' $'\b \f \t \r \n'

I get:

"A\u0022B"

while my expected output is:

"A\u0022B"
"C\u005cD"
"\u0008 \u000c \u0009 \u000d \u000a"

What could be the problem(s) in my code?

CodePudding user response:

One issue I see is the dual use of i as a loop variable in both the awk/BEGIN block as well as the function, and because i is not declared as 'local' in the function you end up with just one instance of i in use for the entire script. Net result is the function is pushing i out to 127 which is well beyond ARGC so the BEGIN block only loops once (i=1) because on the 2nd loop i=127.

Two possible fixes:

declare i as local to the function, eg:

function json_stringify( str, _str, _out, i ) {

or use a different loop variable (eg, j) in one of the loops, eg:

# in the BEGIN block:

for ( j = 1; j < ARGC; j   )
    print json_stringify(ARGV[j])

# or in the function:

for ( j = 1; j <= 127; j   )
     _ESC_[ sprintf( "%c", j) ] = sprintf( "\\ux", j )

Testing each of the possible fixes allows me to generate:

"A\u0022B"
"C\u005cD"
"\u0008 \u000c \u0009 \u000d \u000a"

Controlling Variable Scope - brief discussion on this topic.

  • Related