|
|
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: # 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.