Patch title: Release 91 bulk changes
Abstract:
File: /protocol/lpr/device.pli
Key:
    Removed line
    Added line
module "/pliant/language/context.pli"
module "/pliant/language/compiler.pli"
module "/pliant/language/stream.pli"

if os_api="linux"
  module "/pliant/fullpliant/this_computer.pli"
  module "/pliant/language/unsafe.pli"
  module "/pliant/admin/execute.pli"
  module "/pliant/linux/kernel/module.pli"
  module "/pliant/admin/file.pli"
  module "/pliant/linux/storage/filesystem.pli"
  module "/pliant/linux/kernel/device.pli"
  module "/pliant/language/os.pli"

  gvar Sem sem
  gvar (Dictionary Str Void) devices
  
  function lpr_device_init device
    arg Str device
    sem request
    if not exists:(devices first device)
      if (device parse "device:/lp" (var Int num))
        execute "insmod parport" quiet
        execute "insmod parport_pc" quiet
        execute "insmod lp" quiet
        kernel_load_module "parport"
        kernel_load_module "parport_pc"
        kernel_load_module "lp"
        kernel_make_device device
      eif (device parse "device:/usb/lp" (var Int num))
        execute "insmod usbcore" quiet
        var Str module := this_computer:env:"hardware":"usb":"module"
        if module=""
          module := "usb-uhci"
        execute "insmod "+module quiet
        execute "insmod printer" quiet
        kernel_load_module "usbcore"
        kernel_load_module "usb-uhci" # 2.4
        kernel_load_module "usb-ohci" # 2.4
        kernel_load_module "ehci-hcd" # 2.4
        kernel_load_module "uhci_hcd" # 2.6
        kernel_load_module "ohci_hcd" # 2.6
        kernel_load_module "ehci_hcd" # 2.6
        kernel_load_module "printer" # 2.4
        kernel_load_module "usblp" # 2.6
        filesystem_mount "file:usb" "file:/proc/bus/usb/" "filesystem [dq]usbdevfs[dq]"
        file_tree_create "device:/usb/"
        kernel_make_device device kernel_character_device 180 num
        sleep 2 # USB device is not available immediately
      eif (device parse any:(var Str protocol) ":" any) and (protocol="lpr" or protocol="lprng" or protocol="ftp" or protocol="http")
        pliant_compiler_semaphore request
        pliant_load_module "/pliant/protocol/"+(replace protocol "lprng" "lpr")+"/client.pli" the_module:"/pliant/language/basic/safe.pli" 0 (null map Module)
        pliant_compiler_semaphore release
      devices insert device void
    sem release

  function os_ioctl_read handle query length -> answer
    arg Int handle query ; arg Int query length ; arg Str answer
    var uInt cmd := 2*2^30+(cast length uInt)*2^16+"P":number*2^8+query
    answer set (memory_allocate length addressof:answer) length true
    var Int l := os_ioctl handle cmd answer:characters
    if l<0
      answer := ""
  
  function device_info handle -> answer
    arg Int handle ; arg Str answer
    answer := os_ioctl_read handle 1 8192
    if answer:len<2
      answer := ""
    else
      answer := answer 2 (answer:characters map uInt16_hi)
  
  function device_usb_bus handle bus device
    arg Int handle ; arg_w Int bus device
    var Str answer := os_ioctl_read handle 5 2*Int:size
    if answer:len=2*Int:size
      bus := answer:characters map Int
      device := answer:characters map Int 1
    else
      bus := undefined ; device := undefined
  
  function device_field devicename id1 id2 -> answer
    arg Str devicename ; arg Str id1 id2 answer
    lpr_device_init devicename
    (var Stream s) open devicename in+safe
    if s=failure
      return ""
    if not (";"+(device_info s:stream_handle)+";" parse any (pattern ";"+id1+":") any:answer ";" any)
      answer := ""
      device_usb_bus s:stream_handle (var Int bus) (var Int device)
      (var Stream s) open "file:/proc/bus/usb/devices" in+safe
      var CBool selected := true
      while not s:atend
        var Str l := s readline
        if (l 0 2)="T:"
          selected := (l parse any "Bus=" (var Int l_bus) any "Dev#=" (var Int l_device) any) and l_bus=bus and l_device=device
        eif selected and (l 0 2)="S:"
          if (l parse "S:" word:id2 "=" any:(var Str v))
            answer := v

else

  function lpr_device_init device
    arg Str device

  function device_field devicename id1 id2 -> answer
    arg Str devicename ; arg Str id1 id2 answer
    answer := ""


function lpr_device_model devicename -> model
  arg Str devicename ; arg Str model
  model := device_field devicename "MDL" "none"

function lpr_device_sn devicename -> sn
  arg Str devicename ; arg Str sn
  sn := device_field devicename "SERN" "SerialNumber"

function lpr_device_search id -> devicename
  arg Str id ; arg Str devicename
  if (id parse "printer_sn:" any:(var Str sn))
    for (var Int i) 0 15
      devicename := "device:/usb/lp"+string:i
      if lpr_device_sn:devicename=sn
        return
  lpr_device_init id
  devicename := id

export lpr_device_model lpr_device_sn lpr_device_search