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