1 /* This file is part of Netwib. Read and honor its license.
2 */
3
4 /*-------------------------------------------------------------*/
netwib_priv_kbd_init_fd(int fd,netwib_priv_kbd * pkbd)5 netwib_err netwib_priv_kbd_init_fd(int fd,
6 netwib_priv_kbd *pkbd)
7 #if defined NETWIBDEF_SYSNAME_Unix
8 {
9 struct termios thetermios;
10
11 pkbd->fd = fd;
12
13 /* check if it's a tty */
14 pkbd->type = NETWIB_PRIV_KBDTYPE_UNKNOWN;
15 pkbd->consoleecho = NETWIB_FALSE;
16 pkbd->consolereadbyline = NETWIB_FALSE;
17 if (isatty(fd)) {
18 pkbd->type = NETWIB_PRIV_KBDTYPE_CONSOLE;
19 /* check if characters are echoed */
20 if (tcgetattr(fd, &thetermios)) {
21 return(NETWIB_ERR_FUTCGETATTR);
22 }
23 if (thetermios.c_lflag & ECHO) {
24 pkbd->consoleecho = NETWIB_TRUE;
25 }
26 if (thetermios.c_lflag & ICANON) {
27 pkbd->consolereadbyline = NETWIB_TRUE;
28 }
29 }
30
31 pkbd->originalconsoleecho = pkbd->consoleecho;
32 pkbd->originalconsolereadbyline = pkbd->consolereadbyline;
33
34 pkbd->availdata = NETWIB_FALSE;
35
36 return(NETWIB_ERR_OK);
37 }
38 #elif defined NETWIBDEF_SYSNAME_Windows
39 {
40 pkbd = pkbd; /* for compiler warning */
41 fd = fd; /* for compiler warning */
42 return(NETWIB_ERR_LONOTIMPLEMENTED);
43 }
44 #else
45 #error "Unknown value for NETWIBDEF_SYSNAME"
46 #endif
47 /*-------------------------------------------------------------*/
netwib_priv_kbd_init_handle(NETWIBHANDLE h,netwib_priv_kbd * pkbd)48 netwib_err netwib_priv_kbd_init_handle(NETWIBHANDLE h,
49 netwib_priv_kbd *pkbd)
50 #if defined NETWIBDEF_SYSNAME_Unix
51 {
52 pkbd = pkbd; /* for compiler warning */
53 h = h; /* for compiler warning */
54 return(NETWIB_ERR_LONOTIMPLEMENTED);
55 }
56 #elif defined NETWIBDEF_SYSNAME_Windows
57 {
58 DWORD ftype, conmode;
59 BOOL err;
60
61 pkbd->h = h;
62
63 /* check if it's a tty */
64 pkbd->type = NETWIB_PRIV_KBDTYPE_UNKNOWN;
65 ftype = GetFileType(h);
66 if (ftype == FILE_TYPE_CHAR) {
67 pkbd->type = NETWIB_PRIV_KBDTYPE_CONSOLE;
68 } else if (ftype == FILE_TYPE_DISK) {
69 pkbd->type = NETWIB_PRIV_KBDTYPE_FILE;
70 } else if (ftype == FILE_TYPE_PIPE) {
71 pkbd->type = NETWIB_PRIV_KBDTYPE_PIPE;
72 }
73
74 pkbd->availdata = NETWIB_FALSE;
75
76 /* check if characters are echoed */
77 pkbd->consoleecho = NETWIB_TRUE;
78 if (pkbd->type == NETWIB_PRIV_KBDTYPE_CONSOLE) {
79 err = GetConsoleMode(h, &conmode);
80 if (!err) return(NETWIB_ERR_FUGETCONSOLEMODE);
81 if (!(conmode & ENABLE_ECHO_INPUT)) {
82 pkbd->consoleecho = NETWIB_FALSE;
83 }
84 }
85
86 /* default behavior is to read line by line */
87 pkbd->consolereadbyline = NETWIB_TRUE;
88
89 pkbd->originalconsoleecho = pkbd->consoleecho;
90 pkbd->originalconsolereadbyline = pkbd->consolereadbyline;
91
92 return(NETWIB_ERR_OK);
93 }
94 #else
95 #error "Unknown value for NETWIBDEF_SYSNAME"
96 #endif
97
98 /*-------------------------------------------------------------*/
netwib_priv_kbd_initdefault(netwib_priv_kbd * pkbd)99 netwib_err netwib_priv_kbd_initdefault(netwib_priv_kbd *pkbd)
100 {
101 #if defined NETWIBDEF_SYSNAME_Unix
102 return(netwib_priv_kbd_init_fd(0, pkbd));
103 #elif defined NETWIBDEF_SYSNAME_Windows
104 return(netwib_priv_kbd_init_handle(GetStdHandle(STD_INPUT_HANDLE), pkbd));
105 #else
106 #error "Unknown value for NETWIBDEF_SYSNAME"
107 #endif
108 }
109
110 /*-------------------------------------------------------------*/
netwib_priv_kbd_close(netwib_priv_kbd * pkbd)111 netwib_err netwib_priv_kbd_close(netwib_priv_kbd *pkbd)
112 {
113 netwib_er(netwib_priv_kbd_ctl_set_echoline(pkbd,
114 pkbd->originalconsoleecho,
115 pkbd->originalconsolereadbyline));
116 return(NETWIB_ERR_OK);
117 }
118
119 /*-------------------------------------------------------------*/
netwib_priv_kbd_ctl_set_purge(netwib_priv_kbd * pkbd)120 netwib_err netwib_priv_kbd_ctl_set_purge(netwib_priv_kbd *pkbd)
121 {
122 if (pkbd->type == NETWIB_PRIV_KBDTYPE_CONSOLE) {
123 #if defined NETWIBDEF_SYSNAME_Unix
124 struct termios old_termios;
125 if (tcgetattr(pkbd->fd, &old_termios)) {
126 return(NETWIB_ERR_FUTCGETATTR);
127 }
128 /* we use TCSAFLUSH which discards all input */
129 if (tcsetattr(pkbd->fd, TCSAFLUSH, &old_termios)) {
130 return(NETWIB_ERR_FUTCSETATTR);
131 }
132 #if 0
133 /* this works under Linux, Solaris, but not FreeBSD or OpenBSD (it
134 perturbs next calls) */
135 /* Note for next implementation : we can also use tcflush() */
136 struct termios old_termios, new_termios;
137 int c;
138
139 /* ensure we read char by char (instead of line by line) */
140 if (tcgetattr(pkbd->fd, &old_termios)) {
141 return(NETWIB_ERR_FUTCGETATTR);
142 }
143 new_termios = old_termios;
144 new_termios.c_lflag &= (~ICANON);
145 new_termios.c_cc[VMIN] = 0;
146 new_termios.c_cc[VTIME] = 0;
147 if (tcsetattr(pkbd->fd, TCSANOW, &new_termios)) {
148 return(NETWIB_ERR_FUTCSETATTR);
149 }
150
151 do {
152 c = getchar();
153 } while (c != EOF);
154
155 /* reset */
156 if (tcsetattr(pkbd->fd, TCSANOW, &old_termios)) {
157 return(NETWIB_ERR_FUTCSETATTR);
158 }
159 #endif
160 #elif defined NETWIBDEF_SYSNAME_Windows
161 while (_kbhit()) {
162 _getch();
163 }
164 #else
165 #error "Unknown value for NETWIBDEF_SYSNAME"
166 #endif
167 }
168
169 pkbd->availdata = NETWIB_FALSE;
170
171 return(NETWIB_ERR_OK);
172 }
173
174 /*-------------------------------------------------------------*/
netwib_priv_kbd_ctl_set_echoline(netwib_priv_kbd * pkbd,netwib_bool consoleecho,netwib_bool consolereadbyline)175 netwib_err netwib_priv_kbd_ctl_set_echoline(netwib_priv_kbd *pkbd,
176 netwib_bool consoleecho,
177 netwib_bool consolereadbyline)
178 #if defined NETWIBDEF_SYSNAME_Unix
179 {
180 struct termios thetermios;
181
182 /* change mode */
183 if (pkbd->type == NETWIB_PRIV_KBDTYPE_CONSOLE) {
184 if (tcgetattr(pkbd->fd, &thetermios)) {
185 return(NETWIB_ERR_FUTCGETATTR);
186 }
187 if (consoleecho) {
188 thetermios.c_lflag |= ECHO;
189 } else {
190 thetermios.c_lflag &= ~ECHO;
191 }
192 if (consolereadbyline) {
193 thetermios.c_lflag |= ICANON;
194 } else {
195 thetermios.c_lflag &= (~ICANON);
196 thetermios.c_cc[VMIN] = 1; /* need one char */
197 thetermios.c_cc[VTIME] = 0; /* wait forever */
198 }
199 if (tcsetattr(pkbd->fd, TCSANOW, &thetermios)) {
200 return(NETWIB_ERR_FUTCSETATTR);
201 }
202 }
203
204 /* store them */
205 pkbd->consoleecho = consoleecho;
206 pkbd->consolereadbyline = consolereadbyline;
207
208 return(NETWIB_ERR_OK);
209 }
210 #elif defined NETWIBDEF_SYSNAME_Windows
211 {
212 /* we cannot change. We'll then use getch/getche */
213
214 /* store them */
215 pkbd->consoleecho = consoleecho;
216 pkbd->consolereadbyline = consolereadbyline;
217
218 return(NETWIB_ERR_OK);
219 }
220 #else
221 #error "Unknown value for NETWIBDEF_SYSNAME"
222 #endif
223
224 /*-------------------------------------------------------------*/
netwib_priv_kbd_press(netwib_priv_kbd * pkbd,netwib_char * pc)225 netwib_err netwib_priv_kbd_press(netwib_priv_kbd *pkbd,
226 netwib_char *pc)
227 #if defined NETWIBDEF_SYSNAME_Unix
228 {
229 netwib_bool consoleecho, consolereadbyline;
230
231 netwib_er(netwib_priv_kbd_ctl_set_purge(pkbd));
232 consoleecho = pkbd->consoleecho;
233 consolereadbyline = pkbd->consolereadbyline;
234 netwib_er(netwib_priv_kbd_ctl_set_echoline(pkbd, NETWIB_FALSE,
235 NETWIB_FALSE));
236 netwib_er(netwib_priv_kbd_read_key(pkbd, pc));
237 netwib_er(netwib_priv_kbd_ctl_set_echoline(pkbd, consoleecho,
238 consolereadbyline));
239
240 return(NETWIB_ERR_OK);
241 }
242 #elif defined NETWIBDEF_SYSNAME_Windows
243 {
244 netwib_byte c;
245 netwib_err ret;
246 BOOL err;
247
248 netwib_er(netwib_priv_kbd_ctl_set_purge(pkbd));
249
250 /* cases which cannot be treated here */
251 if (pkbd->type != NETWIB_PRIV_KBDTYPE_CONSOLE) {
252 ret = netwib_priv_kbd_read_key(pkbd, pc);
253 return(ret);
254 }
255
256 c = (netwib_byte) _getch();
257 if (c == 0x00) {
258 /* on Function-i, get the second part */
259 _getch();
260 } else if (c == 0xE0) {
261 /* arrow key, but get the second part */
262 _getch();
263 } else if (c == 0x03) {
264 /* on control-c, generate the event (then the program should exit) */
265 err = GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
266 if (!err) {
267 return(NETWIB_ERR_FUGENERATECONSOLECTRLEVENT);
268 }
269 }
270 if (pc != NULL) *pc = c;
271
272 return(NETWIB_ERR_OK);
273 }
274 #else
275 #error "Unknown value for NETWIBDEF_SYSNAME"
276 #endif
277
278 /*-------------------------------------------------------------*/
netwib_priv_kbd_read_key_pipe(netwib_priv_kbd * pkbd,netwib_char * pc)279 static netwib_err netwib_priv_kbd_read_key_pipe(netwib_priv_kbd *pkbd,
280 netwib_char *pc)
281 {
282 #if defined NETWIBDEF_SYSNAME_Unix
283 return(netwib_priv_fd_read_byte(pkbd->fd, (netwib_byte*)pc));
284 #elif defined NETWIBDEF_SYSNAME_Windows
285 return(netwib_priv_handle_read_byte(pkbd->h, (netwib_byte*)pc));
286 #else
287 #error "Unknown value for NETWIBDEF_SYSNAME"
288 #endif
289 }
290
291 /*-------------------------------------------------------------*/
netwib_priv_kbd_read_key(netwib_priv_kbd * pkbd,netwib_char * pc)292 netwib_err netwib_priv_kbd_read_key(netwib_priv_kbd *pkbd,
293 netwib_char *pc)
294 #if defined NETWIBDEF_SYSNAME_Unix
295 {
296 netwib_char c;
297
298 /* cases which cannot be treated here */
299 if (pkbd->type != NETWIB_PRIV_KBDTYPE_CONSOLE || pkbd->fd != 0) {
300 return(netwib_priv_kbd_read_key_pipe(pkbd, pc));
301 }
302
303 /* read */
304 c = (netwib_char)fgetc(stdin);
305
306 if (pc != NULL) *pc = c;
307 return(NETWIB_ERR_OK);
308 }
309 #elif defined NETWIBDEF_SYSNAME_Windows
310 {
311 netwib_byte c;
312 BOOL err;
313
314 /* cases which cannot be treated here */
315 if (pkbd->type != NETWIB_PRIV_KBDTYPE_CONSOLE) {
316 return(netwib_priv_kbd_read_key_pipe(pkbd, pc));
317 }
318
319 c = 0;
320 while (NETWIB_TRUE) {
321 c = (netwib_byte)_getch();
322 if (c == 0x08) {
323 /* ignore backspace */
324 } else if (c == 0x00) {
325 /* ignore Function-i, but get the second part */
326 _getch();
327 } else if (c == 0xE0) {
328 /* ignore arrow, but get the second part */
329 _getch();
330 } else if (c == 0x03) {
331 /* on control-c, generate the event (then the program should exit) */
332 err = GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
333 if (!err) {
334 return(NETWIB_ERR_FUGENERATECONSOLECTRLEVENT);
335 }
336 } else {
337 /* ok */
338 break;
339 }
340 }
341
342 if (pkbd->consoleecho) {
343 /* display pressed key */
344 if (c == 0x0D) {
345 /* because the newline is suppressed */
346 putchar(0x0D);
347 putchar(0x0A);
348 } else {
349 putchar(c);
350 }
351 }
352
353 if (pc != NULL) *pc = c;
354 return(NETWIB_ERR_OK);
355 }
356 #else
357 #error "Unknown value for NETWIBDEF_SYSNAME"
358 #endif
359
360 /*-------------------------------------------------------------*/
netwib_priv_kbd_read_line_pipe(netwib_priv_kbd * pkbd,netwib_buf * pbuf)361 static netwib_err netwib_priv_kbd_read_line_pipe(netwib_priv_kbd *pkbd,
362 netwib_buf *pbuf)
363 {
364 netwib_char c;
365
366 while(NETWIB_TRUE) {
367 netwib_er(netwib_priv_kbd_read_key(pkbd, &c));
368 if (c == '\n') break;
369 netwib_er(netwib_buf_append_byte(c, pbuf));
370 }
371
372 return(NETWIB_ERR_OK);
373 }
374
375 /*-------------------------------------------------------------*/
netwib_priv_kbd_read_line(netwib_priv_kbd * pkbd,netwib_buf * pbuf)376 netwib_err netwib_priv_kbd_read_line(netwib_priv_kbd *pkbd,
377 netwib_buf *pbuf)
378 #if defined NETWIBDEF_SYSNAME_Unix
379 {
380 int c;
381 netwib_err ret;
382
383 /* cases which cannot be treated here */
384 if (pkbd->type != NETWIB_PRIV_KBDTYPE_CONSOLE || pkbd->fd != 0) {
385 return(netwib_priv_kbd_read_line_pipe(pkbd, pbuf));
386 }
387
388 ret = NETWIB_ERR_OK;
389 while (NETWIB_TRUE) {
390 c = getc(stdin);
391 if (c == 0x0D || c == 0x0A || c == EOF) {
392 break;
393 }
394 ret = netwib_buf_append_byte(c, pbuf);
395 if (ret != NETWIB_ERR_OK) {
396 break;
397 }
398 }
399 if (!pkbd->consoleecho) {
400 puts("");
401 }
402
403 return(NETWIB_ERR_OK);
404 }
405 #elif defined NETWIBDEF_SYSNAME_Windows
406 {
407 netwib_uint32 userstringsize;
408 int c;
409 BOOL err;
410
411 /* cases which cannot be treated here */
412 if (pkbd->type != NETWIB_PRIV_KBDTYPE_CONSOLE) {
413 return(netwib_priv_kbd_read_line_pipe(pkbd, pbuf));
414 }
415
416 userstringsize = 0;
417 while (NETWIB_TRUE) {
418 /* cannot use getche because backspace can erase data
419 printed before calling the function */
420 c = _getch();
421 if (c == 0x0D || c == 0x0A) {
422 if (pkbd->consoleecho) {
423 putchar(0x0D);
424 putchar(0x0A);
425 }
426 break;
427 } else if (c == 0x08) {
428 /* backspace */
429 if (userstringsize) {
430 userstringsize--;
431 pbuf->endoffset--;
432 if (pkbd->consoleecho) {
433 putchar(0x08);
434 putchar(' ');
435 putchar(0x08);
436 }
437 }
438 } else if (c == 0x00) {
439 /* Function-i ignore, but get the second part */
440 _getch();
441 } else if (c == 0xE0) {
442 /* ignore arrow, but get the second part */
443 _getch();
444 } else if (c == 0x03) {
445 /* on control-c, generate the event (then the program should exit) */
446 err = GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
447 if (!err) {
448 return(NETWIB_ERR_FUGENERATECONSOLECTRLEVENT);
449 }
450 } else {
451 netwib_er(netwib_buf_append_byte((netwib_char)c, pbuf));
452 userstringsize++;
453 if (pkbd->consoleecho) {
454 putchar(c);
455 }
456 }
457 }
458 if (!pkbd->consoleecho) {
459 puts("");
460 }
461
462 return(NETWIB_ERR_OK);
463 }
464 #else
465 #error "Unknown value for NETWIBDEF_SYSNAME"
466 #endif
467
468 /*-------------------------------------------------------------*/
netwib_priv_kbd_wait(netwib_priv_kbd * pkbd,netwib_consttime * pabstime,netwib_bool * pevent)469 netwib_err netwib_priv_kbd_wait(netwib_priv_kbd *pkbd,
470 netwib_consttime *pabstime,
471 netwib_bool *pevent)
472 #if defined NETWIBDEF_SYSNAME_Unix
473 {
474 netwib_bool event;
475
476 /* unfortunately, Linux does not detect a line twice, so we have
477 to keep state. This state is reset when we purge or read. */
478 if (pkbd->availdata) {
479 if (pevent != NULL) *pevent = NETWIB_TRUE;
480 return(NETWIB_ERR_OK);
481 }
482
483 /* wait */
484 netwib_er(netwib_priv_fd_wait(pkbd->fd, NETWIB_IO_WAYTYPE_READ,
485 pabstime, &event));
486
487 /* save state */
488 if (event) {
489 pkbd->availdata = NETWIB_TRUE;
490 }
491
492 if (pevent != NULL) *pevent = event;
493 return(NETWIB_ERR_OK);
494 }
495 #elif defined NETWIBDEF_SYSNAME_Windows
496 {
497 netwib_handletype handletype;
498 netwib_bool event;
499
500 switch(pkbd->type) {
501 case NETWIB_PRIV_KBDTYPE_CONSOLE : handletype = NETWIB_HANDLETYPE_CONSOLE; break;
502 case NETWIB_PRIV_KBDTYPE_FILE : handletype = NETWIB_HANDLETYPE_FILE; break;
503 case NETWIB_PRIV_KBDTYPE_PIPE : handletype = NETWIB_HANDLETYPE_PIPE; break;
504 default : handletype = NETWIB_HANDLETYPE_UNKNOWN; break;
505 }
506
507 netwib_er(netwib_priv_handle_wait(pkbd->h, handletype,
508 NETWIB_IO_WAYTYPE_READ,
509 pabstime, &event));
510 /* waiting on a console handle does not ensure we have an event
511 because we use PeekConsoleInput to recheck */
512 if (!event) {
513 return(NETWIB_ERR_PLEASELOOPTIME);
514 }
515
516 if (pevent != NULL) *pevent = NETWIB_TRUE;
517 return(NETWIB_ERR_OK);
518 }
519 #else
520 #error "Unknown value for NETWIBDEF_SYSNAME"
521 #endif
522
523 /*-------------------------------------------------------------*/
netwib_priv_kbd_read(netwib_priv_kbd * pkbd,netwib_buf * pbuf)524 netwib_err netwib_priv_kbd_read(netwib_priv_kbd *pkbd,
525 netwib_buf *pbuf)
526 #if defined NETWIBDEF_SYSNAME_Unix
527 {
528 netwib_char c;
529
530 /* reset state */
531 pkbd->availdata = NETWIB_FALSE;
532
533 if (pkbd->consolereadbyline) {
534 netwib_er(netwib_priv_kbd_read_line(pkbd, pbuf));
535 } else {
536 netwib_er(netwib_priv_kbd_read_key(pkbd, &c));
537 netwib_er(netwib_buf_append_byte(c, pbuf));
538 }
539
540 return(NETWIB_ERR_OK);
541 }
542 #elif defined NETWIBDEF_SYSNAME_Windows
543 {
544 netwib_char c;
545
546 if (pkbd->consolereadbyline) {
547 netwib_er(netwib_priv_kbd_read_line(pkbd, pbuf));
548 } else {
549 netwib_er(netwib_priv_kbd_read_key(pkbd, &c));
550 netwib_er(netwib_buf_append_byte(c, pbuf));
551 }
552
553 return(NETWIB_ERR_OK);
554 }
555 #else
556 #error "Unknown value for NETWIBDEF_SYSNAME"
557 #endif
558
559 /*-------------------------------------------------------------*/
netwib_priv_kbd_buf_append(netwib_constbuf * pmessage,netwib_constbuf * pdefaulttext,netwib_bool echokeys,netwib_char prompt,netwib_bool askifempty,netwib_buf * pbuf)560 netwib_err netwib_priv_kbd_buf_append(netwib_constbuf *pmessage,
561 netwib_constbuf *pdefaulttext,
562 netwib_bool echokeys,
563 netwib_char prompt,
564 netwib_bool askifempty,
565 netwib_buf *pbuf)
566 {
567 netwib_buf buf, cmsg, call;
568 netwib_string bufref;
569 netwib_priv_kbd kbd;
570 netwib_bool havemessage, havedefaulttext;
571 netwib_char c;
572 netwib_err ret;
573
574 /* obtain strings */
575 havemessage = NETWIB_FALSE;
576 if (netwib__buf_ref_data_sizenull(pmessage) != 0) {
577 havemessage = NETWIB_TRUE;
578 }
579 havedefaulttext = NETWIB_FALSE;
580 if (netwib__buf_ref_data_sizenull(pdefaulttext) != 0) {
581 havedefaulttext = NETWIB_TRUE;
582 }
583
584 /* display message */
585 if (havemessage) {
586 if (echokeys && havedefaulttext) {
587 netwib_er(netwib_fmt_display("%{buf} [%{buf}]%c ", pmessage,
588 pdefaulttext, prompt));
589 } else {
590 netwib_er(netwib_fmt_display("%{buf}%c ", pmessage, prompt));
591 }
592 }
593
594 /* get user string */
595 netwib_er(netwib_buf_init_mallocdefault(&buf));
596 netwib_er(netwib_priv_kbd_initdefault(&kbd));
597 netwib_er(netwib_priv_kbd_ctl_set_echoline(&kbd, echokeys, NETWIB_TRUE));
598 netwib_er(netwib_priv_kbd_read_line(&kbd, &buf));
599 netwib_er(netwib_priv_kbd_close(&kbd));
600
601 /* user entered something */
602 netwib_er(netwib_buf_ref_string(&buf, &bufref));
603 if (bufref[0] != '\0') {
604 ret = netwib_buf_append_buf(&buf, pbuf);
605 netwib_er(netwib_buf_close(&buf));
606 return(ret);
607 }
608 netwib_er(netwib_buf_close(&buf));
609
610 /* user entered nothing and there is no default : nothing to append */
611 if (!havedefaulttext) {
612 return(NETWIB_ERR_OK);
613 }
614
615 /* ask user */
616 if (askifempty) {
617 netwib_er(netwib_buf_init_ext_string("Do you want an Empty string or the Default string ?", &cmsg));
618 netwib_er(netwib_buf_init_ext_string("eEdD", &call));
619 netwib_er(netwib_char_init_kbd(&cmsg, &call, 'd', &c));
620 if (c == 'd' || c == 'D') {
621 netwib_er(netwib_buf_append_buf(pdefaulttext, pbuf));
622 }
623 }
624
625 return(NETWIB_ERR_OK);
626 }
627