|
|
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.