help-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Help-bash] Reading and handling "control" characters from a file


From: Conrad J. Sabatier
Subject: Re: [Help-bash] Reading and handling "control" characters from a file
Date: Sat, 21 Apr 2012 19:44:05 +0000 (UTC)
User-agent: Pan/0.135 (Tomorrow I'll Wake Up and Scald Myself with Tea; GIT 30dc37b master)

On Sat, 21 Apr 2012 14:13:52 -0400, Chet Ramey wrote:

> On 4/19/12 6:11 PM, Conrad J. Sabatier wrote:
>> I've just started doing a little prototyping in bash for a program I'll
>> eventually code most likely in C, and have hit a serious stumbling
>> block re: the handling of characters (bytes) in the very low range of
>> the ASCII table.
> 
> Bash variables are strings of characters.  There is a difference between
> a character with ASCII value 4 and a character with the ASCII value 52
> ("4").  Shell arithmetic convers the latter into numbers using the
> equivalent of strtol() before use.
> 
> To make what you want work, you'll have to figure out some way to offset
> the value you read from the file (i.e., c+'0') before attempting to use
> it in an arithmetic context.  Maybe perl or something like that could
> help. It's quite difficult to do using just what the shell provides.
> 
> Chet

Tell me about it!  I thought for a while that I had finally hit on a 
solution using printf:

function read_size_field
#
# read the next four bytes from file, run the data through the
# synchsafe decoder and output the resulting 32-bit integer
#
# the printf syntax is weird, I'll admit, but it works; don't mess with
# it!
# (almost works, that is; still fails if byte == '\n')
{
        local -i synchsafe_num=0
        local -i return_num
        local -i return_code
        local -i byte
        local -i i
        
        # read the synchsafe-encoded number from file
        
        for ((i = 3; i >= 0; --i))
        do
                read -n 1
                printf -v byte "%d" \'"${REPLY}"
                ((DEBUG)) && echo "byte = ${byte}" >&2
                ((synchsafe_num += (byte << (8 * i))))
        done
        
        ((DEBUG)) && echo "synchsafe_num = ${synchsafe_num}" >&2
        
        # convert the synchsafe-encoded number to a normal 32-bit integer
        return_num=$(synchsafe_decode ${synchsafe_num})
        return_code=$?
        
        echo ${return_num}      # output the result back to the caller
        return ${return_code}   # and return the return code from the
                                # decoding
}

The printf statement (that's bash's builtin printf) works for *almost* 
every possible value you can throw at it.  It will handle the CTRL-D 
character that was giving me trouble before, but now I'm running into 
trouble reading ASCII 0x0a (newline).

Still have yet to find a "universal" solution to this problem using shell 
features only.  Thinking of writing an external function in C that I can 
add to bash using its "dynamically loadable built-ins" capability.  Seems 
rather drastic to me, but it may in fact be the only way to have a "read" 
function that will accept the entire range of values (0-255) without any 
problems.

It's really a shame that bash still has such a glaring deficiency in such 
an important basic functionality as this after all these years.  I really 
do like using it as my main scripting tool, but having to devise these 
types of workarounds to accommodate some of its persnickety behavior can 
become rather tedious at times.

Anyway, thanks for the reminder as to how bash views things.  Sometimes I 
do forget.  :-)

-- 
Conrad J. Sabatier
address@hidden




reply via email to

[Prev in Thread] Current Thread [Next in Thread]