|
|
1.1 root 1: #ifndef lint
2: static char sccsid[] = "@(#)conn.c 5.3 (Berkeley) 8/13/83";
3: #endif
4:
5: #include "uucp.h"
6: #include <signal.h>
7: #include <setjmp.h>
8: #include <ctype.h>
9: #include <sys/types.h>
10: #include <sys/time.h>
11: #include <errno.h>
12: #ifdef SYSIII
13: #include <termio.h>
14: #include <fcntl.h>
15: #endif
16: #ifndef SYSIII
17: #include <sgtty.h>
18: #endif
19:
20: #define MAXC 1000
21:
22: extern jmp_buf Sjbuf;
23: extern int errno;
24:
25: /* Parity control during login procedure */
26: #define P_ZERO 0
27: #define P_ONE 1
28: #define P_EVEN 2
29: #define P_ODD 3
30: char par_tab[128]; /* must be power of two */
31:
32: int next_fd = -1; /* predicted fd to close interrupted opens */
33: /* rti!trt, courtesy unc!smb */
34: /***
35: * alarmtr() - catch alarm routine for "expect".
36: */
37: alarmtr()
38: {
39: signal(SIGALRM, alarmtr);
40: if (next_fd >= 0) {
41: if (close(next_fd))
42: logent("FAIL", "ACU LINE CLOSE");
43: next_fd = -1;
44: }
45: longjmp(Sjbuf, 1);
46: }
47:
48: /*******
49: * conn(system)
50: * char *system;
51: *
52: * conn - place a telephone call to system and
53: * login, etc.
54: *
55: * return codes:
56: * CF_SYSTEM: don't know system
57: * CF_TIME: wrong time to call
58: * CF_DIAL: call failed
59: * CF_NODEV: no devices available to place call
60: * CF_LOGIN: login/password dialog failed
61: *
62: * >0 - file no. - connect ok
63: *
64: */
65:
66: int Dcf = -1;
67:
68: conn(system)
69: char *system;
70: {
71: int ret, nf;
72: register int fn, fnd;
73: char info[MAXC], *flds[MAXC/10];
74: register FILE *fsys;
75: int fcode = 0;
76:
77: nf = 0;
78: fnd = 0;
79:
80:
81: fsys = fopen(SYSFILE, "r");
82: ASSERT(fsys != NULL, "CAN'T OPEN", SYSFILE, 0);
83:
84: DEBUG(4, "finds %s\n", "called");
85: while((nf = finds(fsys, system, info, flds)) > 0) {
86: DEBUG(4, "getto %s\n", "called");
87: if ((fn = getto(flds)) > 0) {
88: fnd = 1;
89: Dcf = fn;
90: break;
91: }
92: fcode = (fn == FAIL ? CF_DIAL : fn);
93: }
94: fclose(fsys);
95:
96: if (nf <= 0)
97: return(fcode ? fcode : nf);
98:
99: DEBUG(4, "login %s\n", "called");
100: ret = login(nf, flds, fn);
101: if (ret < 0) {
102: clsacu();
103: return(CF_LOGIN);
104: }
105: /* rti!trt: avoid passing file to children */
106: fioclex(fn);
107: return(fn);
108: }
109:
110: /***
111: * getto(flds) connect to remote machine
112: * char *flds[];
113: *
114: * return codes:
115: * >0 - file number - ok
116: * FAIL - failed
117: */
118:
119: getto(flds)
120: register char *flds[];
121: {
122: register struct condev *cd;
123: int nulldev(), diropn();
124:
125: DEBUG(4, "call: no. %s ", flds[F_PHONE]);
126: DEBUG(4, "for sys %s\n", flds[F_NAME]);
127:
128: CU_end = nulldev;
129: for (cd = condevs; cd->CU_meth != NULL; cd++) {
130: if (snccmp(cd->CU_meth, flds[F_LINE]) == SAME) {
131: DEBUG(4, "Using %s to call\n", cd->CU_meth);
132: return((*(cd->CU_gen))(flds));
133: }
134: }
135: logent(flds[F_LINE], "getto: Can't find, using DIR");
136: return(diropn(flds)); /* search failed, so use direct */
137: }
138:
139: /***
140: * clsacu() close call unit
141: *
142: * return codes: none
143: */
144:
145: int (*CU_end)() = nulldev;
146: clsacu()
147: {
148: (*(CU_end))(Dcf);
149: if (close(Dcf) == 0) {
150: DEBUG(4, "fd %d NOT CLOSED by CU_clos\n", Dcf);
151: logent("clsacu", "NOT CLOSED by CU_clos");
152: }
153: Dcf = -1;
154: CU_end = nulldev;
155: }
156:
157: /***
158: * exphone - expand phone number for given prefix and number
159: *
160: * return code - none
161: */
162:
163: exphone(in, out)
164: register char *in, *out;
165: {
166: FILE *fn;
167: char pre[MAXPH], npart[MAXPH], tpre[MAXPH], p[MAXPH];
168: char buf[BUFSIZ];
169: register char *s1;
170:
171: if (!isalpha(*in)) {
172: strcpy(out, in);
173: return;
174: }
175:
176: s1=pre;
177: while (isalpha(*in))
178: *s1++ = *in++;
179: *s1 = '\0';
180: s1 = npart;
181: while (*in != '\0')
182: *s1++ = *in++;
183: *s1 = '\0';
184:
185: tpre[0] = '\0';
186: if ((fn = fopen(DIALFILE, "r")) == NULL)
187: DEBUG(2, "CAN'T OPEN %s\n", DIALFILE);
188: else {
189: while (cfgets(buf, BUFSIZ, fn)) {
190: sscanf(buf, "%s%s", p, tpre);
191: if (strcmp(p, pre) == SAME)
192: goto found;
193: tpre[0] = '\0';
194: }
195: DEBUG(2, "CAN'T FIND dialcodes prefix '%s'\n", pre);
196: found:;
197: fclose(fn);
198: }
199:
200: strcpy(out, tpre);
201: strcat(out, npart);
202: return;
203: }
204:
205: /***
206: * rddev - read and decode a line from device file
207: *
208: * return code - FAIL at end-of file; 0 otherwise
209: */
210:
211: rddev(fp, dev)
212: register struct Devices *dev;
213: FILE *fp;
214: {
215: char *fdig();
216: char buf[BUFSIZ];
217: int na;
218:
219: if (!cfgets(buf, BUFSIZ, fp))
220: return(FAIL);
221:
222: na = sscanf(buf, "%s%s%s%s%s", dev->D_type, dev->D_line,
223: dev->D_calldev, dev->D_class, dev->D_brand);
224: ASSERT(na >= 4, "BAD DEVICE ENTRY", buf, 0);
225: if (na != 5) dev->D_brand[0] = '\0';
226: dev->D_speed = atoi(fdig(dev->D_class));
227: return(0);
228: }
229:
230: /***
231: * finds(fsys, sysnam, info, flds) set system attribute vector
232: *
233: * return codes:
234: * >0 - number of arguments in vector - succeeded
235: * CF_SYSTEM - system name not found
236: * CF_TIME - wrong time to call
237: */
238:
239: finds(fsys, sysnam, info, flds)
240: char *sysnam, info[], *flds[];
241: FILE *fsys;
242: {
243: char sysn[8];
244: int na;
245: int fcode = 0;
246:
247: /* format of fields
248: * 0 name;
249: * 1 time
250: * 2 acu/hardwired
251: * 3 speed
252: * etc
253: */
254: while (cfgets(info, MAXC, fsys) != NULL) {
255: na = getargs(info, flds);
256: sprintf(sysn, "%.7s", flds[F_NAME]);
257: if (strcmp(sysnam, sysn) != SAME)
258: continue;
259: if (ifdate(flds[F_TIME]))
260: /* found a good entry */
261: return(na);
262: DEBUG(2, "Wrong time ('%s') to call\n", flds[F_TIME]);
263: fcode = CF_TIME;
264: }
265: return(fcode ? fcode : CF_SYSTEM);
266: }
267:
268: /***
269: * login(nf, flds, dcr) do login conversation
270: * char *flds[];
271: * int nf;
272: *
273: * return codes: 0 | FAIL
274: */
275:
276: login(nf, flds, fn)
277: register char *flds[];
278: int nf, fn;
279: {
280: register char *want, *altern;
281: extern char *index();
282: int k, ok;
283:
284: ASSERT(nf > 4, "TOO FEW LOG FIELDS", "", nf);
285: for (k = F_LOGIN; k < nf; k += 2) {
286: want = flds[k];
287: ok = FAIL;
288: while (ok != 0) {
289: altern = index(want, '-');
290: if (altern != NULL)
291: *altern++ = '\0';
292: DEBUG(4, "wanted %s ", want);
293: ok = expect(want, fn);
294: DEBUG(4, "got %s\n", ok ? "?" : "that");
295: if (ok == 0)
296: break;
297: if (altern == NULL) {
298: logent("LOGIN", "FAILED");
299: /* close *not* needed here. rti!trt */
300: return(FAIL);
301: }
302: want = index(altern, '-');
303: if (want != NULL)
304: *want++ = '\0';
305: sendthem(altern, fn);
306: }
307: sleep(2);
308: if (k+1 < nf)
309: sendthem(flds[k+1], fn);
310: }
311: return(0);
312: }
313:
314:
315: /* rti!trt: conditional table generation to support odd speeds */
316: /* Suggested in n44a.139 by n44!dan (Dan Ts'o) */
317: struct sg_spds {int sp_val, sp_name;} spds[] = {
318: #ifdef B50
319: { 50, B50},
320: #endif
321: #ifdef B75
322: { 75, B75},
323: #endif
324: #ifdef B110
325: { 110, B110},
326: #endif
327: #ifdef B150
328: { 150, B150},
329: #endif
330: #ifdef B200
331: { 200, B200},
332: #endif
333: #ifdef B300
334: { 300, B300},
335: #endif
336: #ifdef B600
337: {600, B600},
338: #endif
339: #ifdef B1200
340: {1200, B1200},
341: #endif
342: #ifdef B1800
343: {1800, B1800},
344: #endif
345: #ifdef B2000
346: {2000, B2000},
347: #endif
348: #ifdef B2400
349: {2400, B2400},
350: #endif
351: #ifdef B3600
352: {3600, B3600},
353: #endif
354: #ifdef B4800
355: {4800, B4800},
356: #endif
357: #ifdef B7200
358: {7200, B7200},
359: #endif
360: #ifdef B9600
361: {9600, B9600},
362: #endif
363: #ifdef B19200
364: {19200,B19200},
365: #endif
366: {0, 0}
367: };
368:
369: /***
370: * fixline(tty, spwant) set speed/echo/mode...
371: * int tty, spwant;
372: *
373: * return codes: none
374: */
375:
376: fixline(tty, spwant)
377: int tty, spwant;
378: {
379: #ifdef SYSIII
380: struct termio ttbuf;
381: #endif
382: #ifndef SYSIII
383: struct sgttyb ttbuf;
384: #endif
385: register struct sg_spds *ps;
386: int speed = -1;
387: int ret;
388:
389: for (ps = spds; ps->sp_val; ps++)
390: if (ps->sp_val == spwant)
391: speed = ps->sp_name;
392: ASSERT(speed >= 0, "BAD SPEED", "", speed);
393: #ifdef SYSIII
394: ioctl(tty, TCGETA, &ttbuf);
395: /* ttbuf.sg_flags = (ANYP|RAW);
396: ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed; */
397: ttbuf.c_iflag = (ushort)0;
398: ttbuf.c_oflag = (ushort)0;
399: ttbuf.c_cflag = (speed|CS8|HUPCL|CREAD);
400: ttbuf.c_lflag = (ushort)0;
401: ttbuf.c_cc[VMIN] = 6;
402: ttbuf.c_cc[VTIME] = 1;
403: ret = ioctl(tty, TCSETA, &ttbuf);
404: #endif
405: #ifndef SYSIII
406: ioctl(tty, TIOCGETP, &ttbuf);
407: ttbuf.sg_flags = (ANYP|RAW);
408: ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed;
409: ret = ioctl(tty, TIOCSETP, &ttbuf);
410: #endif
411: ASSERT(ret >= 0, "RETURN FROM STTY", "", ret);
412: #ifndef SYSIII
413: ioctl(tty, TIOCHPCL, STBNULL);
414: ioctl(tty, TIOCEXCL, STBNULL);
415: #endif
416: return;
417: }
418:
419:
420: /* Bill Shannon recommends MR 2000, but that takes too much space on PDPs */
421: /* Actually, the 'expect' algorithm should be rewritten. */
422: #define MR 1000
423:
424:
425: /***
426: * expect(str, fn) look for expected string
427: * char *str;
428: *
429: * return codes:
430: * 0 - found
431: * FAIL - lost line or too many characters read
432: * some character - timed out
433: */
434:
435: expect(str, fn)
436: register char *str;
437: int fn;
438: {
439: char rdvec[MR];
440: register char *rp = rdvec;
441: int kr;
442: char nextch;
443:
444: if (strcmp(str, "\"\"") == SAME)
445: return(0);
446: *rp = 0;
447: if (setjmp(Sjbuf)) {
448: return(FAIL);
449: }
450: signal(SIGALRM, alarmtr);
451: /* change MAXCHARTIME to MAXMSGTIME, outside while loop -- brl-bmd!dpk */
452: alarm(MAXMSGTIME);
453: while (notin(str, rdvec)) {
454: kr = read(fn, &nextch, 1);
455: if (kr <= 0) {
456: alarm(0);
457: DEBUG(4, "lost line kr - %d\n, ", kr);
458: logent("LOGIN", "LOST LINE");
459: return(FAIL);
460: }
461: {
462: int c;
463: c = nextch & 0177;
464: DEBUG(4, c >= 040 ? "%c" : "\\%03o", c);
465: }
466: if ((*rp = nextch & 0177) != '\0')
467: rp++;
468: /* Check rdvec before null termination -- cmcl2!salkind */
469: if (rp >= rdvec + MR) {
470: alarm(0);
471: return(FAIL);
472: }
473: *rp = '\0';
474: }
475: alarm(0);
476: return(0);
477: }
478:
479:
480: /*
481: * Determine next file descriptor that would be allocated.
482: * This permits later closing of a file whose open was interrupted.
483: * It is a UNIX kernel problem, but it has to be handled.
484: * unc!smb (Steve Bellovin) probably first discovered it.
485: */
486: getnextfd()
487: {
488: close(next_fd = open("/", 0));
489: }
490:
491: /***
492: * sendthem(str, fn) send line of login sequence
493: * char *str;
494: *
495: * return codes: none
496: */
497:
498: sendthem(str, fn)
499: register char *str;
500: int fn;
501: {
502: register char *strptr;
503: int i, n, cr = 1;
504: static int p_init = 0;
505:
506: /* Note: debugging authorized only for privileged users */
507: DEBUG(5, "send %s\n", str);
508:
509: if (!p_init) {
510: p_init++;
511: bld_partab(P_EVEN);
512: }
513:
514: if (prefix("BREAK", str)) {
515: sscanf(&str[5], "%1d", &i);
516: if (i <= 0 || i > 10)
517: i = 3;
518: /* send break */
519: genbrk(fn, i);
520: return;
521: }
522:
523: if (prefix("PAUSE", str)) {
524: sscanf(&str[5], "%1d", &i);
525: if (i <= 0 || i > 10)
526: i = 3;
527: /* pause for a while */
528: sleep((unsigned)i);
529: return;
530: }
531:
532: if (strcmp(str, "EOT") == SAME) {
533: p_chwrite(fn, '\04');
534: return;
535: }
536:
537: /* LF, CR, and "" courtesy unc!smb */
538: /* Send a '\n' */
539: if (strcmp(str, "LF") == SAME)
540: str = "\\n\\c";
541:
542: /* Send a '\r' */
543: if (strcmp(str, "CR") == SAME)
544: str = "\\r\\c";
545:
546: /* Set parity as needed */
547: if (strcmp(str, "P_ZERO") == SAME) {
548: bld_partab(P_ZERO);
549: return;
550: }
551: if (strcmp(str, "P_ONE") == SAME) {
552: bld_partab(P_ONE);
553: return;
554: }
555: if (strcmp(str, "P_EVEN") == SAME) {
556: bld_partab(P_EVEN);
557: return;
558: }
559: if (strcmp(str, "P_ODD") == SAME) {
560: bld_partab(P_ODD);
561: return;
562: }
563:
564: /* If "", just send '\r' */
565: if (strcmp(str, "\"\"") != SAME)
566: for (strptr = str; *strptr; strptr++) {
567: if (*strptr == '\\') switch(*++strptr) {
568: case 's':
569: DEBUG(5, "BLANK\n", "");
570: *strptr = ' ';
571: break;
572: case 'd':
573: DEBUG(5, "DELAY\n", "");
574: sleep(1);
575: continue;
576: case 'r':
577: DEBUG(5, "RETURN\n", "");
578: *strptr = '\r';
579: break;
580: case 'b':
581: if (isdigit(*(strptr+1))) {
582: i = (*++strptr - '0');
583: if (i <= 0 || i > 10)
584: i = 3;
585: } else
586: i = 3;
587: /* send break */
588: genbrk(fn, i);
589: continue;
590: case 'c':
591: if (*(strptr+1) == '\0') {
592: DEBUG(5, "NO CR\n", "");
593: cr = 0;
594: continue;
595: }
596: DEBUG(5, "NO CR - MIDDLE IGNORED\n", "");
597: continue;
598: default:
599: if (isdigit(strptr[1])) {
600: i = 0;
601: n = 0;
602: while (isdigit(strptr[1]) && ++n <= 3)
603: i = i*8 + (*++strptr - '0');
604: p_chwrite(fn, i);
605: continue;
606: }
607: DEBUG(5, "BACKSLASH\n", "");
608: strptr--;
609: }
610: p_chwrite(fn, *strptr);
611: }
612:
613: /* '\n' changed to '\r'--a better default. rti!trt */
614: if (cr)
615: p_chwrite(fn, '\r');
616: return;
617: }
618:
619: p_chwrite(fd, c)
620: int fd;
621: int c;
622: {
623: char t[2];
624:
625: t[0] = par_tab[c&0177];
626: t[1] = '\0';
627: ASSERT(write(fd, t, 1) == 1, "BAD WRITE", "", t[0]);
628: }
629:
630: /*
631: * generate parity table for use by p_chwrite.
632: */
633: bld_partab(type)
634: int type;
635: {
636: register int i, j, n;
637:
638: for (i = 0; i < sizeof(par_tab); i++) {
639: n = 0;
640: for (j = i&(sizeof(par_tab)-1); j; j = (j-1)&j)
641: n++;
642: par_tab[i] = i;
643: if (type == P_ONE
644: || (type == P_EVEN && (n&01) != 0)
645: || (type == P_ODD && (n&01) == 0))
646: par_tab[i] |= sizeof(par_tab);
647: }
648: }
649:
650: #define BSPEED B150
651:
652: /***
653: * genbrk send a break
654: *
655: * return codes; none
656: */
657:
658: genbrk(fn, bnulls)
659: register int fn, bnulls;
660: {
661: register int ret;
662: #ifdef SYSIII
663: ret = ioctl(fn, TCSBRK, STBNULL);
664: DEBUG(5, "break ioctl ret %d\n", ret);
665: #endif
666: #ifndef SYSIII
667: #ifdef TIOCSBRK
668: ret = ioctl(fn, TIOCSBRK, STBNULL);
669: DEBUG(5, "break ioctl ret %d\n", ret);
670: #ifdef TIOCCBRK
671: ret = write(fn, "\0\0\0\0\0\0\0\0\0\0\0\0", bnulls);
672: ASSERT(ret > 0, "BAD WRITE genbrk", "", ret);
673: sleep(1);
674: ret = ioctl(fn, TIOCCBRK, STBNULL);
675: DEBUG(5, "break ioctl ret %d\n", ret);
676: #endif
677: DEBUG(4, "ioctl 1 second break\n", STBNULL);
678: #else
679: struct sgttyb ttbuf;
680: register int sospeed;
681:
682: ret = ioctl(fn, TIOCGETP, &ttbuf);
683: sospeed = ttbuf.sg_ospeed;
684: ttbuf.sg_ospeed = BSPEED;
685: ret = ioctl(fn, TIOCSETP, &ttbuf);
686: ret = write(fn, "\0\0\0\0\0\0\0\0\0\0\0\0", bnulls);
687: ASSERT(ret > 0, "BAD WRITE genbrk", "", ret);
688: ttbuf.sg_ospeed = sospeed;
689: ret = ioctl(fn, TIOCSETP, &ttbuf);
690: ret = write(fn, "@", 1);
691: ASSERT(ret > 0, "BAD WRITE genbrk", "", ret);
692: DEBUG(4, "sent BREAK nulls - %d\n", bnulls);
693: #endif
694: #endif
695: }
696:
697:
698: /***
699: * notin(sh, lg) check for occurrence of substring "sh"
700: * char *sh, *lg;
701: *
702: * return codes:
703: * 0 - found the string
704: * 1 - not in the string
705: */
706:
707: notin(sh, lg)
708: register char *sh, *lg;
709: {
710: while (*lg != '\0') {
711: /* Dave Martingale: permit wild cards in 'expect' */
712: if (wprefix(sh, lg))
713: return(0);
714: else
715: lg++;
716: }
717: return(1);
718: }
719:
720:
721: /*******
722: * ifdate(s)
723: * char *s;
724: *
725: * ittvax!swatt
726: * Allow multiple date specifications separated by '|'.
727: * Calls ifadate, formerly "ifdate".
728: *
729: * return codes:
730: * see ifadate
731: */
732:
733: ifdate(s)
734: char *s;
735: {
736: register char *p;
737: register int ret;
738:
739: for (p = s; p && (*p == '|' ? *++p : *p); p = index(p, '|'))
740: if (ret = ifadate(p))
741: return(ret);
742: return(0);
743: }
744:
745:
746: /*******
747: * ifadate(s)
748: * char *s;
749: *
750: * ifadate - this routine will check a string (s)
751: * like "MoTu0800-1730" to see if the present
752: * time is within the given limits.
753: * SIDE EFFECT - Retrytime is set
754: *
755: * String alternatives:
756: * Wk - Mo thru Fr
757: * zero or one time means all day
758: * Any - any day
759: *
760: * return codes:
761: * 0 - not within limits
762: * 1 - within limits
763: */
764:
765: ifadate(s)
766: char *s;
767: {
768: static char *days[]={
769: "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", 0
770: };
771: time_t clock;
772: int rtime;
773: int i, tl, th, tn, flag, dayok=0;
774: struct tm *localtime();
775: struct tm *tp;
776: char *index();
777: char *p;
778:
779: /* pick up retry time for failures */
780: /* global variable Retrytime is set here */
781: if ((p = index(s, ',')) == NULL) {
782: Retrytime = RETRYTIME;
783: }
784: else {
785: i = sscanf(p+1, "%d", &rtime);
786: if (i < 1 || rtime < 5)
787: rtime = 5;
788: Retrytime = rtime * 60;
789: }
790:
791: time(&clock);
792: tp = localtime(&clock);
793: while (isalpha(*s)) {
794: for (i = 0; days[i]; i++) {
795: if (prefix(days[i], s))
796: if (tp->tm_wday == i)
797: dayok = 1;
798: }
799:
800: if (prefix("Wk", s))
801: if (tp->tm_wday >= 1 && tp->tm_wday <= 5)
802: dayok = 1;
803: if (prefix("Any", s))
804: dayok = 1;
805: s++;
806: }
807:
808: if (dayok == 0)
809: return(0);
810: i = sscanf(s, "%d-%d", &tl, &th);
811: tn = tp->tm_hour * 100 + tp->tm_min;
812: if (i < 2)
813: return(1);
814: if (th < tl)
815: flag = 0; /* set up for crossover 2400 test */
816: else
817: flag = 1;
818: if ((tn >= tl && tn <= th)
819: || (tn >= th && tn <= tl)) /* test for crossover 2400 */
820: return(flag);
821: else
822: return(!flag);
823: }
824:
825:
826: /***
827: * char *
828: * lastc(s) return pointer to last character
829: * char *s;
830: *
831: */
832:
833: char *
834: lastc(s)
835: register char *s;
836: {
837: while (*s != '\0') s++;
838: return(s);
839: }
840:
841:
842: /***
843: * char *
844: * fdig(cp) find first digit in string
845: *
846: * return - pointer to first digit in string or end of string
847: */
848:
849: char *
850: fdig(cp)
851: register char *cp;
852: {
853: register char *c;
854:
855: for (c = cp; *c; c++)
856: if (*c >= '0' && *c <= '9')
857: break;
858: return(c);
859: }
860:
861:
862: /*
863: * Compare strings: s1>s2: >0 s1==s2: 0 s1<s2: <0
864: * Strings are compared as if they contain all capital letters.
865: */
866:
867: snccmp(s1, s2)
868: register char *s1, *s2;
869: {
870: char c1, c2;
871:
872: if (islower(*s1)) c1 = toupper(*s1);
873: else c1 = *s1;
874: if (islower(*s2)) c2 = toupper(*s2);
875: else c2 = *s2;
876:
877: while (c1 == c2) {
878: if (*s1++=='\0')
879: return(0);
880: s2++;
881: if (islower(*s1)) c1 = toupper(*s1);
882: else c1 = *s1;
883: if (islower(*s2)) c2 = toupper(*s2);
884: else c2 = *s2;
885: }
886: return(c1 - c2);
887: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.