def rb_getstr
      r = @message_row
      c = 0
      win = @window
      @limit = @question.limit
      @history = @question.history
      @history_list = History.new(@history) 
      maxlen = @limit || 100 # fixme


      raise "rb_getstr got no window. bottomline.rb" if win.nil?
      ins_mode = false
      oldstr = nil # for tab completion, origal word entered by user
      default = @default || ""
      $log.debug "XXX: RBGETS got default: #{@default} "
      if @default && @history
        if !@history.include?(default)
          @history_list.push default 
        end
      end

      len = @prompt_length

      # clear the area of len+maxlen
      color = $datacolor
      str = ""
      #str = default
      cpentries = nil
      #clear_line len+maxlen+1
      #print_str(prompt+str)
      print_str(str, :y => @prompt_length+0) if @default
      len = @prompt_length + str.length
      begin
        Ncurses.noecho();
        curpos = str.length
        prevchar = 0
        entries = nil
        while true
          ch=win.getchar()
          $log.debug " XXXX FFI rb_getstr got ch:#{ch}, str:#{str}. "
          case ch
          when 3 # -1 # C-c  # sometimes this causes an interrupt and crash
            return -1, nil
          when ?\C-g.getbyte(0)                              # ABORT, emacs style
            return -1, nil
          when 10, 13 # hits ENTER, complete entry and return
            @history_list.push str
            break
          when ?\C-h.getbyte(0), ?\C-?.getbyte(0), KEY_BSPACE, 263 # delete previous character/backspace
            # C-h is giving 263 i/o 8. 2011-09-19 
            len -= 1 if len > @prompt_length
            curpos -= 1 if curpos > 0
            str.slice!(curpos)
            clear_line len+maxlen+1, @prompt_length
          when 330 # delete character on cursor
            str.slice!(curpos) #rescue next
            clear_line len+maxlen+1, @prompt_length
          when ?\M-h.getbyte(0) #                            HELP KEY
            help_text = @help_text || "No help provided..."
            print_help(help_text) 
            clear_line len+maxlen+1
            print_str @statement # UGH
            #return 7, nil
            #next
          when KEY_LEFT
            curpos -= 1 if curpos > 0
            len -= 1 if len > @prompt_length
            win.move r, c+len # since getchar is not going back on del and bs wmove to move FFIWINDOW
            win.wrefresh
            next
          when KEY_RIGHT
            if curpos < str.length
              curpos += 1 #if curpos < str.length
              len += 1 
              win.move r, c+len # since getchar is not going back on del and bs
              win.wrefresh
            end
            next
          when ?\C-a.getbyte(0)
            #olen = str.length
            clear_line len+maxlen+1, @prompt_length
            len -= curpos
            curpos = 0
            win.move r, c+len # since getchar is not going back on del and bs
          when ?\C-e.getbyte(0)
            olen = str.length
            len += (olen - curpos)
            curpos = olen
            clear_line len+maxlen+1, @prompt_length
            win.move r, c+len # since getchar is not going back on del and bs

          when ?\M-i.getbyte(0) 
            ins_mode = !ins_mode
            next
          when ?\C-k.getbyte(0) # delete forward
            @delete_buffer = str.slice!(curpos..-1) #rescue next
            clear_line len+maxlen+1, @prompt_length
          when ?\C-u.getbyte(0) # delete to the left of cursor till start of line
            @delete_buffer = str.slice!(0..curpos-1) #rescue next
            curpos = 0
            clear_line len+maxlen+1, @prompt_length
            len = @prompt_length
          when ?\C-y.getbyte(0) # paste what's in delete buffer
            if @delete_buffer
              olen = str.length
              str << @delete_buffer if @delete_buffer
              curpos = str.length
              len += str.length - olen
            end
          when KEY_TAB # TAB
            if !@completion_proc.nil?
              # place cursor at end of completion
              # after all completions, what user entered should come back so he can edit it
              if prevchar == 9
                if !entries.nil? and !entries.empty?
                  olen = str.length
                  str = entries.delete_at(0)
                  str = str.to_s.dup
                  #str = entries[@current_index].dup
                  #@current_index += 1
                  #@current_index = 0 if @current_index == entries.length
                  curpos = str.length
                  len += str.length - olen
                  clear_line len+maxlen+1, @prompt_length
                else
                  olen = str.length
                  str = oldstr if oldstr
                  curpos = str.length
                  len += str.length - olen
                  clear_line len+maxlen+1, @prompt_length
                  prevchar = ch = nil # so it can start again completing
                end
              else
                #@current_index = 0
                tabc = @completion_proc unless tabc
                next unless tabc
                oldstr = str.dup
                olen = str.length
                entries = tabc.call(str).dup
                $log.debug "XXX tab [#{str}] got #{entries} "
                str = entries.delete_at(0) unless entries.nil? or entries.empty?
                #str = entries[@current_index].dup unless entries.nil? or entries.empty?
                #@current_index += 1
                #@current_index = 0 if @current_index == entries.length
                str = str.to_s.dup
                if str
                  curpos = str.length
                  len += str.length - olen
                else
                  alert "NO MORE 2"
                end
              end
            else
              # there's another type of completion that bash does, which is irritating
              # compared to what vim does, it does partial completion 
              if cpentries
                olen = str.length
                if cpentries.size == 1
                  str = cpentries.first.dup
                elsif cpentries.size > 1
                  str = shortest_match(cpentries).dup
                end
                curpos = str.length
                len += str.length - olen
              end
            end
          when ?\C-a.getbyte(0) .. ?\C-z.getbyte(0)
            # here' swhere i wish i could pass stuff back without closing
            # I'd like the user to be able to scroll list or do something based on
            # control or other keys
            if @key_handler_proc  # added  2011-11-3 7:38 PM 
              @key_handler_proc.call(ch) 
              next
            else
              Ncurses.beep
            end
          when KEY_UP
            if @history && !@history.empty?
              olen = str.length
              str = if prevchar == KEY_UP
                       @history_list.previous
                     elsif prevchar == KEY_DOWN
                       @history_list.previous
                     else
                       @history_list.last
                     end
              str = str.dup
              curpos = str.length
              len += str.length - olen
              clear_line len+maxlen+1, @prompt_length
            else # try to pick up default, seems we don't get it 2011-10-14 
              if @default
                olen = str.length
                str = @default
                str = str.dup
                curpos = str.length
                len += str.length - olen
                clear_line len+maxlen+1, @prompt_length
              end
            end
          when KEY_DOWN
            if @history && !@history.empty?
              olen = str.length
              str = if prevchar == KEY_UP
                       @history_list.next
                     elsif prevchar == KEY_DOWN
                       @history_list.next
                     else
                       @history_list.first
                     end
              str = str.dup
              curpos = str.length
              len += str.length - olen
              clear_line len+maxlen+1, @prompt_length
            end

          else
            if ch < 0 || ch > 255
              Ncurses.beep
              next
            end
            # if control char, beep
            if ch.chr =~ /[[:cntrl:]]/
              Ncurses.beep
              next
            end
            # we need to trap KEY_LEFT and RIGHT and what of UP for history ?
            if ins_mode
              str[curpos] = ch.chr
            else
              str.insert(curpos, ch.chr) # FIXME index out of range due to changeproc
            end
            len += 1
            curpos += 1
            break if str.length >= maxlen
          end
          case @question.echo
          when true
            begin
              cpentries = @change_proc.call(str) if @change_proc # added 2010-11-09 23:28 
            rescue => exc
              $log.error "bottomline: change_proc EXC #{exc} " if $log.debug? 
              $log.error( exc) if exc
              $log.error(exc.backtrace.join("\n")) if exc
              Ncurses.error
            end
            print_str(str, :y => @prompt_length+0)
          when false
            # noop, no echoing what is typed
          else
            print_str(@question.echo * str.length, :y => @prompt_length+0)
          end
          win.move r, c+len # more for arrow keys, curpos may not be end
          win.wrefresh # 2011-10-10 
          prevchar = ch
        end
              $log.debug "XXXW bottomline: after while loop"

        str = default if str == ""
      ensure
        Ncurses.noecho();
      end
      return 0, str
    end
