Tuesday 20 March 2012

local variables are great

In the last few months I have really come to appreciate what perl and bash local variables really are. And it took a better understanding of list/scheme/tex/texmacs, and a couple of years to think about it.

And my bash scripts are more and more lisp-like using extreme parallelisations and local variables.

This bash function takes the name of a variable as a first argument and returns in this argument a free file descriptor number, rather like C's fopen(). The second argument can be the lowest file descriptor to choose from, but it defaults to the current value of the variable whose name is given in the first argument. The third argument is the highest value to work to, and defaults to 254.

The shell function closes stderr as it uses stderr for fdup to test if a destructor is in use. Ironically to close stderr, bash has to save it in another file descriptor - but internally bash can find one that is free, something that this function is written to do! But this means that this function will never allocate the descriptor in temporary use to save stderr even though that descriptor will be free when this function exits. Thus while this function can allocate a free descriptor it may miss some that were free. C'est la vie.

fd_allocate() {
  set "$1" "${2:-${!1:-3}}" "${3:-254}"

  printf -v "$1" ""
  while test "$2" -le "$3"
  do
    if ! : 2>&"$2"
    then printf -v "$1" "%s" "$2"
         return
    fi
    set "$1" "$(( $2 + 1 ))" "$3"
  done
  return 1
} 2>&-

This function is used for high parallelisation like this:

do_something() {
  local fd=4 things
  for thing in "$@"
  do
    if fd_allocate fd && exec 3< <( something "$thing" )
    then eval "exec $fd<&3 3<&-"
         things[$fd]="$thing"
    else # spawn failed, do foreground instead
         echo "Output for $thing:"
         something "$thing"
    fi
  done

The results (stdout) can then be reaped like this ($? cannot be obtained, if you want it, emit it to stdout):

  local output
  for fd in ${!things[@]}
  do 
     thing = ${!things[$fd]}
     read -d "" -u $fd output
     echo "Output for $thing: $output"
  done
}


Of course cat </dev/fd/$fd might do instead of read

However, all these uses of local are abusive and ideally I do want scoped variables in bash too. In fact fd_allocate was specially written to not use any local variables but to re-write it's parameters instead.

But the point is I can reap the parallised results in the right local environment without having to pass parameters. This becomes more useful as I factor my code which is written using literate programming techniques; and so I now longer write linear functions but instead compose fragments of code, and of course in this context, the environment of local or scoped variables becomes an implicit API, and so this is the situation in which I find myself understanding the power of local variables or the environment.

Local variables are visible to all subsequently called functions and so reduce the burden to pass a lot of parameters (something which C++ tries to ameliorate with default parameters) or objects of parameter sets.

Local variables are part of the environment exposed to called functions.

C could never really have local variables.


Tuesday 6 March 2012

Update Acer Aspire Bios

The readme file for the Acer Aspire BIOS update requires that FLASHIT.EXE and the BIOS file are copied to a dos-bootable disk.

Well... the Acer Aspire netbook does not have a floppy drive, and who these days can conveniently get a boot image working off USB? I can, but it's too much hassle (it involves loading a file system image as a ramdisk, blah blah boring boring).

But I find that there is a secret BIOS mode that let's the netbook flash it's own BIOS!

http://www.qrpcw.com/2009/01/acer-aspire-one-bios-recovery.html

I quote for posterity's sake:
First format an USB stick with FAT.

Download the latest BIOS, and put both FLASHIT.EXE and the BIOS file in the root directory of the stick. Rename the BIOS file to ZG5IA32.FD, that's important. Do not remove the USB stick.

Turn the AA1 off, make sure both battery and AC adapter are connected. Press Fn+Esc, keep it pressed and press the power button to turn the AA1 on. Release Fn+Esc after a few seconds, the power button will be blinking. Press the power button once. The AA1 will now initiate the BIOS flash, do not interrupt it under any circumstances. After a while the power button will stop blinking, and the AA1 will reboot shortly after. Wait patiently.

The BIOS has been flashed and all settings reset to default.

If for some reason you made a mistake during the procedure and it doesn't reboot by itself wait 5 minutes before turning it off, just to be safe that it isn't still flashing the BIOS.
Also, thanks to http://macles.blogspot.com/2008/08/acer-aspire-one-bios-recovery.html