Subject: "info.exe" finally working on W95
From: [email-masked] (Tony FITZPATRICK)

11 Mar 1997 18:21:09 -0800
Approved: [email-masked]
Distribution: cygnus
Message-ID: <[email-masked]>
Mime-Version: 1.0
Content-Type: text/plain; charset="us-ascii"
X-Sender: [email-masked] (Unverified)
X-Mailer: Windows Eudora Light Version 1.5.2
Original-To: [email-masked]
Original-Sender: [email-masked]

Hi
        Dogged persistance has finally paid off and I have now got the stand
alone info reader "info.exe" running on W95 under cygwin. What I had to do
is more "proof of concept" than a definitive solution and I would appreciate
it if any of you C++ experts out there could tell me how I should be doing
it. I have never written any C++ code in my life and my normal C is a lot
rusty so go easy on me please. I didn't have to modify "info" at all to get
it working only cygwin.dll.

There are two major difficulties. 1) the state of console support in
fhandler.cc and 2) the non existance of support for non blocking console
input. I'll start with 2).

2) info.exe uses the "fcntl" function and the O_NDELAY attribute to request
non blocking reads on the ConsoleInput buffer. W95 does not appear to
provide non blocking i/o and the "fcntl" function in "fcntl.cc" only
concerns itself with what W95 (and I suppose NT but I have no way of
checking) can provide. The flag O_NDELAY is simply ignored. To provide the
information to "fhandler.cc" I simply created a variable in "fcntl.cc" which
I set if O_NDELAY is programmed and reset if it isn't. I declared the
variable as external in "fcntl.h" and that was all. (N.B. I have 9 files
called "fcntl.h" installed, the one I modified was in
"...cdk/winsup/include" and it now looks like this.

#include <sys/fcntl.h>
#define O_NDELAY	_FNDELAY
extern int ndelay_set;

I know there must be a better way of doing this, I only take O_NDELAY into
account if the call is flagged with the F_SETFL attribute and I don't return
it if "fcntl" is called with F_GETFL. As fhandler.cc can now simulate the
action of O_NDELAY it would be better to return it as well. I suspect this
kind of stuff should be stored in the "fd"  but I don't know where, any ideas?

1) "fhandler.cc", all the modifications I had to make to this file are in
the function "FakeReadFile". (This function must take the prize for the most
modified function in b17.) There are two previously posted modifications to
FakeReadFile from the mailing list and both of them need to be installed
(many thanks for those). I have marked all changed areas in the following
listing (sorry about the format, I'll do a proper diff against b17 for the
definitive modifs). There is nothing after the listing so you can stop here
if you want.

I'm sure that what I have done is not good programming practice and a long
way from the spirit of C++ so any help in doing it properly would be much
appreciated. TIA Tony  

static int
FakeReadFile (HANDLE hndl, void* pv, size_t lenin, unsigned int* done, 
			 OVERLAPPED *ov)
{
  DWORD flags;
  int res;
  int need_chars = 1;
  int copied_chars = 0;
  char *buf;

  res = GetConsoleMode (hndl, &flags);
 
  debug_printf("FakeReadFile, res = %d, flags = %x\n", res, flags);

  /* if things are special, just do what we used to */
>>  if ((!res) || (ov != 0))
>>       {
>>          return ReadFile (hndl, pv, lenin, done, ov);
>>       }
>>   if (flags & ENABLE_LINE_INPUT) 
>>        { /* I know this is just treating the symptoms */
>>	   FlushConsoleInputBuffer(hndl);
>>           return ReadFile (hndl, pv, lenin, done, ov);
>>	}
  /* otherwise, do something that works */
  unsigned int num_events = 0, ne2, st;

>>          if (ndelay_set == 1) 
>>            need_chars = 0;

  st = GetNumberOfConsoleInputEvents (hndl, &num_events);

  debug_printf("FakeReadFile, GetNumberOfConsoleInputEvents returned =
%d\n", st);

  if (!st)
    {
      /* it failed, we're confused */
      return 0;			/* seems to be failure */
    }
  if (num_events == 0)
    {
      select_printf ("fhandler_console::FakeReadFile: gnocie found no
events\n");
      /* so are we blocking or what? FIONBIO isn't implemented... */
      /* either spin here and read at least one thing, return none... */
      /* readfile blocks already, so we probably can't do worse... */
>>          if (ndelay_set == 1)
>>           { 
>>            need_chars = 0;
>>           }
>>          else
            need_chars = 1;

    } 

  INPUT_RECORD input_rec;
  
  buf = (char*)pv;
  while (need_chars || num_events)
    {
      st = ReadConsoleInput (hndl, &input_rec, 1, &ne2);
      if (!st)
        {
          /* it failed, we're confused */
          return 0;		/* seems to be failure */
        }
      /* doc says it will return at least one event... */
>>      if(num_events)
>>	  num_events--;
      /* check if we're just disposing of this one */

      if (input_rec.EventType != KEY_EVENT)
        continue;
      if (input_rec.Event.KeyEvent.bKeyDown == 0)
        continue;

      if (input_rec.Event.KeyEvent.AsciiChar == 0)  /* arrow/function keys */
        {
          static struct {
            int vk;
            char *val;
          } keytable[] = {
            VK_LEFT,    "\033[D",
            VK_RIGHT,   "\033[C",
            VK_UP,      "\033[A",
            VK_DOWN,    "\033[B",
            VK_PRIOR,   "\033[5~",
            VK_NEXT,    "\033[6~",
            VK_HOME,    "\033[1~",
            VK_END,     "\033[4~",
            VK_INSERT,  "\033[2~",
            VK_DELETE,  "\033[3~",
            VK_F1,      "\0331",
            VK_F2,      "\0332",
            VK_F3,      "\0333",
            VK_F4,      "\0334",
            VK_F5,      "\0335",
            VK_F6,      "\0336",
            VK_F7,      "\0337",
            VK_F8,      "\0338",
            VK_F9,      "\0339",
            VK_F10,     "\0330",
            0,          ""
          };
          char *ptr=NULL;
          int i;

          for(i=0; keytable[i].vk; i++)
            if(input_rec.Event.KeyEvent.wVirtualKeyCode == keytable[i].vk) {
              ptr = keytable[i].val;
                break;
            }
          if(!ptr)
            continue;
          buf[copied_chars++] = *ptr++;
          while(*ptr)
            {
              input_rec.Event.KeyEvent.AsciiChar = *ptr++;
              WriteConsoleInput (hndl, &input_rec, 1, &ne2);
            }
        }
    else /* keep it */
      {
        buf[copied_chars++] = input_rec.Event.KeyEvent.AsciiChar;
      }
      if (copied_chars >= lenin)
        {
          /* we got all we could handle */
          num_events = 0;
        }
      need_chars = 0;    
   }
  *done = copied_chars;

>>      /* If we haven't got anything of interest and we don't want to wait for
>>         anything (O_NDELAY is set) force the calling read to error (ret 0) */
>>
>>  if (copied_chars == 0 && need_chars == 0)
>>    {
>>      return 0;
>>    }
>>  else
>>    {
>>      return 1;			/* success == true */
>>    }
}

-
For help on using this list, send a message to
"[email-masked]" with one line of text: "help".