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