From: pfitz AT pratique DOT fr (Tony FITZPATRICK) Subject: "info.exe" finally working on W95 11 Mar 1997 18:21:09 -0800 Approved: cygnus DOT gnu-win32 AT cygnus DOT com Distribution: cygnus Message-ID: <199703112040.VAA14334.cygnus.gnu-win32@prat.iway.fr> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" X-Sender: pfitz AT mail DOT pratique DOT fr (Unverified) X-Mailer: Windows Eudora Light Version 1.5.2 Original-To: gnu-win32 AT cygnus DOT com Original-Sender: owner-gnu-win32 AT cygnus DOT com 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 #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 "gnu-win32-request AT cygnus DOT com" with one line of text: "help".