1: # include <stdio.h> 2: # include <func.h> 3: # include <pv.h> 4: # include <ingres.h> 5: # include <aux.h> 6: # include <access.h> 7: # include <symbol.h> 8: # include <lock.h> 9: # include <signal.h> 10: # include <sccs.h> 11: # include <errors.h> 12: 13: SCCSID(@(#)copy.c 8.5 2/8/85) 14: 15: /* 16: ** COPY -- Performs an ingres COPY. 17: ** 18: ** Trace Flags: 19: ** 30 20: */ 21: 22: 23: # define MAXMAP 3 * MAXDOM 24: # define DUMMY 'd' 25: # define ESCAPE '\\' 26: 27: extern short tTdbu[100]; 28: extern int copy(); 29: extern int null_fn(); 30: 31: struct fn_def CopyFn = 32: { 33: "COPY", 34: copy, 35: null_fn, 36: null_fn, 37: NULL, 38: 0, 39: tTdbu, 40: 100, 41: 'Z', 42: 0 43: }; 44: 45: 46: 47: 48: struct map 49: { 50: char name[MAXNAME+1]; /* attribute name */ 51: char ftype; /* attfrmt of file domain */ 52: char rtype; /* attfrmt of relation domain */ 53: int flen; /* attfrml of file domain */ 54: int rlen; /* attfrml of relation domain */ 55: int roffset; /* attoff of relation domain */ 56: int used; /* tag for duplicate checking */ 57: char *fdelim; /* pointer to list of file param delims */ 58: char *paramname; /* pointer to original parameter name */ 59: /* used for supplying domain name in case of error */ 60: }; 61: struct map Map[MAXMAP]; /* one entry for each user 62: specified domain in copy statement. */ 63: 64: int Mapcount; /* number of Map entries */ 65: 66: 67: DESC Des; /* descriptor for copied relation */ 68: 69: extern struct out_arg Out_arg; /* user defined formats for numeric output */ 70: 71: FILE *File_iop; /* i/o file pointer */ 72: char *Filename; /* pointer to file name */ 73: 74: int Into; /* into is one if this is a copy into file */ 75: 76: char Inbuf[BUFSIZ]; /* input holder */ 77: char Outbuf[BUFSIZ]; /* output holder */ 78: 79: long Tupcount; /* number of tuples processed */ 80: char *Relname; /* name of relation */ 81: long Duptuple; /* number of duplicate tuples */ 82: long Baddoms; /* number of domains with control chars */ 83: long Truncount; /* number of truncations on a c0 field */ 84: int Piped[2]; /* pipe descriptor for copy communication */ 85: char *Cpdomains[] = /* dummy domain names for copy "into" */ 86: { 87: "nl", "\n", 88: "tab", "\t", 89: "sp", " ", 90: "nul", "\0", 91: "null", "\0", 92: "comma", ",", 93: "colon", ":", 94: "dash", "-", 95: "lparen", "(", 96: "rparen", ")", 97: 0 98: }; 99: 100: char Delimitor[] = ",\n\t"; /* default delims for c0 & d0 */ 101: 102: 103: 104: copy(pc,pv) 105: int pc; 106: PARM pv[]; 107: { 108: extern char *Usercode; 109: extern int Noupdt; 110: register int i, pid; 111: register char *cp; 112: int stat; 113: int copydone(); 114: int op; 115: 116: # ifdef xZTR1 117: if (tTf(30,1)) 118: { 119: printf("entered copy\n"); 120: prvect(pc, pv); 121: } 122: # endif 123: Duptuple = 0; 124: Truncount = 0; 125: Tupcount = 0; 126: Baddoms = 0; 127: Relname = pv[0].pv_val.pv_str; 128: Into = (pv[pc-2].pv_val.pv_str[0] == 'i'); 129: Filename = pv[pc-1].pv_val.pv_str; 130: 131: /* relation must exist and not be a system relation */ 132: /* in addition a copy "from" can't be done if the user */ 133: /* doesn't own the relation */ 134: /* and furthermore it can't have an index */ 135: i = 0; /* assume all is well */ 136: if (op = openr(&Des, OR_WRITE, Relname)) 137: { 138: if (op == AMOPNVIEW_ERR) 139: i = NOCPVIEW; 140: else 141: { 142: if (op < 0) 143: syserr("COPY: openr 1 (%.14s) %d", Relname, op); 144: else 145: /* non-existant relation */ 146: i = NOEXIST; 147: } 148: } 149: else 150: { 151: if (Into) 152: { 153: if ((Des.reldum.relstat & S_PROTALL) 154: && (Des.reldum.relstat & S_PROTRET) 155: && !bequal(Usercode, Des.reldum.relowner, UCODE_SZ)) 156: i = RELPROTECT; 157: } 158: else 159: { 160: /* extra checking if this is a copy "from" */ 161: 162: /* must be owned by the user */ 163: if (!bequal(Usercode, Des.reldum.relowner, UCODE_SZ)) 164: i = NOTOWNER; 165: else 166: /* must be updateable */ 167: if ((Des.reldum.relstat & S_NOUPDT) && Noupdt) 168: i = NOUPDT; 169: else 170: /* must not be indexed */ 171: if (Des.reldum.relindxd > 0) 172: i = DESTINDEX; 173: } 174: } 175: if (i) 176: { 177: closer(&Des); 178: return (error(i, Relname, 0)); /* relation doesn't exist for this user */ 179: } 180: 181: /* check that file name begins with a "/" */ 182: cp = Filename; 183: while (*cp == ' ') 184: cp++; 185: if (*cp != '/') 186: { 187: closer(&Des); 188: return (error(FULLPATH, Filename, 0)); 189: } 190: 191: /* fill map structures with transfer information */ 192: if (i = mapfill(&pv[1])) 193: { 194: closer(&Des); 195: return (i); /* error in user semantics */ 196: } 197: 198: /* fork a child process which will run as the real user */ 199: /* that child will complete the copy and exit */ 200: if (pipe(Piped)) 201: syserr("copy:can't make pipe"); 202: if ((pid = fork()) < 0) 203: syserr("copy:can't fork"); 204: if (pid) 205: { 206: /* the ingres parent */ 207: close(Piped[1]); 208: ruboff(0); /* interrupts off */ 209: stat = fullwait(pid, "copy"); 210: if (read(Piped[0], &Des.reladds, 4) != 4) 211: syserr("copy:can't read pipe"); 212: close(Piped[0]); 213: closer(&Des); /* close the rel */ 214: rubon(); 215: /* if stat is != 0 then add on 5800 for error */ 216: if (stat) 217: stat += 5800; 218: return (stat); /* done */ 219: } 220: 221: /* the child. change to run as the real user */ 222: if (signal(SIGINT, SIG_IGN) != SIG_IGN) 223: signal(SIGINT, copydone); /* clean up on rubout */ 224: setuid(getuid()); 225: # ifndef xB_UNIX 226: setgid(getgid()); 227: # endif 228: if (Into) /* from relation into file */ 229: { 230: if ((File_iop = fopen(Filename, "w")) == NULL) /* create file for user */ 231: i = nferror(NOFILECRT, Filename, 0); /* cant create file */ 232: else 233: { 234: if (Lockrel) /* set a shared lock on relation*/ 235: setrll(A_SLP, Des.reltid.ltid, M_SHARE); 236: i = rel_file(); 237: } 238: } 239: else /* from UNIX file into relation */ 240: { 241: if ((File_iop = fopen(Filename, "r")) == NULL) 242: i = nferror(NOFILEOPN, Filename, 0); /* cant open user file */ 243: else 244: { 245: if (Lockrel) /* set an exclusive lock on relat*/ 246: setrll(A_SLP, Des.reltid.ltid, M_EXCL); 247: i = file_rel(); 248: if (Duptuple) 249: nferror(DUPTUPS, locv(Duptuple), 0); /* warning only */ 250: if (Baddoms) 251: nferror(BADDOMS, locv(Baddoms), 0); /* warning only */ 252: } 253: } 254: copydone(i); 255: } 256: /* 257: ** Finish up and exit after a copy or interrupt 258: ** 259: ** I is the return code. Since only a byte can be 260: ** returned, only the least significant 2 decimal 261: ** digits are returned. i is either 0 or a number like 58?? 262: */ 263: 264: copydone(i) 265: int i; 266: { 267: if (Lockrel) /* unlock relation */ 268: unlrl(Des.reltid.ltid); 269: if (Truncount) 270: nferror(TRUNCCHARS, locv(Truncount), 0); /* warning only */ 271: /* force the updates to be flushed */ 272: cleanrel(&Des); 273: if (File_iop) 274: fclose(File_iop); 275: if (write(Piped[1], &Des.reladds, 4) != 4) 276: syserr("copyc:can't writepipe"); 277: exit (i % 100); 278: } 279: /* 280: ** REL_FILE -- copy from relation to file 281: */ 282: 283: rel_file() 284: { 285: int j; 286: struct tup_id tid, limtid; 287: char *cp, save; 288: register int offset; 289: register int i; 290: register struct map *mp; 291: 292: /* set scan limits to scan the entire relation */ 293: if (find(&Des, NOKEY, &tid, &limtid)) 294: syserr("find error"); 295: 296: while ((i = get(&Des, &tid, &limtid, Inbuf, 1)) == 0) 297: { 298: mp = Map; 299: offset = 0; 300: for (i = 0; i < Mapcount; i++) 301: { 302: /* 303: ** For cases of char to numeric conversion, 304: ** there must be a null byte at the end of the 305: ** string. The character just past the current 306: ** domain is saved an a null byte inserted 307: */ 308: 309: cp = &Inbuf[mp->roffset + mp->rlen]; /* compute address */ 310: save = *cp; /* get the character */ 311: *cp = '\0'; /* insert a null */ 312: 313: /* 314: ** Special case, we want to copy the tid 315: */ 316: if ( mp->roffset == -1 ) 317: j = transfer(&tid,mp->rtype,mp->rlen, 318: mp->ftype,mp->flen,offset); 319: else 320: j = transfer(&Inbuf[mp->roffset], mp->rtype, 321: mp->rlen, mp->ftype, mp->flen, offset); 322: if (j) 323: { 324: /* bad ascii to numeric conversion or field length too small */ 325: return (nferror(j, mp->paramname, &Inbuf[mp->roffset], locv(Tupcount), Relname, Filename, 0)); 326: } 327: *cp = save; /* restore the saved character */ 328: offset += mp->flen; 329: mp++; 330: } 331: Tupcount++; 332: if (fwrite(Outbuf, 1, offset, File_iop) != offset) 333: syserr("copy:cant write to user file %s", Filename); 334: } 335: if (i < 0) 336: syserr("bad get from rel %d", i); 337: return (0); 338: } 339: /* 340: ** file_rel is called to transfer tuples from 341: ** the input file and append them to the relation 342: ** 343: ** Char domains are initialized to blank and numeric 344: ** domains are initialized to zero. 345: */ 346: 347: file_rel() 348: { 349: register int i, j; 350: register struct map *mp; 351: struct tup_id tid; 352: 353: clr_tuple(&Des, Outbuf); 354: 355: /* copy domains until an end of file or an error */ 356: for (;;) 357: { 358: mp = Map; 359: for (i = 0; i < Mapcount; i++) 360: { 361: if ((j = bread(mp)) <= 0) 362: { 363: if (j < 0) 364: { 365: i = 1; /* force an error */ 366: j = UNDETC0; /* unterminated string */ 367: } 368: else 369: j = UNEXEOF; /* end of file */ 370: if (i) /* error only if end of file during a tuple or unterminated string */ 371: { 372: i = nferror(j, mp->paramname, locv(Tupcount), Filename, Relname, 0); 373: } 374: return (i); 375: } 376: j = transfer(Inbuf, mp->ftype, mp->flen, mp->rtype, mp->rlen, mp->roffset); 377: if (j) 378: { 379: /* bad ascii to numeric or field length too small */ 380: return (nferror(j, mp->paramname, Inbuf, locv(Tupcount), Filename, Relname, 0)); 381: } 382: mp++; 383: } 384: Tupcount++; 385: if ((j = insert(&Des, &tid, Outbuf, 1)) < 0) 386: syserr("insert error %d rel=%s", j, Relname); 387: if (j == 1) 388: Duptuple++; 389: mp++; 390: } 391: /* 392: ** This statement was here -- i don'T think it does anything, but we'll see 393: ** return (0); 394: */ 395: } 396: /* 397: ** transfer copies data from "*in" to 398: ** Outbuf doing conversions whenever 399: ** necessary 400: */ 401: 402: transfer(in, sf, sl, df, dl, doff) 403: ANYTYPE *in; /* pointer to input chars */ 404: char sf; /* source format */ 405: int sl; /* source length */ 406: char df; /* destination format */ 407: int dl; /* destination length */ 408: int doff; /* destination offset */ 409: { 410: register char *outp; 411: register ANYTYPE *inp; 412: register int i; 413: int j; 414: short smalli; 415: char temp[MAXFIELD]; /* holds char during conversions to ascii */ 416: float f; 417: double d; 418: long l; 419: 420: 421: outp = &Outbuf[doff]; 422: inp = in; 423: 424: if (sf == DUMMY) 425: /* if source format is a dummy fields then 426: nothing else need be done */ 427: return (0); 428: 429: if (df == DUMMY) 430: { 431: /* fill field with dummy domain character */ 432: i = dl; /* i equals the number of chars */ 433: while (i--) 434: *outp++ = sf; /* sf holds dummy char */ 435: return (0); 436: } 437: 438: if (sf != CHAR) 439: { 440: if (df == CHAR) /* numeric to char conversion */ 441: { 442: switch (sl) 443: { 444: /* int of size 1 or 2 */ 445: case 1: 446: itoa(inp->i1type, temp); 447: break; 448: 449: case 2: 450: itoa(inp->i2type, temp); /* convert to ascii */ 451: break; 452: 453: /* int or float of size 4 */ 454: case 4: 455: if (sf == INT) 456: { 457: smove(locv(inp->i4type), temp); /* convert and copy */ 458: } 459: 460: else 461: { 462: ftoa(inp->f4type, temp, dl, Out_arg.f4prec, Out_arg.f4style); 463: } 464: break; 465: 466: /* float of size 8 */ 467: case 8: 468: ftoa(inp->f8type, temp, dl, Out_arg.f8prec, Out_arg.f8style); 469: break; 470: 471: /* there is no possible default */ 472: default: 473: syserr("bad domain length %d",sl); 474: } 475: 476: j = length(temp); 477: if ((i = dl - j) < 0) 478: return (5808); /* field won't fit */ 479: 480: /* blank pad from left. Number will be right justified */ 481: while (i--) 482: *outp++ = ' '; 483: 484: bmove(temp, outp, j); 485: return (0); 486: } 487: 488: if (convert(inp, outp, sf, sl, df, dl)) /* numeric to numeric transfer */ 489: return (DOMTOOSMALL); /* numeric truncation error */ 490: return (0); 491: } 492: 493: /* character to numeric conversion */ 494: /* and character to character conversion */ 495: switch (df) 496: { 497: 498: case CHAR: 499: i = sl; 500: if (!i) 501: { 502: i = length(inp->c0type); 503: } 504: if (i > dl) 505: i = dl; 506: if (charmove(inp->c0type, outp, i)) 507: Baddoms++; 508: for (outp += i; i<dl; i++) 509: *outp++ = ' '; 510: return (0); 511: 512: case FLOAT: 513: if (atof(inp->c0type, &d)) 514: return (BADINPUT); /* bad conversion to numeric */ 515: if (dl == 8) 516: bmove(&d, outp, dl); 517: else 518: { 519: f = d; /* f8 to f4 conversion */ 520: bmove(&f, outp, dl); 521: } 522: return (0); 523: 524: case INT: 525: if (dl == 4) 526: { 527: if (atol(inp->c0type, &l)) 528: return (5809); 529: bmove(&l, outp, 4); 530: return (0); 531: } 532: smalli = atoi(inp->c0type); 533: if ((dl == 1) && ((smalli < -128) || (smalli > 127))) 534: return (5809); 535: bmove(&smalli, outp, dl); 536: return (0); 537: } 538: } 539: /* 540: ** moves a character string from "in" 541: ** to "out" removing any control characters. 542: ** returns true if any control characters were found 543: */ 544: 545: charmove(in, out, length) 546: char *in, *out; 547: int length; 548: { 549: register char *ip, *op; 550: register int l; 551: int bad; 552: 553: bad = FALSE; 554: ip = in; 555: op = out; 556: l = length; 557: 558: while (l--) 559: if ((*op++ = *ip++) < ' ') 560: { 561: *(op-1) = ' '; 562: bad = TRUE; 563: } 564: return (bad); 565: } 566: /* 567: ** Mapfill fills the Map structure with the list 568: ** of user supplied attributes. It then reads 569: ** the list of relation attributes and checks 570: ** for matching attribute names. 571: ** 572: ** if an error occures then mapfill returns -1 573: ** else it returns 0 574: ** 575: ** Mapfill performs special processing on 576: ** dummy domains. 577: ** 578: ** If no user attributes are given, then "given"=FALSE 579: ** and each attribute in the relation is set up to be 580: ** copied in the formats and order in which they 581: ** exist in the relation 582: */ 583: 584: mapfill(aptr) 585: PARM aptr[]; 586: { 587: register PARM *ap; 588: register struct map *mp; 589: register int i; 590: char *fp; 591: extern DESC Attdes; 592: struct attribute att; 593: struct tup_id tid, limtid; 594: int given, cnt; 595: char *zcheck(); 596: char *dumvalue(); 597: 598: Mapcount = 0; 599: mp = Map; 600: ap = aptr; 601: 602: /* Gather list of user supplied attributes */ 603: 604: while (*(ap->pv_val.pv_str) != '\0') 605: { 606: /* check for overflow */ 607: if (Mapcount == MAXMAP) 608: return (error(TOOMANYATTR, 0)); /* more than MAXMAP specifiers */ 609: 610: mp->paramname = (ap->pv_val).pv_str; /* save pointer to user supplied name */ 611: pmove(((ap++)->pv_val).pv_str, mp->name, MAXNAME, ' '); 612: fp = ((ap++)->pv_val).pv_str; /* fp points to format string */ 613: mp->used = 0; 614: mp->rlen = 0; /* zero in case this is a dummy domain */ 615: mp->roffset = 0; 616: mp->fdelim = 0; 617: /* check domain type in *fp */ 618: switch (*fp++) 619: { 620: 621: case 'c': 622: i = CHAR; 623: if ((mp->fdelim = zcheck(fp)) == 0) 624: return (-1); /* bad delimitor */ 625: break; 626: 627: case 'f': 628: i = FLOAT; 629: break; 630: 631: case 'i': 632: i = INT; 633: break; 634: 635: case DUMMY: 636: i = DUMMY; 637: if ((mp->fdelim = zcheck(fp)) == 0) 638: return (-1); 639: break; 640: 641: default: 642: return (error(BADATTRTYPE, mp->paramname, --fp, 0)); 643: } 644: mp->ftype = i; 645: 646: 647: /* convert format length to binary */ 648: mp->flen = atoi(fp); 649: if (mp->flen < 0 || 650: mp->flen > 511 || 651: (mp->ftype == FLOAT && mp->flen != 4 && mp->flen != 8) || 652: (mp->ftype == INT && mp->flen != 1 && mp->flen != 2 && mp->flen != 4)) 653: { 654: return (error(BADATTRLEN, mp->paramname, --fp, 0)); /* bad length for attribute */ 655: } 656: 657: /* process dummy domain if any */ 658: if (Into && mp->ftype == DUMMY && mp->flen) 659: { 660: if ((fp = dumvalue(mp->paramname)) == 0) 661: return (5807); /* bad dummy name */ 662: mp->rtype = *fp; /* use first char of string */ 663: } 664: 665: /* check for format of type "c0delim" on copy "into" */ 666: if (Into && mp->flen == 0 && mp->fdelim != Delimitor) 667: { 668: fp = mp->fdelim; 669: 670: /* is there room for a dummy domain? */ 671: mp++; 672: if (++Mapcount == MAXMAP) 673: return (error(TOOMANYATTR, 0)); /* no room */ 674: 675: /* create a dummy entry */ 676: mp->ftype = DUMMY; 677: mp->flen = 1; 678: mp->rtype = *fp; 679: mp->roffset = mp->rlen = 0; 680: } 681: 682: mp++; 683: Mapcount++; 684: } 685: /* if no atributes were given, set flag */ 686: if (Mapcount) 687: given = TRUE; 688: else 689: given = FALSE; 690: 691: /* open attribute relation and prepare for scan */ 692: opencatalog("attribute", OR_READ); 693: 694: setkey(&Attdes, &att, Des.reldum.relid, ATTRELID); 695: setkey(&Attdes, &att, Des.reldum.relowner, ATTOWNER); 696: 697: if (find(&Attdes, EXACTKEY, &tid, &limtid, &att)) 698: syserr("find error for att-rel"); 699: 700: /* scan Map for each relation attribute */ 701: while ((i = get(&Attdes, &tid, &limtid, &att, 1)) == 0) 702: { 703: if (!bequal(&Des, &att, MAXNAME+2)) 704: continue; 705: /* if no user attributes were supplied, fake an entry */ 706: if (!given) 707: { 708: Mapcount++; 709: mp = &Map[att.attid -1]; 710: mp->rtype = mp->ftype = att.attfrmt; 711: mp->rlen = mp->flen = att.attfrml & I1MASK; 712: mp->roffset = att.attoff; 713: mp->used = 1; 714: mp->paramname = mp->name; /* point to name */ 715: bmove(att.attname, mp->name, MAXNAME); /* copy name */ 716: continue; 717: } 718: mp = Map; 719: 720: /* check each user domain for match with relation domain */ 721: for (i = Mapcount; i--; mp++) 722: { 723: if (mp->ftype == DUMMY) 724: continue; /* ignore dummy */ 725: if (!bequal(mp->name, att.attname, 12)) 726: continue; 727: 728: mp->rtype = att.attfrmt; 729: mp->rlen = att.attfrml & I1MASK; 730: mp->roffset = att.attoff; 731: mp->used++; 732: 733: /* check for special case of C0 in a copy "into" */ 734: if (Into && (mp->flen == 0) && mp->ftype == CHAR) 735: { 736: switch (mp->rtype) 737: { 738: case CHAR: 739: mp->flen = mp->rlen; 740: break; 741: 742: case INT: 743: switch (mp->rlen) 744: { 745: 746: case 1: 747: mp->flen = Out_arg.i1width; 748: break; 749: 750: case 2: 751: mp->flen = Out_arg.i2width; 752: break; 753: 754: case 4: 755: mp->flen = Out_arg.i4width; 756: } 757: break; 758: 759: case FLOAT: 760: if (mp->rlen == 4) 761: mp->flen = Out_arg.f4width; 762: else 763: mp->flen = Out_arg.f8width; 764: } 765: } 766: /* if this is a copy "from" then break 767: otherwise continue. In a copy "into" 768: an attribute might be copied more than once */ 769: if (!Into) 770: break; 771: } 772: } 773: if (i < 0) 774: syserr("bad get from att-rel %d", i); 775: 776: /* check that all user domains have been identified */ 777: cnt = 0; 778: mp = Map; 779: for (i = Mapcount; i--; mp++) 780: { 781: cnt += mp->flen; 782: if (mp->ftype == DUMMY) 783: continue; 784: if (!mp->used) 785: { 786: if ( Into && bequal(mp->name,"tid ",12) ) 787: { 788: mp->flen = 4; 789: mp->rtype = INT; 790: mp->rlen = 4; 791: mp->roffset = -1; 792: mp->used++; 793: } 794: else 795: return (error(ATTRNOEXIST, mp->paramname, Relname, 0)); /* unrecognizable domain name */ 796: } 797: } 798: /* check that copy into doesn't exceed buffer size */ 799: if (Into && cnt > BUFSIZ) 800: return (error(FILETOOWIDE, 0)); /* cnt too large */ 801: return (0); 802: } 803: /* 804: ** BREAD 805: */ 806: 807: bread(mp) 808: struct map *mp; 809: { 810: register int count, i; 811: register char *inp; 812: char *dl; 813: int esc; /* escape flag */ 814: 815: count = mp->flen; 816: inp = Inbuf; 817: 818: if (count) 819: { 820: /* block mode. read characters */ 821: i = fread(inp, 1, count, File_iop); 822: 823: /* null terminate */ 824: *(inp + count) = '\0'; 825: 826: return (i == count); /* true -> normal, false ->eof */ 827: } 828: 829: /* string mode read */ 830: /* 831: ** Determine the maximum size the C0 field being read can be. 832: ** In the case where it is being copied into a CHAR field, then 833: ** the size is that of the char field (+1 for the delimitor). 834: ** In the case of a numeric, it is limited only by the size of the 835: ** buffer area. 836: */ 837: count = mp->rtype == CHAR ? mp->rlen + 1 : BUFSIZ; 838: esc = FALSE; 839: 840: for (;;) 841: { 842: if ((i = getc(File_iop)) == EOF) 843: return (inp == Inbuf ? 0 : -1); /* -1 -> unexpected EOF, 0 -> normal EOF */ 844: 845: if (count > 0) 846: { 847: count--; 848: *inp++ = i; 849: } 850: else 851: { 852: if (count == 0) 853: { 854: /* determine type of overflow */ 855: if (mp->rtype == CHAR) 856: { 857: Truncount++; 858: count--; /* read until delim */ 859: } 860: else 861: { 862: return (-1); 863: } 864: } 865: } 866: if (esc) 867: { 868: esc = FALSE; 869: continue; 870: } 871: if (i == ESCAPE) 872: { 873: esc = TRUE; 874: /* 875: ** If esc was stored, back it up. 876: */ 877: if (count >= 0) 878: { 879: inp--; /* remove escape char */ 880: count++; /* restore counter */ 881: } 882: } 883: else 884: { 885: for (dl = mp->fdelim; *dl; dl++) 886: if (*dl == i) 887: { 888: *(inp-1) = '\0'; 889: return (1); 890: } 891: } 892: } 893: } 894: /* 895: ** Look for the existence of a param of the 896: ** form "0nl" or "00comma" etc. 897: ** 898: ** Returns the correct delim list or 0 899: ** if there was a user error 900: ** 901: ** If successful, a null is inserted at the 902: ** rightmost '0' so the subsequent atoi will work. 903: */ 904: 905: char * 906: zcheck(param) 907: char *param; 908: { 909: register char *np, *ret; 910: 911: np = param; 912: ret = Delimitor; /* assume default delimitors */ 913: 914: if (*np++ == '0') 915: { 916: /* we have a starting zero. trim the rest */ 917: while (*np == '0') 918: np++; 919: 920: if (*np > '9' || (*np < '0' && *np >= ' ')) 921: { 922: /* we have a special delim on a 0 width field */ 923: if (ret = dumvalue(np)) 924: *(--np) = '\0'; /* 925: ** end string before delim 926: ** Do not alter delimitor but 927: ** instead destroy last '0'. 928: */ 929: } 930: } 931: return (ret); 932: } 933: /* 934: ** Search list of valid dummy names looking 935: ** for 'name'. If 'name' is a single char 936: ** then use just that name else it is 937: ** an error if the name is not found 938: */ 939: 940: char * 941: dumvalue(name) 942: char *name; 943: { 944: register char **dp, *np, *ret; 945: 946: dp = Cpdomains; /* get list of valid dummy names */ 947: np = name; 948: ret = 0; 949: 950: /* first look for a matching key word */ 951: while (*dp) 952: { 953: if (sequal(np, *dp++)) 954: { 955: ret = *dp; 956: break; 957: } 958: dp++; 959: } 960: 961: /* If single char, use that char */ 962: if (length(np) == 1) 963: ret = np; /* use first char of name */ 964: if (ret == 0) 965: error(UNRECDUMMY, np, 0); 966: 967: return (ret); 968: }