1 /*********************************************************************
2  *   Copyright 1993, University Corporation for Atmospheric Research
3  *   See netcdf/README file for copying and redistribution conditions.
4  *   $Id$
5  *********************************************************************/
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <ctype.h>
11 #include <stdlib.h>
12 #include <unistd.h> /* for getopt() */
13 #include "local_nc.h"
14 
15 #include "ncdump.h"
16 #include "dumplib.h"
17 #include "vardata.h"
18 
19 static const char * type_name(nc_type type);
20 
21 char *progname;
22 struct ncdim dims[H4_MAX_NC_DIMS]; /* dimensions */
23 long vdims[H4_MAX_NC_DIMS];	/* dimension sizes for a single variable */
24 
25 static void
usage()26 usage()
27 {
28 #define USAGE   "\
29   [-V]             Display version of the HDF4 library and exit\n\
30   [-c]             Coordinate variable data and header information\n\
31   [-h]             Header information only, no data\n\
32   [-u]             Replace nonalpha-numerics in names with underscores\n\
33   [-v var1[,...]]  Data for variable(s) <var1>,... only\n\
34   [-b [c|f]]       Brief annotations for C or Fortran indices in data\n\
35   [-f [c|f]]       Full annotations for C or Fortran indices in data\n\
36   [-l len]         Line length maximum in data section (default 80)\n\
37   [-n name]        Name for netCDF (default derived from file name)\n\
38   [-d n[,n]]       Approximate floating-point values with less precision\n\
39   file             File name of input netCDF file\n"
40 
41     (void) fprintf(stderr,
42 		   "%s [-V|-c|-h|-u] [-v ...] [[-b|-f] [c|f]] [-l len] [-n name] [-d n[,n]] file\n%s",
43 		   progname,
44 		   USAGE);
45     exit(EXIT_FAILURE);
46 }
47 
48 
49 /*
50  * convert pathname of netcdf file into name for cdl unit, by taking
51  * last component of path and stripping off any extension.
52  */
53 static char *
name_path(path)54 name_path(path)
55      char *path;
56 {
57     char *cp, *new;
58 
59 #ifdef MSDOS
60 #define FILE_DELIMITER '\\'
61 #endif
62 #ifndef FILE_DELIMITER /* default to unix */
63 #define FILE_DELIMITER '/'
64 #endif
65     cp = strrchr(path, FILE_DELIMITER);
66     if (cp == 0)		/* no delimiter */
67       cp = path;
68     else			/* skip delimeter */
69       cp++;
70     new = (char *) malloc((unsigned) (strlen(cp)+1));
71     if (new == 0) {
72 	error("out of memory!");
73 	exit(EXIT_FAILURE);
74     }
75     (void) strcpy(new, cp);	/* copy last component of path */
76     if ((cp = strrchr(new, '.')) != NULL)
77       *cp = '\0';		/* strip off any extension */
78     return new;
79 }
80 
81 static const char *
type_name(type)82 type_name(type)
83      nc_type type;
84 {
85     switch (type) {
86       case NC_BYTE:
87 	return "byte";
88       case NC_CHAR:
89 	return "char";
90       case NC_SHORT:
91 	return "short";
92       case NC_LONG:
93 	return "long";
94       case NC_FLOAT:
95 	return "float";
96       case NC_DOUBLE:
97 	return "double";
98       default:
99 	error("type_name: bad type %d", type);
100 	return "bogus";
101     }
102 }
103 
104 /*
105  * Remove trailing zeros (after decimal point) but not trailing decimal
106  * point from ss, a string representation of a floating-point number that
107  * might include an exponent part.
108  */
109 static void
tztrim(ss)110 tztrim(ss)
111      char *ss;			/* returned string representing dd */
112 {
113     char *cp, *ep;
114 
115     cp = ss;
116     if (*cp == '-')
117         cp++;
118     while(isdigit((int)*cp) || *cp == '.')
119         cp++;
120     if (*--cp == '.')
121         return;
122     ep = cp+1;
123     while (*cp == '0')
124         cp--;
125     cp++;
126     if (cp == ep)
127         return;
128     while (*ep)
129         *cp++ = *ep++;
130     *cp = '\0';
131     return;
132 }
133 
134 /*
135  * Print list of attribute values.  Attribute values must be printed with
136  * explicit type tags, because their types are not declared.
137  */
138 static void
pr_att_vals(type,len,vals)139 pr_att_vals(type, len, vals)
140      nc_type type;
141      int len;
142      void *vals;
143 {
144     int iel;
145     union {
146 	char *cp;
147 	short *sp;
148 	nclong *lp;
149 	float *fp;
150 	double *dp;
151     } gp;
152     char *sp;
153     unsigned char uc;
154     char gps[30];		/* for ascii of a float or double precision */
155     char *f_fmt = "%#.8g";
156     char *d_fmt = "%#.16g";
157 
158     switch (type) {
159       case NC_BYTE:
160 	gp.cp = (char *) vals;
161 	for (iel = 0; iel < len; iel++)
162 	  if (isprint(uc = *gp.cp++ & 0377))
163 	    Printf ("'%c'%s", uc, iel<len-1 ? ", " : "");
164 	  else
165 	    Printf ("'\\%o'%s", uc, iel<len-1 ? ", " : "");
166 	break;
167       case NC_CHAR:
168 	gp.cp = (char *) vals;
169 	Printf ("\"");
170 	/* adjust len so trailing nulls don't get printed */
171 	sp = gp.cp + len - 1;
172 	while (*sp-- == '\0' && len > 0)
173 	    len--;
174 	for (iel = 0; iel < len; iel++)
175 	  switch (uc = *gp.cp++ & 0377) {
176 	    case '\b':
177 	      Printf ("\\b");
178 	      break;
179 	    case '\f':
180 	      Printf ("\\f");
181 	      break;
182 	    case '\n':		/* generate linebreaks after new-lines */
183 	      Printf ("\\n\",\n    \"");
184 	      break;
185 	    case '\r':
186 	      Printf ("\\r");
187 	      break;
188 	    case '\t':
189 	      Printf ("\\t");
190 	      break;
191 	    case '\v':
192 	      Printf ("\\v");
193 	      break;
194 	    case '\\':
195 	      Printf ("\\\\");
196 	      break;
197 	    case '\'':
198 	      Printf ("\\'");
199 	      break;
200 	    case '\"':
201 	      Printf ("\\\"");
202 	      break;
203 	    default:
204 	      Printf ("%c",uc);
205 	      break;
206 	  }
207 	Printf ("\"");
208 	break;
209       case NC_SHORT:
210 	gp.sp = (short *) vals;
211 	for (iel = 0; iel < len; iel++)
212 	  Printf ("%ds%s",*gp.sp++,iel<len-1 ? ", " : "");
213 	break;
214       case NC_LONG:
215 	gp.lp = (nclong *) vals;
216 	for (iel = 0; iel < len; iel++)
217 	  Printf ("%d%s",(int)*gp.lp++,iel<len-1 ? ", " : "");
218 	break;
219       case NC_FLOAT:
220 	gp.fp = (float *) vals;
221 	for (iel = 0; iel < len; iel++) {
222 	    int ll;
223 	    (void) sprintf(gps, f_fmt, * gp.fp++);
224 	    /* append a trailing "f" for floating-point attributes */
225 	    ll = strlen(gps);
226 	    gps[ll + 1] = '\0';
227 	    gps[ll] = 'f';
228             tztrim(gps);	/* trim trailing 0's after '.' */
229 	    Printf ("%s%s", gps, iel<len-1 ? ", " : "");
230 	}
231 	break;
232       case NC_DOUBLE:
233 	gp.dp = (double *) vals;
234 	for (iel = 0; iel < len; iel++) {
235 	    (void) sprintf(gps, d_fmt, *gp.dp++);
236 	    tztrim(gps);	/* trim trailing 0's after '.' */
237 	    Printf ("%s%s", gps, iel<len-1 ? ", " : "");
238 	}
239 	break;
240       default:
241 	error("pr_att_vals: bad type");
242     }
243 }
244 
245 /*
246  * fixstr
247  *
248  * 	If the string contains characters other than alpha-numerics,
249  * 	an underscore, or a hyphen, convert it to an underscore.
250  *
251  * Modification:
252  *	- Added "fix_str" to determine whether the conversion should be
253  *	  carried out, based on user's request. - bug #934, BMR 7/3/2005
254  */
fixstr(char * str,bool fix_str)255 char *fixstr(char *str, bool fix_str)
256 {
257 #ifndef __GNUC__
258     char *strdup(const char *);
259 #endif  /* linux */
260 	char *new_str, *ptr;
261 
262 	if (!str)
263 		return NULL;
264 
265 	ptr = new_str = strdup(str);
266 
267 	if (!ptr) {
268 		error("Out of memory!");
269 		return NULL;
270 	}
271 
272 	if (fix_str)
273 	{
274 	    for (; *ptr; ptr++)
275 		if (!isalnum(*ptr) && *ptr != '_' && *ptr != '-')
276 			*ptr = '_';
277 	}
278 
279 	return new_str;
280 }
281 
282 static void
do_ncdump(char * path,struct fspec * specp)283 do_ncdump(char *path, struct fspec* specp)
284 /*     char *path;
285      struct fspec* specp;
286 */
287 {
288 	int ndims;			/* number of dimensions */
289 	int nvars;			/* number of variables */
290 	int ngatts;			/* number of global attributes */
291 	int xdimid;			/* id of unlimited dimension */
292 	int dimid;			/* dimension id */
293 	int varid;			/* variable id */
294 	struct ncvar var;		/* variable */
295 	struct ncatt att;		/* attribute */
296 	int id;				/* dimension number per variable */
297 	int ia;				/* attribute number */
298 	int iv;				/* variable number */
299 	int is_coord;			/* true if variable is a coordinate variable */
300 	int isempty = 0;		/* true if an old hdf dim has no scale values */
301 
302 	int ncid = ncopen(path, NC_NOWRITE); /* netCDF id */
303 	vnode* vlist = newvlist();	/* list for vars specified with -v option */
304 
305 	/* don't crash on error */
306 	ncopts = 0;
307 
308 	if (ncid == -1) {
309 		error("ncopen failed on %s", path);
310 		return;
311 	}
312 
313 	/*
314 	 * If any vars were specified with -v option, get list of associated
315 	 * variable ids
316 	 */
317 	for (iv = 0; iv < specp->nlvars; iv++) {
318 		varid = ncvarid(ncid, specp->lvars[iv]);
319 		varadd(vlist, varid);
320 	}
321 
322 	/* if name not specified, derive it from path */
323 	if (specp->name == NULL)
324 		specp->name = name_path (path);
325 
326 	Printf ("netcdf %s {\n", specp->name);
327 
328 	/*
329 	 * get number of dimensions, number of variables, number of global
330 	 * atts, and dimension id of unlimited dimension, if any
331 	 */
332 	(void)ncinquire(ncid, &ndims, &nvars, &ngatts, &xdimid);
333 
334 	/* get dimension info */
335 	if (ndims > 0) {
336 		Printf ("dimensions:\n");
337 
338 		for (dimid = 0; dimid < ndims; dimid++) {
339 			char *fixed_str;
340 
341 			(void)ncdiminq(ncid, dimid, dims[dimid].name,
342 				       &dims[dimid].size);
343 			fixed_str = fixstr(dims[dimid].name, specp->fix_str);
344 
345 			if (!fixed_str && dims[dimid].name) {
346 				/* strdup(3) failed */
347 				(void) ncclose(ncid);
348 				return;
349 			}
350 
351 			if (dimid == xdimid)
352 				Printf ("\t%s = %s ; // (%d currently)\n",
353 					fixed_str, "UNLIMITED",
354 					(int)dims[dimid].size);
355 			else
356 				Printf ("\t%s = %ld ;\n",
357 					fixed_str, dims[dimid].size);
358 
359 			free(fixed_str);
360 		}
361 	}
362 
363 	Printf ("\nvariables:\n");
364 
365 	/* get variable info, with variable attributes */
366 	for (varid = 0; varid < nvars; varid++) {
367 		char *fixed_var;
368 
369 		(void) ncvarinq(ncid, varid, var.name, &var.type, &var.ndims,
370 				var.dims, &var.natts);
371 		fixed_var = fixstr(var.name, specp->fix_str);
372 
373 		if (!fixed_var && var.name) {
374 			/* strdup(3) failed */
375 			(void) ncclose(ncid);
376 			return;
377 		}
378 
379 		Printf ("\t%s %s", type_name(var.type), fixed_var);
380 
381 		if (var.ndims > 0)
382 			Printf ("(");
383 
384 		for (id = 0; id < var.ndims; id++) {
385 			char *fixed_dim = fixstr(dims[var.dims[id]].name,
386 						 specp->fix_str);
387 
388 			if (!fixed_dim && dims[var.dims[id]].name) {
389 				/* strdup(3) failed */
390 			 	(void) ncclose(ncid);
391 				free(fixed_var);
392 				return;
393 			}
394 
395 			Printf ("%s%s", fixed_dim,
396 				id < var.ndims - 1 ? ", " : ")");
397 			free(fixed_dim);
398 		}
399 
400 		Printf (" ;\n");
401 
402 		/* get variable attributes */
403 		for (ia = 0; ia < var.natts; ia++) {
404 			char *fixed_att;
405 
406 			(void) ncattname(ncid, varid, ia, att.name);
407 			fixed_att = fixstr(att.name, specp->fix_str);
408 
409 			if (!fixed_att) {
410 				(void) ncclose(ncid);
411 				free(fixed_var);
412 				return;
413 			}
414 
415 			Printf ("\t\t%s:%s = ", fixed_var, fixed_att);
416 			(void) ncattinq(ncid, varid, att.name,
417 					&att.type, &att.len);
418 			att.val = (void *) malloc((unsigned)att.len * nctypelen(att.type));
419 
420 			if (!att.val) {
421 				error("Out of memory!");
422 				(void) ncclose(ncid);
423 				free(fixed_att);
424 				free(fixed_var);
425 				return;
426 			}
427 
428 			(void) ncattget(ncid, varid, att.name, att.val);
429 			pr_att_vals(att.type, att.len, att.val);
430 			Printf (" ;\n");
431 			free(att.val);
432 			free(fixed_att);
433 		}
434 
435 		free(fixed_var);
436 	}
437 
438 	/* get global attributes */
439 	if (ngatts > 0)
440 		Printf ("\n// global attributes:\n");
441 
442 	for (ia = 0; ia < ngatts; ia++) {
443 		char *fixed_att;
444 
445 		(void) ncattname(ncid, NC_GLOBAL, ia, att.name);
446 		fixed_att = fixstr(att.name, specp->fix_str);
447 
448 		if (!fixed_att) {
449 			(void) ncclose(ncid);
450 			return;
451 		}
452 
453 		Printf ("\t\t:%s = ", fixed_att);
454 
455 		(void) ncattinq(ncid, NC_GLOBAL, att.name,
456 				&att.type, &att.len);
457 		att.val = malloc((unsigned)(att.len * nctypelen(att.type)));
458 
459 		if (!att.val) {
460 			error("Out of memory!");
461 			(void) ncclose(ncid);
462 			free(fixed_att);
463 			return;
464 		}
465 
466 		(void) ncattget(ncid, NC_GLOBAL, att.name, att.val);
467 		pr_att_vals(att.type, att.len, att.val);
468 		Printf (" ;\n");
469 		free(att.val);
470 		free(fixed_att);
471 	}
472 
473 	if (! specp->header_only) {
474 		if (nvars > 0)
475 			Printf ("\ndata:\n");
476 
477 		/* output variable data */
478 		for (varid = 0; varid < nvars; varid++) {
479 			/* if var list specified, test for membership */
480 			if (specp->nlvars > 0 && ! varmember(vlist, varid))
481 				continue;
482 
483 			(void) ncvarinq(ncid, varid, var.name, &var.type,
484 					&var.ndims, var.dims, &var.natts);
485 
486 			if (specp->coord_vals) {
487 				/* Find out if this is a coordinate variable */
488 				is_coord = 0;
489 
490 				for (dimid = 0; dimid < ndims; dimid++) {
491 					if (strcmp(dims[dimid].name, var.name) == 0 &&
492 						var.ndims == 1) {
493 						is_coord = 1;
494 						break;
495 					}
496 				}
497 
498 				if (! is_coord)
499 					/* don't get data for non-coordinate vars */
500 					continue;
501 			}
502 
503 			/*
504 			 * Only get data for variable if it is not a record variable,
505 			 * or if it is a record variable and at least one record has
506 			 * been written.
507 			 */
508 #ifdef HDF
509 			/* skip the dimension vars which have dim strings only.  */
510 			{
511 				NC *handle ;
512 				NC_var *vp;
513 #ifdef OLD_WAY
514 				NC_var *NC_hlookupvar() ;
515 #endif /* OLD_WAY */
516 
517 				isempty = 0;
518 				handle = NC_check_id(ncid);
519 
520 				if (handle->file_type == HDF_FILE)  {
521 					vp = NC_hlookupvar(handle, varid) ;
522 					/* This is set up to take care of
523 					 * cases where an array has been
524 					 * defined but no data */
525 					/* has yet been added. */
526 					if ((vp->data_tag == DFTAG_SDS ||
527 						vp->data_tag == DFTAG_SD) &&
528 						(vp->data_ref == 0))
529 						isempty = 1;
530 				}
531 			}
532 
533 #endif /* HDF */
534 			if (isempty)
535 				continue;
536 
537 			if (var.ndims == 0 || var.dims[0] != xdimid || dims[xdimid].size != 0) {
538 				int ret = 0;
539 
540 				/* Collect variable's dim sizes */
541 				for (id = 0; id < var.ndims; id++)
542 					vdims[id] = dims[var.dims[id]].size;
543 
544 				 /* if (vardata(&var, vdims, ncid, varid, specp) == -1)
545  */
546 				ret = vardata(&var, vdims, ncid, varid, specp);
547 				/* Keep the original failure detection until further improvement */
548 				if (ret == -1) {
549 					error("can't output data for variable %s", var.name);
550 					(void) ncclose(ncid);
551 					return;
552 				}
553 				/* This failure indicates that vardata failed
554 				   because ncvarget fails.  (HDFFR-1468)
555 				   -BMR, 2015/01/20) */
556 				if (ret == ERR_READFAIL) {
557 					error("Reading failed for variable %s, possibly the data is corrupted.", var.name);
558 					(void) ncclose(ncid);
559 					return;
560 				}
561 			}
562 		}
563 	}
564 
565 	Printf ("}\n");
566 	(void) ncclose(ncid);
567 }
568 
569 static void
make_lvars(optarg,fspecp)570 make_lvars(optarg, fspecp)
571      char *optarg;
572      struct fspec* fspecp;
573 {
574     char *cp = optarg;
575     int nvars = 1;
576     char ** cpp;
577 
578     /* compute number of variable names in comma-delimited list */
579     fspecp->nlvars = 1;
580     while (*cp++)
581       if (*cp == ',')
582  	nvars++;
583 
584     fspecp->lvars = (char **) malloc(nvars * sizeof(char*));
585     if (!fspecp->lvars) {
586 	error("out of memory");
587 	exit(EXIT_FAILURE);
588     }
589 
590     cpp = fspecp->lvars;
591     /* copy variable names into list */
592     for (cp = strtok(optarg, ",");
593 	 cp != NULL;
594 	 cp = strtok((char *) NULL, ",")) {
595 
596 	*cpp = (char *) malloc(strlen(cp) + 1);
597 	if (!*cpp) {
598 	    error("out of memory");
599 	    exit(EXIT_FAILURE);
600 	}
601 	strcpy(*cpp, cp);
602 	cpp++;
603     }
604     fspecp->nlvars = nvars;
605 }
606 
607 
608 /*
609  * Extract the significant-digits specifiers from the -d argument on the
610  * command-line and update the default data formats appropriately.
611  */
612 static void
set_sigdigs(optarg)613 set_sigdigs(optarg)
614      char *optarg;
615 {
616     char *ptr = optarg;
617     char *ptr2 = 0;
618     long flt_digits = 7;	/* default floating-point digits */
619     long dbl_digits = 15;	/* default double-precision digits */
620     char flt_fmt[6];
621     char dbl_fmt[6];
622 
623     if (optarg != 0 && strlen(optarg) > 0 && optarg[0] != ',')
624         flt_digits=strtol(optarg, &ptr, 10);
625 
626     if (flt_digits < 1 || flt_digits > 10) {
627 	error("unreasonable value for float significant digits: %d",
628 	      flt_digits);
629 	exit(EXIT_FAILURE);
630     }
631     if (*ptr == ',')
632       dbl_digits = strtol(ptr+1, &ptr2, 10);
633     if (ptr2 == ptr+1 || dbl_digits < 1 || dbl_digits > 20) {
634 	error("unreasonable value for double significant digits: %d",
635 	      dbl_digits);
636 	exit(EXIT_FAILURE);
637     }
638     (void) sprintf(flt_fmt, "%%.%dg", (int)flt_digits);
639     (void) sprintf(dbl_fmt, "%%.%dg", (int)dbl_digits);
640     set_formats(flt_fmt, dbl_fmt);
641 }
642 
643 
644 int
main(argc,argv)645 main(argc, argv)
646 int argc;
647 char *argv[];
648 {
649     extern int optind;
650     extern int opterr;
651     extern char *optarg;
652     static struct fspec fspec =	/* defaults, overridden on command line */
653       {
654 	  0,			/* construct netcdf name from file name */
655 	  false,		/* print header info only, no data? */
656 	  false,		/* just print coord vars? */
657 	  false,		/* brief  comments in data section? */
658 	  false,		/* full annotations in data section?  */
659 	  false,		/* replace nonalpha-numeric with underscore?  */
660 	  LANG_NONE,		/* language conventions for indices */
661 	  0,			/* if -v specified, number of variables */
662 	  0			/* if -v specified, list of variable names */
663 	  };
664     int c;
665     int i;
666     int max_len = 80;		/* default maximum line length */
667 
668     opterr = 1;
669     progname = argv[0];
670 
671     if (1 == argc)             /* if no arguments given, print help and exit */
672       usage();
673 
674     while ((c = getopt(argc, argv, "b:cf:hul:n:v:d:V")) != EOF)
675       switch(c) {
676 	case 'V':		/* display version of the library */
677 	  printf("%s, %s\n\n", argv[0], LIBVER_STRING );
678 	  exit(EXIT_SUCCESS);
679 	case 'h':		/* dump header only, no data */
680 	  fspec.header_only = true;
681 	  break;
682 	case 'c':		/* header, data only for coordinate dims */
683 	  fspec.coord_vals = true;
684 	  break;
685 	case 'n':		/*
686 				 * provide different name than derived from
687 				 * file name
688 				 */
689 	  fspec.name = optarg;
690 	  break;
691 	case 'u':		/* replace nonalpha-numerics with underscores */
692 	  fspec.fix_str = true;
693 	  break;
694 	case 'b':		/* brief comments in data section */
695 	  fspec.brief_data_cmnts = true;
696 	  switch (tolower(optarg[0])) {
697 	    case 'c':
698 	      fspec.data_lang = LANG_C;
699 	      break;
700 	    case 'f':
701 	      fspec.data_lang = LANG_F;
702 	      break;
703 	    default:
704 	      error("invalid value for -b option: %s", optarg);
705 	      exit(EXIT_FAILURE);
706 	  }
707 	  break;
708 	case 'f':		/* full comments in data section */
709 	  fspec.full_data_cmnts = true;
710 	  switch (tolower(optarg[0])) {
711 	    case 'c':
712 	      fspec.data_lang = LANG_C;
713 	      break;
714 	    case 'f':
715 	      fspec.data_lang = LANG_F;
716 	      break;
717 	    default:
718 	      error("invalid value for -b option: %s", optarg);
719 	      exit(EXIT_FAILURE);
720 	  }
721 	  break;
722 	case 'l':		/* maximum line length */
723 	  max_len = strtol(optarg, 0, 0);
724 	  if (max_len < 10) {
725 	      error("unreasonably small line length specified: %d", max_len);
726 	      exit(EXIT_FAILURE);
727 	  }
728 	  break;
729 	case 'v':		/* variable names */
730 	  /* make list of names of variables specified */
731 	  make_lvars (optarg, &fspec);
732 	  break;
733 	case 'd':		/* specify precision for floats */
734 #ifdef OLD_WAY
735 	  set_sigdigs(optarg, &fspec);
736 #else /* OLD_WAY */
737 	  set_sigdigs(optarg);
738 #endif /* OLD_WAY */
739 	  break;
740 	case '?':
741 	  usage();
742 	  break;
743       }
744 
745     set_max_len(max_len);
746 
747     argc -= optind;
748     argv += optind;
749 
750     i = 0;
751     do {
752 	if (argc > 0)
753 	  do_ncdump(argv[i], &fspec);
754     } while (++i < argc);
755     return EXIT_SUCCESS;
756 }
757