1 /***********************************************************************/
2 /* Open Visualization Data Explorer                                    */
3 /* (C) Copyright IBM Corp. 1989,1999                                   */
4 /* ALL RIGHTS RESERVED                                                 */
5 /* This code licensed under the                                        */
6 /*    "IBM PUBLIC LICENSE - Open Visualization Data Explorer"          */
7 /***********************************************************************/
8 
9 #include <dxconfig.h>
10 
11 
12 #include <dx/dx.h>
13 #include <stdio.h>
14 #include <ctype.h>
15 #include <string.h>
16 #include <stdarg.h>
17 #include <stdlib.h>
18 
19 #if defined(HAVE_SYS_ERRNO_H)
20 #include <sys/errno.h>
21 #endif
22 
23 #if defined(HAVE_ERRNO_H)
24 #include <errno.h>
25 #endif
26 
27 #if defined(HAVE_SYS_FILE_H)
28 #include <sys/file.h>
29 #endif
30 
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <math.h>
34 
35 #if ! DXD_HAS_UNIX_SYS_INCLUDES
36 typedef unsigned long mode_t;
37 #endif
38 
39 #include "edf.h"
40 
41 #include <stdlib.h>
42 
43 #if  defined(DXD_NON_UNIX_DIR_SEPARATOR)
44 #define DX_DIR_SEPARATOR ';'
45 #else
46 #define DX_DIR_SEPARATOR ':'
47 #endif
48 /* prototypes
49  */
50 
51 static Error check_parms(struct getby *gp, char *fname, char **namelist,
52 			 int *start, int *end, int *delta);
53 static Error is_dir(FILE *fp, char *name);
54 
55 #if DXD_POPEN_OK && DXD_HAS_LIBIOP
56 #define popen popen_host
57 #define pclose pclose_host
58 #endif
59 
60 
61 /* messages about components and their consistency with each other
62  */
63 #define Err_MustBeString      "#10700"
64 #define Err_MustBeStringList  "#10701"
65 #define Err_MissingComp       "#10702"
66 #define Wrn_NotPosConnFac     "#10704"
67 #define Err_NotArray          "#10706"
68 #define Err_DiffCount         "#10708"
69 #define Err_RefNotInt         "#10710"
70 #define Err_BadElemType       "#10712"
71 #define Err_OutOfRange        "#10714"
72 
73 
ending(int num)74 static char *ending(int num)
75 {
76     switch(num % 10) {
77       case 1:
78 	return (num%100)==11 ? "th" : "st";
79 
80       case 2:
81 	return (num%100)==12 ? "th" : "nd";
82 
83       case 3:
84 	return (num%100)==13 ? "th" : "rd";
85     }
86 
87     return "th";
88 }
89 
elemtypecheck(int num,char * str)90 static Error elemtypecheck(int num, char *str)
91 {
92     char rightstr[20];
93 
94     switch(num) {
95       case 0:
96 	strcpy(rightstr, "points");
97 	break;
98       case 1:
99 	strcpy(rightstr, "lines");
100 	break;
101       case 2:
102 	strcpy(rightstr, "quads");
103 	break;
104       case 3:
105 	strcpy(rightstr, "cubes");
106 	break;
107       default:
108 	sprintf(rightstr, "cubes%dD", num);
109 	break;
110     }
111 
112     if (strcmp(rightstr, str)) {
113 	DXSetError(ERROR_DATA_INVALID, Err_BadElemType, str, rightstr);
114 	return ERROR;
115     }
116 
117     return OK;
118 }
119 
120 Error
_dxfValidate(Field f)121 _dxfValidate(Field f)
122 {
123     Array current = NULL;
124     Array target = NULL;
125     char *tname, *cname;
126     int ncurrent, ntarget, *ip;
127     int index;
128     unsigned char *cp;
129     int i, j, lim, nitems;
130     Type type, ref_type;
131     Category cat;
132     String s = NULL;
133     Object o = NULL;
134     int rank, shape[MAXRANK];
135     int counts[MAXRANK];
136 
137     for (i=0; (current=(Array)DXGetEnumeratedComponentValue(f, i, &cname)); i++) {
138 
139 	/* dep */
140 	if ((s = (String)DXGetAttribute((Object)current, "dep")) != NULL) {
141 	    /* make sure number of items matches number of items in dep */
142 	    if ((DXGetObjectClass((Object)s) != CLASS_STRING) ||
143 	        ((tname = DXGetString(s)) == NULL)) {
144 		DXSetError(ERROR_DATA_INVALID,
145 			 Err_MustBeString, "dep", cname);
146 		return ERROR;
147 	    }
148 
149 	    if ((target = (Array)DXGetComponentValue(f, tname)) == NULL) {
150 		DXSetError(ERROR_DATA_INVALID,
151 			 Err_MissingComp, tname, "dep", cname);
152 		return ERROR;
153 	    }
154 
155 	    if (DXGetObjectClass((Object)target) != CLASS_ARRAY) {
156 		DXSetError(ERROR_DATA_INVALID,
157 			 Err_NotArray, tname, "dep", cname);
158 		return ERROR;
159 	    }
160 
161 	    if (!DXGetArrayInfo(current, &nitems, &type, &cat, &rank, shape))
162 		return ERROR;
163 
164 	    ncurrent = nitems;
165 
166 	    if (!DXGetArrayInfo(target, &nitems, &type, &cat, &rank, shape))
167 		return ERROR;
168 
169 	    ntarget = nitems;
170 
171 	    if (ncurrent != ntarget) {
172 		DXSetError(ERROR_DATA_INVALID,
173 			 Err_DiffCount, "dep",
174 			 ncurrent, cname, ntarget, tname);
175 		return ERROR;
176 	    }
177 
178 	} /* end of if (has dep) */
179 
180 
181 	/* ref */
182 	if ((s = (String)DXGetAttribute((Object)current, "ref")) != NULL) {
183 	    if ((DXGetObjectClass((Object)s) != CLASS_STRING) ||
184 	        ((tname = DXGetString(s)) == NULL)) {
185 		DXSetError(ERROR_DATA_INVALID,
186 			   Err_MustBeString, "ref", cname);
187 		return ERROR;
188 	    }
189 
190 	    if ((target = (Array)DXGetComponentValue(f, tname)) == NULL) {
191 		DXSetError(ERROR_DATA_INVALID,
192 			   Err_MissingComp, tname, "ref", cname);
193 		return ERROR;
194 	    }
195 
196 	    if (DXGetObjectClass((Object)target) != CLASS_ARRAY) {
197 		DXSetError(ERROR_DATA_INVALID,
198 			   Err_NotArray, tname, "ref", cname);
199 		return ERROR;
200 	    }
201 
202 	    if (!DXGetArrayInfo(current, &nitems, &type, &cat, &rank, shape))
203 		return ERROR;
204 
205 	    if ( !( type == TYPE_INT || type == TYPE_UBYTE ) ) {
206 		DXSetError(ERROR_DATA_INVALID, Err_RefNotInt, cname);
207 		return ERROR;
208 	    }
209 	    ref_type = type;
210 
211 	    ncurrent = nitems;
212 	    for (j=0; j<rank; j++)
213 	        ncurrent *= shape[j];
214 
215 	    if (ncurrent > 0) {
216 
217 		if (!DXGetArrayInfo(target, &nitems, &type, &cat, &rank, shape))
218 		    return ERROR;
219 
220 		ntarget = nitems;
221 
222                 /* only do this if they are already irregular */
223                 if (DXGetArrayClass(current) == CLASS_ARRAY) {
224                     if ((ip = (int *)DXGetArrayData(current)) == NULL)
225                         return ERROR;
226 		    cp = (unsigned char *) ip;
227 
228 		    /* neighbors can have -1's as indicies */
229                     lim = strcmp(cname, "neighbors") ? 0 : -1;
230 
231 		    for (j=0; j < ncurrent; j++) {
232 			if (ref_type == TYPE_INT) index = *(ip++);
233 			else                      index = *(cp++);
234 
235 			if (index < lim || index >= ntarget) {
236 			    DXSetError(ERROR_DATA_INVALID, Err_OutOfRange,
237 				j+1, ending(j+1), cname, index, lim, ntarget-1);
238 			    return ERROR;
239 			}
240 		    }
241 
242                 } else if (DXQueryGridConnections(current, &rank, counts)) {
243 		    for (j=0, ncurrent=1; j<rank; j++)
244 			ncurrent *= counts[j];
245                     if (ncurrent > ntarget) {
246                         DXSetError(ERROR_DATA_INVALID,
247                                  Err_DiffCount, "ref",
248                                  ncurrent, cname, ntarget, tname);
249                         return ERROR;
250                     }
251                 } else {
252                     /* mesh array of mixed path and irregular arrays. */
253                     /* have to handle the terms separately */
254                 }
255 	    }
256 	} /* end of if (has ref) */
257 
258 
259         /* der - can be string lists here */
260 	if ((o = DXGetAttribute((Object)current, "der")) != NULL) {
261 
262 	    if (DXExtractString(o, &tname)) {    /* simple string? */
263 		if ((target = (Array)DXGetComponentValue(f, tname)) == NULL) {
264 		    DXSetError(ERROR_DATA_INVALID,
265 			       Err_MissingComp, tname, "der", cname);
266 		    return ERROR;
267 		}
268 
269 		if (DXGetObjectClass((Object)target) != CLASS_ARRAY) {
270 		    DXSetError(ERROR_DATA_INVALID,
271 			       Err_NotArray, tname, "der", cname);
272 		    return ERROR;
273 		}
274 	    } else if (DXExtractNthString(o, 0, &tname)) {  /* string list? */
275 		for (j=0; DXExtractNthString(o, j, &tname); j++) {
276 
277 		    if ((target = (Array)DXGetComponentValue(f, tname)) == NULL) {
278 			DXSetError(ERROR_DATA_INVALID,
279 				   Err_MissingComp, tname, "der", cname);
280 			return ERROR;
281 		    }
282 
283 		    if (DXGetObjectClass((Object)target) != CLASS_ARRAY) {
284 			DXSetError(ERROR_DATA_INVALID,
285 				   Err_NotArray, tname, "der", cname);
286 			return ERROR;
287 		    }
288 		}
289 	    } else {  /* neither string or string list */
290 		DXSetError(ERROR_DATA_INVALID,
291 			   Err_MustBeStringList, "der", cname);
292 		return ERROR;
293 	    }
294 
295 	} /* end of if (has der) */
296 
297         /* element type */
298 	if ((s = (String)DXGetAttribute((Object)current, "element type")) != NULL) {
299 	    if ((DXGetObjectClass((Object)s) != CLASS_STRING) ||
300 	        ((tname = DXGetString(s)) == NULL)) {
301 		DXSetError(ERROR_DATA_INVALID,
302 			 Err_MustBeString, "element type", cname);
303 		return ERROR;
304 	    }
305 
306 	    if (!strcmp(cname, "connections") &&
307 		DXQueryGridConnections(current, &rank, counts)) {
308 
309 		if (!elemtypecheck(rank, tname))
310 		    return ERROR;
311 	    }
312 
313 	} /* end of if (has element type) */
314 
315     }  /* for each component in the field */
316 
317     /* check for missing positions component if the field has more than
318      *  one component.
319      */
320     if (i > 1 && !DXGetComponentValue(f, "positions"))
321 	DXWarning("importing a field with no `positions' component");
322 
323     return OK;
324 }
325 
326 /* stolen from system.m (cpv's code)
327  */
328 #if !defined(DXD_POPEN_OK)
mkfifo(char * path,mode_t mode)329 static Error mkfifo(char *path, mode_t mode)
330 {
331     int rc;
332     char *cmd = (char *)DXAllocateLocal(strlen("mknod ") +
333 				      strlen(path) +
334 				      strlen(" p; chmod ") +
335 				      12 +
336 				      strlen(path) + 1);
337     sprintf(cmd, "mknod %s p; chmod 0%o %s", path, mode, path);
338     rc = system(cmd);
339 
340     DXFree((Pointer)cmd);
341     return (rc==0) ? OK : ERROR;
342 }
Unlink(char * path)343 static Error Unlink(char *path)
344 {
345     int rc;
346     char *cmd = (char *)DXAllocateLocal(strlen("rm -f") +
347 				      strlen(path) + 1);
348     sprintf(cmd, "rm -f %s", path);
349     rc = system(cmd);
350 
351     DXFree((Pointer)cmd);
352     return (rc==0) ? OK : ERROR;
353 }
354 #endif
355 
356 
357 
358 /*
359  *
360  * entry point for processing a file
361  *
362  */
363 
DXImportDX(char * filename,char ** namelist,int * start,int * end,int * delta)364 Object DXImportDX(char *filename, char **namelist,
365 		  int *start, int *end, int *delta)
366 {
367     struct finfo f;
368     Object o = NULL;
369     char needfree = 1;
370     int rc;
371 
372     /* setup finfo struct
373      */
374 
375     /* clear struct to be sure all pointers are NULL, and set stuff which
376      *  we know the value of now.  then call the init subroutine to finish
377      *  the rest of the initialization.
378      */
379     memset(&f, '\0', sizeof(f));
380 
381     f.fd = _dxfopen_dxfile(filename, NULL, &f.fname,".dx");
382     if (!f.fd)
383 	goto done;
384 
385     rc = check_parms(&f.gb, NULL, namelist, start, end, delta);
386     if (!rc)
387 	goto done;
388 
389     if (!f.fname) {
390 	f.fname = "<NULL>";
391 	needfree = 0;
392     }
393 
394     f.recurse = 0;
395     f.onepass = filename[0]=='!' ? 1 : 0;
396 
397     rc = _dxfinitfinfo(&f);
398     if (!rc) {
399 	if (needfree)
400 	    DXFree((Pointer)f.fname);
401 	DXFree((Pointer)f.gb.gbuf);
402 	return NULL;
403     }
404 
405 
406     /* read the file and construct the requested object
407      */
408     rc = _dxfparse_file(&f, &o);
409     if (!rc)
410 	goto done;
411 
412 
413   done:
414 #if DXD_POPEN_OK
415     _dxfclose_dxfile(f.fd, filename);   /* original filename possibly w/ ! */
416 #else
417     _dxfclose_dxfile(f.fd, filename);
418 #endif
419 
420     if (needfree)
421 	DXFree((Pointer)f.fname);
422 
423     DXFree((Pointer)f.gb.gbuf);
424 
425     _dxffreefinfo(&f);
426 
427     /* special routine which decrements ref count without deleting the object.
428      *  the object was referenced when added to the dictionary, so that
429      *  cleanup could delete all things not being returned.
430      */
431     if (o)
432 	DXUnreference(o);
433 
434     return o;
435 }
436 
437 
438 /* special internal entry point.  input is a single open stream pointer,
439  *  which can't be closed.  the caller has to ensure the file stream
440  *  is a valid open file or pipe, and the default object will be imported
441  *  and the format MUST be follows (can't seek on pipes, so can't look
442  *  for forward references to data).
443  */
_dxfImportDX_FD(FILE * fptr)444 Object _dxfImportDX_FD(FILE *fptr)
445 {
446     struct finfo f;
447     Object o = NULL;
448     int rc;
449 
450     /* setup finfo struct
451      */
452 
453     /* clear struct to be sure all pointers are NULL, and set stuff which
454      *  we know the value of now.   then call the init subroutine to finish
455      *  the rest of the initialization.
456      */
457     memset(&f, '\0', sizeof(f));
458 
459     rc = check_parms(&f.gb, NULL, NULL, NULL, NULL, NULL);
460     if (!rc)
461 	goto done;
462 
463     f.fd = fptr;
464     f.fname = "<NULL>";
465     f.recurse = 0;
466     f.onepass = 1;
467 
468     rc = _dxfinitfinfo(&f);
469     if (!rc) {
470 	DXFree((Pointer)f.gb.gbuf);
471 	return NULL;
472     }
473 
474 
475     /* read the file and construct the requested object
476      */
477     rc = _dxfparse_file(&f, &o);
478     if (!rc)
479 	goto done;
480 
481   done:
482 
483     DXFree((Pointer)f.gb.gbuf);
484     _dxffreefinfo(&f);
485 
486     /* special routine which decrements ref count without deleting the object.
487      *  the object was referenced when added to the dictionary, so that
488      *  cleanup could delete all things not being returned.
489      */
490     if (o)
491 	DXUnreference(o);
492 
493     return o;
494 }
495 
496 
497 
498 /*
499  * open a file, trying to append 'ext' and using each part of the DXDATA path
500  *  if the environment variable is defined.  if auxname is defined, use
501  *  the basename of that directory first before using the search path.
502  */
_dxfopen_dxfile(char * inname,char * auxname,char ** outname,char * ext)503 FILE *_dxfopen_dxfile(char *inname, char *auxname, char **outname,char *ext)
504 {
505     FILE *fd = NULL;
506     char *datadir = NULL, *cp;
507     char *basename = NULL;
508     int bytes = 0;
509     int rc;
510 
511     *outname = NULL;
512 
513     /* support for external filters
514      */
515     if (inname[0] == '!') {
516 	if (inname[1] == '\0') {
517 	    DXSetError(ERROR_BAD_PARAMETER, "#10200", "external filter name");
518 	    return NULL;
519 	}
520 
521 #if DXD_POPEN_OK
522 
523 	if ((fd = popen(inname+1, "r")) == NULL) {
524 	    DXSetError(ERROR_BAD_PARAMETER, "#10720", inname+1);
525 	    return NULL;
526 	}
527 	/* popen appears to succeed even if the program trying to
528 	 *  be run doesn't get started.  this is trying to test for
529 	 *  that case and give a more reasonable error message.
530 	 */
531 	if ((rc=fgetc(fd)) == EOF) {
532 	    DXSetError(ERROR_BAD_PARAMETER, "#10722", inname+1);
533 	    return NULL;
534 	} else
535 	    ungetc(rc, fd);
536 
537 	*outname = (char *)DXAllocateLocalZero(strlen(inname)+1);
538 	if (!*outname) {
539 	    pclose(fd);
540 	    return NULL;
541 	}
542 
543 	strcpy(*outname, inname+1);
544 
545         return fd;
546 
547 #else
548 #if os2
549         DXSetError(ERROR_BAD_PARAMETER, "'!' is not supported by os2");
550         return ERROR;
551 #else
552 
553         /* popen() is currently not supported on ibmpvs, so for now, use
554          *  a named pipe as a substitute.
555          */
556 #define TEMPLATE  "!/tmp/DXI%08d.0"
557 
558         bytes = strlen("(%s) > %s &") +
559                 strlen(inname) + 1 +
560                 strlen(TEMPLATE) + 6;
561 
562 	if ((cmd = (char *)DXAllocateLocalZero(bytes)) == NULL)
563 	    return NULL;
564 
565 	if ((*outname = (char *)DXAllocateLocalZero(strlen(TEMPLATE) + 6)) == NULL)
566 	    return NULL;
567 
568         pid = getpid();
569         sprintf(*outname, TEMPLATE, pid);
570 
571         if (mkfifo(*outname+1, 0600) == ERROR)
572             goto npipe_error;
573 
574         sprintf(cmd, "(%s) > %s &", inname+1, *outname+1);
575 
576         rc = system(cmd);
577         DXFree((Pointer) cmd);
578 
579         if (rc != 0)
580             goto npipe_error2;
581 
582         /* open for reading */
583 	DXDebug("F", "trying at (0) to open pipe");
584         fd = fopen(*outname+1, "r");
585         if (fd == NULL)
586             goto npipe_error;
587 
588 
589         return fd;
590 
591       npipe_error:
592         DXSetError(ERROR_DATA_INVALID, "%s: %s", *outname+1, strerror(errno));
593         Unlink(*outname+1);
594         return ERROR;
595 
596       npipe_error2:
597         DXSetError(ERROR_BAD_PARAMETER, "#10720", inname+1);
598         Unlink(*outname+1);
599         return ERROR;
600 #endif
601 #endif
602     }
603 
604 
605     /* try to open the filename as given, and save the name
606      *  for error messages later.
607      */
608     DXDebug("F", "trying at (1) to open `%s'", inname);
609     fd = fopen(inname, "r");
610     if (fd) {
611 	if (is_dir(fd, inname) != OK)
612 	    goto error;
613 
614 	*outname = (char *)DXAllocateLocalZero(strlen(inname)+1);
615 	if (!*outname)
616 	    goto error;
617 
618 	strcpy(*outname, inname);
619 	return fd;
620     }
621 
622 
623 #define XXTRA 12   /* space for the null, the / and .general - plus some extra */
624 
625     /* allocate space to construct variations of the given filename.
626      *  get enough space the first time so we can construct any variation
627      *  without having to reallocate.
628      */
629     bytes = strlen(inname) + XXTRA;
630     if (auxname)
631 	bytes += strlen(auxname);
632 
633     datadir = (char *)getenv("DXDATA");
634     if (datadir)
635 	bytes += strlen(datadir);
636 
637     *outname = (char *)DXAllocateLocalZero(bytes);
638     if (!*outname)
639 	goto error;
640 
641     /* name as given, with extension appended to the end
642      */
643     strcpy(*outname, inname);
644     strcat(*outname, ext);
645     DXDebug("F", "trying at (2) to open `%s'", *outname);
646     if ((fd=fopen(*outname, "r"))!=NULL) {
647 	if (is_dir(fd, *outname) != OK)
648 	    goto error;
649 
650 	DXMessage("opening file '%s'", *outname);
651 	return fd;
652     }
653 
654 
655     /* if absolute pathname, it's not found.
656      */
657 #if  defined(DXD_NON_UNIX_DIR_SEPARATOR)
658     if (inname[0] == '/' || inname[0] == '\\' || inname[1] == ':') {
659 #else
660     if (inname[0] == '/') {
661 #endif
662 	DXSetError(ERROR_BAD_PARAMETER, "#12240", inname);
663 	goto error;
664     }
665 
666 
667     /* on a recursive open, try the same directory as the parent file.
668      */
669     if (auxname != NULL) {
670 
671 	/* find basename, keeping the last '/' */
672 #if  defined(DXD_NON_UNIX_DIR_SEPARATOR)
673 	basename = strrchr(auxname, '/');
674 	if(!basename)
675 	    basename = strrchr(auxname, '\\');
676 	if(!basename)
677 	    basename = strrchr(auxname, ':');
678 #else
679 	basename = strrchr(auxname, '/');
680 #endif
681 	if (basename) {
682 
683 	    /* try basename + file */
684 	    strcpy(*outname, auxname);
685 	    (*outname)[basename-auxname+1] = '\0';
686 	    strcat(*outname, inname);
687 	    DXDebug("F", "trying at (3) to open `%s'", *outname);
688 	    if ((fd=fopen(*outname, "r"))!=NULL) {
689 		if (is_dir(fd, *outname) != OK)
690 		    goto error;
691 
692 		DXMessage("opening file '%s'", *outname);
693 		return fd;
694 	    }
695 
696 	    /* basename + file + extension */
697 	    strcat(*outname, ext);
698 	    DXDebug("F", "trying at (4) to open `%s'", *outname);
699 	    if ((fd=fopen(*outname, "r"))!=NULL) {
700 		if (is_dir(fd, *outname) != OK)
701 		    goto error;
702 
703 		DXMessage("opening file '%s'", *outname);
704 		return fd;
705 	    }
706 	}
707     }
708 
709 
710     /* if the DXDATA environment variable existed, try the list of
711      *  directory names.
712      */
713     while (datadir) {
714 
715 	strcpy(*outname, datadir);
716 	if ((cp = strchr(*outname, DX_DIR_SEPARATOR)) != NULL)
717 	    *cp = '\0';
718 	strcat(*outname, "/");
719 	strcat(*outname, inname);
720 	DXDebug("F", "trying at (5) to open `%s'", *outname);
721 	if ((fd=fopen(*outname, "r"))!=NULL) {
722 	    if (is_dir(fd, *outname) != OK)
723 		goto error;
724 
725 	    DXMessage("opening file '%s'", *outname);
726 	    return fd;
727 	}
728 
729 	strcat(*outname, ext);
730 	DXDebug("F", "trying at (6) to open `%s'", *outname);
731 	if ((fd=fopen(*outname, "r"))!=NULL) {
732 	    if (is_dir(fd, *outname) != OK)
733 		goto error;
734 
735 	    DXMessage("opening file '%s'", *outname);
736 	    return fd;
737 	}
738 
739 	datadir = strchr(datadir, DX_DIR_SEPARATOR);
740 	if (datadir)
741 	    datadir++;
742     }
743 
744     /* if you get here, you didn't find the file.  fall thru
745      *  into error section.
746      */
747     DXSetError(ERROR_BAD_PARAMETER, "#12240", inname);
748 
749   error:
750     if (*outname) {
751 	DXFree((Pointer)*outname);
752 	*outname = NULL;
753     }
754 
755     if (fd)
756 	fclose(fd);
757 
758     return NULL;
759 
760 }
761 
762 /* take care of pipes, if supported on this architecture
763  */
764 Error _dxfclose_dxfile(FILE *fptr, char *filename)
765 {
766 #if DXD_POPEN_OK
767     if (fptr) {
768 		if (filename[0] == '!') {
769 	    	pclose(fptr);
770 		} else {
771             fclose(fptr);
772         }
773     }
774 #else
775     if (fptr) {
776 	    fclose(fptr);
777 	    if (filename[0] == '!')
778 	        Unlink(filename+1);
779     }
780 
781 #endif
782 
783     return OK;
784 }
785 
786 
787 /*
788  * make sure the file pointer doesn't point to a directory.  on random
789  *  occasions we're gotten segfaults (which don't reproduce later) when
790  *  the file opened is a directory.
791  */
792 static Error is_dir(FILE *fp, char *fname)
793 {
794     struct stat sbuf;
795 
796     if (fstat(fileno(fp), &sbuf) < 0) {
797         DXSetError(ERROR_BAD_PARAMETER, "%s: %s", fname, strerror(errno));
798 	return ERROR;
799     }
800 
801     if (S_ISDIR(sbuf.st_mode)) {
802 	DXSetError(ERROR_BAD_PARAMETER, "%s is a directory", fname);
803 	return ERROR;
804     }
805 
806     return OK;
807 }
808 
809 /*
810  *  rangecheck input parms, and fill the 'getby' struct.
811  */
812 static Error check_parms(struct getby *gp, char *fname, char **namelist,
813 		  int *start, int *end, int *delta)
814 {
815     gp->which = GETBY_NONE;
816     gp->numlist = NULL;
817     gp->gbuf = NULL;
818 
819     gp->fname = fname;
820 
821     if (namelist && *namelist) {
822 	gp->which = GETBY_NAME;
823 	gp->namelist = namelist;
824     }
825 
826     gp->seriesflag = 0;
827 
828     if (start) {
829 	if (*start < 0) {
830 	    DXSetError(ERROR_BAD_PARAMETER, "#10030", "start");
831 	    return ERROR;
832 	}
833 	gp->seriesflag |= SL_START;
834 	gp->serieslim[0] = *start;
835     }
836     if (end) {
837 	if (*end < 0) {
838 	    DXSetError(ERROR_BAD_PARAMETER, "#10030", "end");
839 	    return ERROR;
840 	}
841 	gp->seriesflag |= SL_END;
842 	gp->serieslim[1] = *end;
843     }
844     if (delta) {
845 	if (*delta <= 0) {
846 	    DXSetError(ERROR_BAD_PARAMETER, "#10020", "delta");
847 	    return ERROR;
848 	}
849 	gp->seriesflag |= SL_DELTA;
850 	gp->serieslim[2] = *delta;
851     }
852 
853     if (start && end) {
854 	if (*start > *end) {
855 	    DXSetError(ERROR_BAD_PARAMETER, "#10185", "start", "end");
856 	    return ERROR;
857 	}
858     }
859 
860     return OK;
861 }
862 
863 /* initialize the finfo struct
864  */
865 Error _dxfinitfinfo(struct finfo *fp)
866 {
867 
868     /* initialize the dictionary
869      */
870     fp->d = (struct dict *)DXAllocateLocal(sizeof(struct dict));
871     if(!fp->d)
872         goto done;
873 
874     if (!_dxfinitdict(fp->d))
875         goto done;
876 
877     /* initialize the object list
878      */
879     if (!_dxfinitobjlist(fp))
880 	goto done;
881 
882 
883     /* initialize the parsing code
884      */
885     if (!_dxfinitparse(fp)) {
886 	DXSetError(ERROR_DATA_INVALID, "#10730", fp->fname);
887 	goto done;
888     }
889 
890 
891     return OK;
892 
893 
894   done:
895     _dxffreefinfo(fp);
896     return ERROR;
897 }
898 
899 
900 void _dxffreefinfo(struct finfo *fp)
901 {
902     _dxfdeleteparse(fp);
903 
904     _dxfdeletedict(fp->d);
905     DXFree((Pointer)fp->d);
906 
907     _dxfdeleteobjlist(fp);
908 }
909 
910 /* copy contents of finfo struct.
911  *  source, destination.
912  */
913 void _dxfdupfinfo(struct finfo *fp1, struct finfo *fp2)
914 {
915     memcpy((void *)fp2, (void *)fp1, sizeof(struct finfo));
916 }
917 
918 
919