|
|
1.1 root 1: /* dispatch.c - fred dispatch */
2:
3: #ifndef lint
4: static char *rcsid = "$Header: /f/osi/others/quipu/uips/fred/RCS/dispatch.c,v 7.9 90/07/27 08:45:18 mrose Exp $";
5: #endif
6:
7: /*
8: * $Header: /f/osi/others/quipu/uips/fred/RCS/dispatch.c,v 7.9 90/07/27 08:45:18 mrose Exp $
9: *
10: *
11: * $Log: dispatch.c,v $
12: * Revision 7.9 90/07/27 08:45:18 mrose
13: * update
14: *
15: * Revision 7.8 90/06/11 10:55:01 mrose
16: * UFN
17: *
18: * Revision 7.7 90/03/22 16:10:42 mrose
19: * xwp
20: *
21: * Revision 7.6 90/03/22 08:36:29 mrose
22: * touch-up
23: *
24: * Revision 7.5 90/03/08 08:05:00 mrose
25: * phone
26: *
27: * Revision 7.4 90/01/16 20:43:19 mrose
28: * last check-out
29: *
30: * Revision 7.3 90/01/11 18:36:21 mrose
31: * real-sync
32: *
33: * Revision 7.2 89/12/14 18:48:56 mrose
34: * KIS project
35: *
36: * Revision 7.1 89/12/13 20:01:43 mrose
37: * errfp
38: *
39: * Revision 7.0 89/11/23 22:08:52 mrose
40: * Release 6.0
41: *
42: */
43:
44: /*
45: * NOTICE
46: *
47: * Acquisition, use, and distribution of this module and related
48: * materials are subject to the restrictions of a license agreement.
49: * Consult the Preface in the User's Manual for the full terms of
50: * this agreement.
51: *
52: */
53:
54:
55: #include <ctype.h>
56: #include "fred.h"
57: #ifdef BSD42
58: #include <sys/ioctl.h>
59: #endif
60: #include <sys/stat.h>
61:
62: /* DATA */
63:
64: int debug = 0;
65: int fflag = 0;
66: int kflag = 0;
67: int mail = 0;
68: int nametype = 1;
69: int network = 0;
70: int phone = 0;
71: int query = 1;
72: int readonly = 0;
73: int soundex = 0;
74: int timelimit = 300;
75: int verbose = 0;
76: int watch = 0;
77:
78: int usetty = 1;
79: int ifd = NOTOK;
80: int ofd = NOTOK;
81:
82: int rcmode = 00;
83: int runcom = 0;
84: int runsys = 0;
85:
86: char *manager = "internal";
87: char *pager = "more";
88:
89: char *mydn = NULLCP;
90: char *myhome = NULLCP;
91: char *myuser = NULLCP;
92:
93:
94: FILE *stdfp = stdout;
95: FILE *errfp = NULL;
96:
97: /* */
98:
99: int f_set (), f_help ();
100: int f_alias (), f_area (), f_dish (), f_edit (), f_manual (), f_report (),
101: f_thisis ();
102: int f_bind (), f_quit ();
103: int f_whois ();
104:
105:
106: static struct dispatch dispatches[] = {
107: "alias", f_alias, DS_SYOK,
108: "report on active aliases",
109:
110: "area", f_area, DS_NULL,
111: "set default area for searches",
112:
113: "dish", f_dish, DS_USER,
114: "talk directly to dish (experts only!)",
115:
116: "edit", f_edit, DS_USER,
117: "edit entry in the white pages",
118:
119: "help", f_help, DS_NULL,
120: "print help information",
121:
122: "manual", f_manual, DS_NULL,
123: "print detailed documentation",
124:
125: "quit", f_quit, DS_USER,
126: "terminate fred",
127:
128: "report", f_report, DS_USER,
129: "send report to white pages manager",
130:
131: "set", f_set, DS_SYOK,
132: "display or change variables",
133:
134: "thisis", f_thisis, DS_USER,
135: "identify self to the white pages",
136:
137: "whois", f_whois, DS_NULL,
138: "find something in the white pages",
139:
140: NULL
141: };
142:
143: struct dispatch *getds ();
144:
145: /* DISPATCH */
146:
147: fredloop (vec, error)
148: char **vec;
149: int error;
150: {
151: register struct dispatch *ds;
152:
153: if ((ds = getds (strcmp (*vec, "?") ? *vec : "help")) == NULL)
154: return error;
155: if (network) {
156: if ((ds -> ds_flags & DS_USER)
157: || ((ds -> ds_flags & DS_SYOK) && !runsys)) {
158: advise (NULLCP, "unavailable operation \"%s\"", *vec);
159: return error;
160: }
161: }
162: else
163: vec[0] = ds -> ds_name;
164:
165: switch ((*ds -> ds_fnx) (vec)) {
166: case NOTOK:
167: return error;
168:
169: case OK:
170: default:
171: return OK;
172:
173: case DONE:
174: return DONE;
175: }
176: }
177:
178: /* */
179:
180: static struct dispatch *getds (name)
181: char *name;
182: {
183: register int longest,
184: nmatches;
185: register char *p,
186: *q;
187: char buffer[BUFSIZ];
188: register struct dispatch *ds,
189: *fs;
190:
191: longest = nmatches = 0;
192: for (ds = dispatches; p = ds -> ds_name; ds++) {
193: for (q = name; *q == *p++; q++)
194: if (*q == NULL)
195: return ds;
196:
197: if (*q == NULL)
198: if (q - name > longest) {
199: longest = q - name;
200: nmatches = 1;
201: fs = ds;
202: }
203: else
204: if (q - name == longest)
205: nmatches++;
206: }
207:
208: switch (nmatches) {
209: case 0:
210: if (*(p = name) == '!')
211: p++;
212: for (; *p; p++)
213: if (!isdigit (*p))
214: break;
215: if (!*p || network)
216: for (ds = dispatches; ds -> ds_name; ds++)
217: if (strcmp (ds -> ds_name, "whois") == 0)
218: return ds;
219:
220: advise (NULLCP, "unknown operation \"%s\"", name);
221: return NULL;
222:
223: case 1:
224: return fs;
225:
226: default:
227: for (ds = dispatches, p = buffer; q = ds -> ds_name; ds++)
228: if (strncmp (q, name, longest) == 0) {
229: (void) sprintf (p, "%s \"%s\"", p != buffer ? "," : "", q);
230: p += strlen (p);
231: }
232: advise (NULLCP, "ambiguous operation, it could be one of:%s",
233: buffer);
234: return NULL;
235: }
236: }
237:
238: /* VARIABLES */
239:
240: static char *bool[] = {
241: "off", "on", NULL
242: };
243:
244: static char *names[] = {
245: "fullname", "surname", "friendly", NULL
246: };
247:
248:
249: struct var {
250: char *v_name;
251: IP v_value;
252:
253: char *v_dname;
254: char **v_dvalue;
255: char *v_mask;
256:
257: IFP v_hook;
258:
259: int v_flags;
260: #define V_NULL 0x00
261: #define V_RDONLY 0x01
262: };
263:
264: struct var *getvar ();
265:
266:
267: static struct var vars[] = {
268: "debug", &debug, "debug FRED", bool,
269: NULLCP, NULLIFP, V_NULL,
270:
271: "manager", NULLIP, "mail address of local white pages manager", &manager,
272: NULLCP, NULLIFP, V_RDONLY,
273:
274: "namesearch", &nametype, "type of name used for matching", names,
275: NULLCP, NULLIFP, V_NULL,
276:
277: "pager", NULLIP, "program to use for output pagination", &pager,
278: NULLCP, NULLIFP, V_RDONLY,
279:
280: "phone", &phone, "display phone numbers in one-liner", bool,
281: NULLCP, NULLIFP, V_NULL,
282:
283: "query", &query, "confirm two-step operations", bool,
284: NULLCP, NULLIFP, V_NULL,
285:
286: "soundex", &soundex, "use soundex for matching", bool,
287: NULLCP, NULLIFP, V_NULL,
288:
289: "timelimit", &timelimit, "maximum time (in seconds) for matching", NULLVP,
290: NULLCP, NULLIFP, V_NULL,
291:
292: "verbose", &verbose, "verbose interaction", bool,
293: NULLCP, NULLIFP, V_NULL,
294:
295: "watch", &watch, "watch dialogue with dish", bool,
296: NULLCP, NULLIFP, V_NULL,
297:
298: NULL
299: };
300:
301:
302: static int varwidth1;
303: static int varwidth2;
304:
305: char **getval ();
306:
307: /* */
308:
309: static int f_set (vec)
310: char **vec;
311: {
312: register int i,
313: j;
314: int value,
315: vflag;
316: register char **cp,
317: *dp;
318: register struct var *v;
319:
320: if (*++vec == NULL) {
321: register int w;
322: int columns,
323: width,
324: lines;
325: register struct var *u;
326:
327: for (u = vars; u -> v_name; u++)
328: continue;
329: width = varwidth1;
330:
331: if ((columns = ncols (stdout) / (width = (width + 8) & ~7)) == 0)
332: columns = 1;
333: lines = ((u - vars) + columns - 1) / columns;
334:
335: printf ("Variables:\n");
336: for (i = 0; i < lines; i++)
337: for (j = 0; j < columns; j++) {
338: v = vars + j * lines + i;
339: printf ("%s", v -> v_name);
340: if (v + lines >= u) {
341: printf ("\n");
342: break;
343: }
344: for (w = strlen (v -> v_name); w < width; w = (w + 8) & ~7)
345: (void) putchar ('\t');
346: }
347:
348: return OK;
349: }
350:
351: if (strcmp (*vec, "-help") == 0) {
352: fprintf (stdfp, "set [variable [value]]\n");
353: fprintf (stdfp,
354: " with no arguments, lists variables which may be set\n");
355: fprintf (stdfp,
356: " with one argument, lists the value of the named variable\n");
357: fprintf (stdfp,
358: " with two arguments, sets the given variable accordingly\n");
359:
360: return OK;
361: }
362:
363: if (strcmp (*vec, "?") == 0) {
364: for (v = vars; v -> v_name; v++)
365: printvar (v);
366:
367: return OK;
368: }
369:
370: if ((v = getvar (*vec)) == NULL)
371: return OK;
372:
373: if (*++vec == NULL) {
374: printvar (v);
375:
376: return OK;
377: }
378:
379: if (readonly && (v -> v_flags & V_RDONLY)) {
380: advise (NULLCP, "variable is read-only");
381: return OK;
382: }
383:
384: if (strcmp (*vec, "?") == 0) {
385: if (v -> v_value && (cp = v -> v_dvalue)) {
386: printf ("use %s of:", v -> v_mask ? "any" : "one");
387: for (i = 0; *cp; cp++)
388: printf ("%s \"%s\"", i++ ? "," : "", *cp);
389: if (v -> v_mask)
390: printf (";\n\tor \"all\";\n\tor a hexadecimal number from 0 to 0x%x\n",
391: (1 << (i - 1)) - 1);
392: else
393: printf (";\n\tor a number from 0 to %d\n",
394: cp - v -> v_dvalue - 1);
395: }
396: else
397: printf ("use any %s value\n",
398: v -> v_value ? "integer" : "string");
399:
400: return OK;
401: }
402:
403: if (v -> v_value == NULLIP) {
404: register int w;
405:
406: if (*v -> v_dvalue)
407: free (*v -> v_dvalue);
408: *v -> v_dvalue = strdup (*vec);
409: if ((w = strlen (*v -> v_dvalue) + 2) > varwidth2)
410: varwidth2 = w;
411: if (v -> v_hook)
412: (*v -> v_hook) (v);
413: if (verbose)
414: printvar (v);
415: return OK;
416: }
417:
418: if (v -> v_mask) {
419: if (strcmp (dp = *vec, "all") == 0 && (cp = v -> v_dvalue)) {
420: i = 1;
421: while (*++cp)
422: i <<= 1;
423: value = i - 1;
424: j = 1;
425: }
426: else {
427: if (strncmp (dp, "0x", 2) == 0)
428: dp += 2;
429: for (j = sscanf (dp, "%x", &value); *dp; dp++)
430: if (!isxdigit (*dp)) {
431: j = 0;
432: break;
433: }
434: }
435: }
436: else
437: j = sscanf (*vec, "%d", &value);
438:
439: if (j == 1) {
440: if (cp = v -> v_dvalue) {
441: if (v -> v_mask) {
442: i = 1;
443: while (*++cp)
444: i <<= 1;
445: if (value >= i)
446: goto out_of_range;
447: }
448: else {
449: for (; *cp; cp++)
450: continue;
451: if (value >= cp - v -> v_dvalue) {
452: out_of_range: ;
453: advise (NULLCP, "value out of range \"%s\"", *vec);
454:
455: return OK;
456: }
457: }
458: }
459:
460: vflag = verbose;
461: *v -> v_value = value;
462: if (v -> v_hook)
463: (*v -> v_hook) (v);
464: if (vflag)
465: printvar (v);
466:
467: return OK;
468: }
469:
470: if (v -> v_mask) {
471: i = 0;
472: for (; *vec; vec++) {
473: if (!(cp = getval (*vec, v -> v_dvalue))) {
474: advise (NULLCP, "bad value \"%s\"", *vec);
475:
476: return OK;
477: }
478: if ((j = cp - v -> v_dvalue) <= 0)
479: continue;
480:
481: i |= 1 << (j - 1);
482: }
483:
484: vflag = verbose;
485: *v -> v_value = i;
486: if (v -> v_hook)
487: (*v -> v_hook) (v);
488: if (vflag)
489: printvar (v);
490:
491: return OK;
492: }
493:
494: if (v -> v_dvalue && (cp = getval (*vec, v -> v_dvalue))) {
495: vflag = verbose;
496: *v -> v_value = cp - v -> v_dvalue;
497: if (v -> v_hook)
498: (*v -> v_hook) (v);
499: if (vflag)
500: printvar (v);
501: }
502: else
503: if (!v -> v_dvalue)
504: advise (NULLCP, "bad value \"%s\"", *vec);
505:
506: return OK;
507: }
508:
509: /* */
510:
511: static printvar (v)
512: register struct var *v;
513: {
514: int i;
515: char buffer[BUFSIZ];
516:
517: if (runcom)
518: return;
519:
520: printf ("%-*s = ", varwidth1, v -> v_name);
521: if (v -> v_value) {
522: i = *v -> v_value;
523:
524: if (v -> v_mask) {
525: if (v -> v_dvalue) {
526: if (i == 0)
527: printf ("%-*s", varwidth2, v -> v_dvalue[i]);
528: else {
529: (void) strcpy (buffer, sprintb (i, v -> v_mask));
530: if (strlen (buffer) <= varwidth2)
531: printf ("%-*s", varwidth2, buffer);
532: else
533: printf ("%s\n%*s", buffer, varwidth1 + varwidth2 + 3,
534: "");
535: }
536: }
537: else
538: printf ("0x%-*x", varwidth2 - 2, i);
539: }
540: else {
541: if (v -> v_dvalue)
542: printf ("%-*s", varwidth2, v -> v_dvalue[i]);
543: else
544: printf ("%-*d", varwidth2, i);
545: }
546: }
547: else
548: if (*v -> v_dvalue) {
549: (void) sprintf (buffer, "\"%s\"", *v -> v_dvalue);
550: printf ("%-*s", varwidth2, buffer);
551: }
552: printf (" - %s\n", v -> v_dname);
553: }
554:
555: /* */
556:
557: static char **getval (name, choices)
558: register char *name;
559: char **choices;
560: {
561: register int longest,
562: nmatches;
563: register char *p,
564: *q,
565: **cp,
566: **fp;
567: char buffer[BUFSIZ];
568:
569: longest = nmatches = 0;
570: for (cp = choices; p = *cp; cp++) {
571: for (q = name; *q == *p++; q++)
572: if (*q == NULL)
573: return cp;
574: if (*q == NULL)
575: if (q - name > longest) {
576: longest = q - name;
577: nmatches = 1;
578: fp = cp;
579: }
580: else
581: if (q - name == longest)
582: nmatches++;
583: }
584:
585: switch (nmatches) {
586: case 0:
587: advise (NULLCP, "unknown value \"%s\"", name);
588: return NULL;
589:
590: case 1:
591: return fp;
592:
593: default:
594: for (cp = choices, p = buffer; q = *cp; cp++)
595: if (strncmp (q, name, longest) == 0) {
596: (void) sprintf (p, "%s \"%s\"", p != buffer ? "," : "", q);
597: p += strlen (p);
598: }
599: advise (NULLCP, "ambiguous value, it could be one of:%s",
600: buffer);
601: return NULL;
602: }
603: }
604:
605: /* */
606:
607: static char *ignore[] = {
608: "level", "listings", "verify", NULL
609: };
610:
611:
612: static struct var *getvar (name)
613: register char *name;
614: {
615: register int longest,
616: nmatches;
617: register char *p,
618: *q,
619: **ip;
620: char buffer[BUFSIZ];
621: register struct var *v,
622: *f;
623:
624: if (runcom)
625: for (ip = ignore; *ip; ip++)
626: if (lexequ (*ip, name) == 0)
627: return NULL;
628:
629: longest = nmatches = 0;
630: for (v = vars; p = v -> v_name; v++) {
631: for (q = name; *q == *p++; q++)
632: if (*q == NULL)
633: return v;
634: if (*q == NULL)
635: if (q - name > longest) {
636: longest = q - name;
637: nmatches = 1;
638: f = v;
639: }
640: else
641: if (q - name == longest)
642: nmatches++;
643: }
644:
645: switch (nmatches) {
646: case 0:
647: advise (NULLCP, "unknown variable \"%s\"", name);
648: return NULL;
649:
650: case 1:
651: return f;
652:
653: default:
654: for (v = vars, p = buffer; q = v -> v_name; v++)
655: if (strncmp (q, name, longest) == 0) {
656: (void) sprintf (p, "%s \"%s\"", p != buffer ? "," : "", q);
657: p += strlen (p);
658: }
659: advise (NULLCP, "ambiguous variable, it could be one of:%s",
660: buffer);
661: return NULL;
662: }
663: }
664:
665: /* HELP */
666:
667: static int helpwidth;
668:
669: /* */
670:
671: int f_help (vec)
672: char **vec;
673: {
674: register int i,
675: j,
676: w;
677: int columns,
678: width,
679: lines;
680: register struct dispatch *ds,
681: *es;
682:
683: if (network || vec == NULL) {
684: register char **ap;
685:
686: for (ap = whois_help; *ap; ap++)
687: fprintf (stdfp, "%s%s", *ap, EOLN);
688:
689: return OK;
690: }
691:
692: for (es = dispatches; es -> ds_name; es++)
693: continue;
694: width = helpwidth;
695:
696: if (*++vec == NULL) {
697: if ((columns = ncols (stdout) / (width = (width + 8) & ~7)) == 0)
698: columns = 1;
699: lines = ((es - dispatches) + columns - 1) / columns;
700:
701: printf ("Operations:\n");
702: for (i = 0; i < lines; i++)
703: for (j = 0; j < columns; j++) {
704: ds = dispatches + j * lines + i;
705: printf ("%s", ds -> ds_name);
706: if (ds + lines >= es) {
707: printf ("\n");
708: break;
709: }
710: for (w = strlen (ds -> ds_name); w < width; w = (w + 8) & ~7)
711: (void) putchar ('\t');
712: }
713: printf ("\n");
714:
715: return OK;
716: }
717:
718: if (strcmp (*vec, "-help") == 0) {
719: fprintf (stdfp, "help [commands ...]\n");
720: fprintf (stdfp,
721: " with no arguments, lists operations which may be invoked\n");
722: fprintf (stdfp,
723: " otherwise prints help for each operation given\n");
724:
725: return OK;
726: }
727:
728: for (; *vec; vec++)
729: if (strcmp (*vec, "?") == 0) {
730: for (ds = dispatches; ds -> ds_name; ds++)
731: printf ("%-*s\t- %s\n", width, ds -> ds_name, ds -> ds_help);
732:
733: break;
734: }
735: else
736: if (ds = getds (*vec))
737: printf ("%-*s\t- %s\n", width, ds -> ds_name, ds -> ds_help);
738:
739: return OK;
740: }
741:
742: /* MISCELLANY */
743:
744: rcinit ()
745: {
746: register int w;
747: register char **cp,
748: *dp;
749: char buffer[BUFSIZ];
750: register struct dispatch *ds;
751: register struct var *v;
752:
753: if (fflag)
754: return;
755:
756: if ((myhome = getenv ("HOME")) == NULL)
757: myhome = "."; /* could do passwd search... */
758:
759: if ((myuser = getenv ("USER")) == NULLCP)
760: myuser = getenv ("LOGNAME");
761:
762: if (dp = getenv ("QUIPURC"))
763: (void) strcpy (buffer, dp);
764: else
765: (void) sprintf (buffer, "%s/.quipurc", myhome);
766: snarf (buffer, "username:", &mydn);
767:
768: for (ds = dispatches, helpwidth = 0; ds -> ds_name; ds++)
769: if ((w = strlen (ds -> ds_name)) > helpwidth)
770: helpwidth = w;
771:
772: for (v = vars, varwidth1 = 0; v -> v_name; v++) {
773: if ((w = strlen (v -> v_name)) > varwidth1)
774: varwidth1 = w;
775:
776: if (v -> v_value) {
777: if (cp = v -> v_dvalue) {
778: if (v -> v_mask) {
779: #ifdef notdef
780: w = 1;
781: while (*++cp)
782: w <<= 1;
783: w--;
784: if ((w = strlen (sprintb (w, v -> v_mask))) > varwidth2)
785: varwidth2 = w;
786: #endif
787: }
788: else
789: for (; *cp; cp++)
790: if ((w = strlen (*cp)) > varwidth2)
791: varwidth2 = w;
792: }
793: }
794: else
795: if (*v -> v_dvalue) {
796: *v -> v_dvalue = strdup (*v -> v_dvalue);
797: if ((w = strlen (*v -> v_dvalue) + 2) > varwidth2)
798: varwidth2 = w;
799: }
800: }
801: }
802:
803: /* */
804:
805: static snarf (file, name, variable)
806: char *file,
807: *name,
808: **variable;
809: {
810: int i;
811: register char *bp,
812: *dp,
813: *ep;
814: char buffer[BUFSIZ];
815: FILE *fp;
816:
817: if (fp = fopen (file, "r")) {
818: while (fgets (bp = buffer, sizeof buffer, fp)) {
819: if (*bp == '#' || *bp == '\n')
820: continue;
821: if (bp = index (buffer, '\n'))
822: *bp = NULL;
823: if (lexnequ (buffer, name, strlen (name)))
824: continue;
825:
826: bp = buffer + strlen (name);
827: while (isspace (*bp))
828: bp++;
829:
830: if (*bp == '"') {
831: if (*(dp = bp + strlen (bp) - 1) == '"')
832: bp++, *dp = NULL;
833: goto set_variable;
834: }
835:
836: i = 0;
837: for (dp = ep = bp; *dp; ) {
838: if (isspace (*dp)) {
839: *ep = ' ';
840: while (isspace (*++dp))
841: i = 1;
842: if (*dp)
843: ep++;
844: else
845: break;
846: }
847: if (i == 1)
848: *ep = *dp;
849:
850: dp++, ep++;
851: }
852: *ep = NULL;
853:
854: set_variable: ;
855: if (*variable)
856: free (*variable);
857: *variable = strdup (bp);
858: break;
859: }
860:
861: (void) fclose (fp);
862: }
863: }
864:
865: /* */
866:
867: rcfile (file, op, isystem)
868: char *file;
869: int op,
870: isystem;
871: {
872: register char *cp;
873: char buffer[BUFSIZ + 1],
874: *vec[NVEC + 1];
875: register FILE *fp;
876: struct stat st;
877:
878: if ((fp = fopen (file, "r")) == NULL)
879: return;
880:
881: runcom = 1, runsys = isystem;
882: if (fstat (fileno (fp), &st) == NOTOK)
883: adios (file, "unable to fstat");
884: rcmode = st.st_mode & 0777;
885:
886: while (fgets (buffer, sizeof buffer, fp)) {
887: if (*buffer == '#')
888: continue;
889: if (cp = index (buffer, '\n'))
890: *cp = NULL;
891:
892: bzero ((char *) vec, sizeof vec);
893: if (str2vecY (buffer, vec) < 1)
894: continue;
895:
896: if (fredloop (vec, NOTOK) != OK && op) {
897: (void) f_quit (NULLVP);
898: exit (1);
899: }
900: }
901:
902: runcom = 0;
903:
904: (void) fclose (fp);
905: }
906:
907: /* */
908:
909: #ifndef TIOCGWINSZ
910: /* ARGSUSED */
911: #endif
912:
913: int ncols (fp)
914: FILE *fp;
915: {
916: #ifdef TIOCGWINSZ
917: int i;
918: struct winsize ws;
919:
920: if (ioctl (fileno (fp), TIOCGWINSZ, (char *) &ws) != NOTOK
921: && (i = ws.ws_col) > 0)
922: return i;
923: #endif
924:
925: return 80;
926: }
927:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.