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: }

Defined functions

bread defined in line 807; used 1 times
charmove defined in line 545; used 1 times
copy defined in line 104; used 2 times
copydone defined in line 264; used 3 times
dumvalue defined in line 940; used 3 times
file_rel defined in line 347; used 1 times
mapfill defined in line 584; used 1 times
rel_file defined in line 283; used 1 times
transfer defined in line 402; used 3 times
zcheck defined in line 905; used 3 times

Defined variables

Baddoms defined in line 82; used 4 times
CopyFn defined in line 31; never used
Cpdomains defined in line 85; used 1 times
Delimitor defined in line 100; used 2 times
Duptuple defined in line 81; used 4 times
Filename defined in line 72; used 11 times
Inbuf defined in line 76; used 8 times
Into defined in line 74; used 9 times
Map defined in line 61; used 6 times
Mapcount defined in line 64; used 10 times
Outbuf defined in line 77; used 4 times
Piped defined in line 84; used 5 times
Relname defined in line 80; used 9 times
Truncount defined in line 83; used 4 times
Tupcount defined in line 79; used 6 times

Defined struct's

map defined in line 48; used 10 times

Defined macros

DUMMY defined in line 24; used 7 times
ESCAPE defined in line 25; used 1 times
MAXMAP defined in line 23; used 3 times
Last modified: 1986-04-17
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2199
Valid CSS Valid XHTML 1.0 Strict