1: #ifndef lint 2: static char sccsid[] = "@(#)conn.c 5.2 (Berkeley) 7/2/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: #ifndef DIALUP 415: ioctl(tty, TIOCEXCL, STBNULL); 416: #endif 417: #endif 418: return; 419: } 420: 421: 422: #define MR 2000 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: }