def rb_getstr
      r = @message_row
      c = 0
      win = @window
      @limit = @question.limit
      @history = @question.history
      @history_list = History.new(@history) 
      maxlen = @limit || 100 # fixme


      raise "rb_getstr got no window. bottomline.rb" if win.nil?
      ins_mode = false
      oldstr = nil # for tab completion, origal word entered by user
      default = @default || ""
      $log.debug "XXX: RBGETS got default: #{@default} "
      if @default && @history
        if !@history.include?(default)
          @history_list.push default 
        end
      end

      len = @prompt_length

      # clear the area of len+maxlen
      color = $datacolor
      str = ""
      #str = default
      cpentries = nil
      #clear_line len+maxlen+1
      #print_str(prompt+str)
      print_str(str, :y => @prompt_length+0) if @default
      len = @prompt_length + str.length
      begin
        Ncurses.noecho();
        curpos = str.length
        prevchar = 0
        entries = nil
        while true
          ch=win.getchar()
          $log.debug " XXXX FFI rb_getstr got ch:#{ch}, str:#{str}. "
          case ch
          when 3 # -1 # C-c  # sometimes this causes an interrupt and crash
            return -1, nil
          when ?\C-g.getbyte(0)                              # ABORT, emacs style
            return -1, nil
          when 10, 13 # hits ENTER, complete entry and return
            @history_list.push str
            break
          when ?\C-h.getbyte(0), ?\C-?.getbyte(0), KEY_BSPACE, 263 # delete previous character/backspace
            # C-h is giving 263 i/o 8. 2011-09-19 
            len -= 1 if len > @prompt_length
            curpos -= 1 if curpos > 0
            str.slice!(curpos)
            clear_line len+maxlen+1, @prompt_length
          when 330 # delete character on cursor
            str.slice!(curpos) #rescue next
            clear_line len+maxlen+1, @prompt_length
          when ?\M-h.getbyte(0) #                            HELP KEY
            help_text = @help_text || "No help provided..."
            print_help(help_text) 
            clear_line len+maxlen+1
            print_str @statement # UGH
            #return 7, nil
            #next
          when KEY_LEFT
            curpos -= 1 if curpos > 0
            len -= 1 if len > @prompt_length
            win.move r, c+len # since getchar is not going back on del and bs wmove to move FFIWINDOW
            win.wrefresh
            next
          when KEY_RIGHT
            if curpos < str.length
              curpos += 1 #if curpos < str.length
              len += 1 
              win.move r, c+len # since getchar is not going back on del and bs
              win.wrefresh
            end
            next
          when ?\C-a.getbyte(0)
            #olen = str.length
            clear_line len+maxlen+1, @prompt_length
            len -= curpos
            curpos = 0
            win.move r, c+len # since getchar is not going back on del and bs
          when ?\C-e.getbyte(0)
            olen = str.length
            len += (olen - curpos)
            curpos = olen
            clear_line len+maxlen+1, @prompt_length
            win.move r, c+len # since getchar is not going back on del and bs

          when ?\M-i.getbyte(0) 
            ins_mode = !ins_mode
            next
          when ?\C-k.getbyte(0) # delete forward
            @delete_buffer = str.slice!(curpos..-1) #rescue next
            clear_line len+maxlen+1, @prompt_length
          when ?\C-u.getbyte(0) # delete to the left of cursor till start of line
            @delete_buffer = str.slice!(0..curpos-1) #rescue next
            curpos = 0
            clear_line len+maxlen+1, @prompt_length
            len = @prompt_length
          when ?\C-y.getbyte(0) # paste what's in delete buffer
            if @delete_buffer
              olen = str.length
              str << @delete_buffer if @delete_buffer
              curpos = str.length
              len += str.length - olen
            end
          when KEY_TAB # TAB
            if !@completion_proc.nil?
              # place cursor at end of completion
              # after all completions, what user entered should come back so he can edit it
              if prevchar == 9
                if !entries.nil? and !entries.empty?
                  olen = str.length
                  str = entries.delete_at(0)
                  str = str.to_s.dup
                  #str = entries[@current_index].dup
                  #@current_index += 1
                  #@current_index = 0 if @current_index == entries.length
                  curpos = str.length
                  len += str.length - olen
                  clear_line len+maxlen+1, @prompt_length
                else
                  olen = str.length
                  str = oldstr if oldstr
                  curpos = str.length
                  len += str.length - olen
                  clear_line len+maxlen+1, @prompt_length
                  prevchar = ch = nil # so it can start again completing
                end
              else
                #@current_index = 0
                tabc = @completion_proc unless tabc
                next unless tabc
                oldstr = str.dup
                olen = str.length
                entries = tabc.call(str).dup
                $log.debug "XXX tab [#{str}] got #{entries} "
                str = entries.delete_at(0) unless entries.nil? or entries.empty?
                #str = entries[@current_index].dup unless entries.nil? or entries.empty?
                #@current_index += 1
                #@current_index = 0 if @current_index == entries.length
                str = str.to_s.dup
                if str
                  curpos = str.length
                  len += str.length - olen
                else
                  alert "NO MORE 2"
                end
              end
            else
              # there's another type of completion that bash does, which is irritating
              # compared to what vim does, it does partial completion 
              if cpentries
                olen = str.length
                if cpentries.size == 1
                  str = cpentries.first.dup
                elsif cpentries.size > 1
                  str = shortest_match(cpentries).dup
                end
                curpos = str.length
                len += str.length - olen
              end
            end
          when ?\C-a.getbyte(0) .. ?\C-z.getbyte(0)
            # here' swhere i wish i could pass stuff back without closing
            # I'd like the user to be able to scroll list or do something based on
            # control or other keys
            if @key_handler_proc  # added  2011-11-3 7:38 PM 
              @key_handler_proc.call(ch) 
              next
            else
              Ncurses.beep
            end
          when KEY_UP
            if @history && !@history.empty?
              olen = str.length
              str = if prevchar == KEY_UP
                       @history_list.previous
                     elsif prevchar == KEY_DOWN
                       @history_list.previous
                     else
                       @history_list.last
                     end
              str = str.dup
              curpos = str.length
              len += str.length - olen
              clear_line len+maxlen+1, @prompt_length
            else # try to pick up default, seems we don't get it 2011-10-14 
              if @default
                olen = str.length
                str = @default
                str = str.dup
                curpos = str.length
                len += str.length - olen
                clear_line len+maxlen+1, @prompt_length
              end
            end
          when KEY_DOWN
            if @history && !@history.empty?
              olen = str.length
              str = if prevchar == KEY_UP
                       @history_list.next
                     elsif prevchar == KEY_DOWN
                       @history_list.next
                     else
                       @history_list.first
                     end
              str = str.dup
              curpos = str.length
              len += str.length - olen
              clear_line len+maxlen+1, @prompt_length
            end

          else
            if ch < 0 || ch > 255
              Ncurses.beep
              next
            end
            # if control char, beep
            if ch.chr =~ /[[:cntrl:]]/
              Ncurses.beep
              next
            end
            # we need to trap KEY_LEFT and RIGHT and what of UP for history ?
            if ins_mode
              str[curpos] = ch.chr
            else
              str.insert(curpos, ch.chr) # FIXME index out of range due to changeproc
            end
            len += 1
            curpos += 1
            break if str.length >= maxlen
          end
          case @question.echo
          when true
            begin
              cpentries = @change_proc.call(str) if @change_proc # added 2010-11-09 23:28 
            rescue => exc
              $log.error "bottomline: change_proc EXC #{exc} " if $log.debug? 
              $log.error( exc) if exc
              $log.error(exc.backtrace.join("\n")) if exc
              Ncurses.error
            end
            print_str(str, :y => @prompt_length+0)
          when false
            # noop, no echoing what is typed
          else
            print_str(@question.echo * str.length, :y => @prompt_length+0)
          end
          win.move r, c+len # more for arrow keys, curpos may not be end
          win.wrefresh # 2011-10-10 
          prevchar = ch
        end
              $log.debug "XXXW bottomline: after while loop"

        str = default if str == ""
      ensure
        Ncurses.noecho();
      end
      return 0, str
    end
actual input routine, gets each character from user, taking care of echo, limit,
 completion proc, and some control characters such as C-a, C-e, C-k
 Taken from io.rb, has some improvements to it. However, does not print the prompt
 any longer
 Completion proc is vim style, on pressing tab it cycles through options