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