PageRenderTime 78ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/other/netcdf_write_matrix/src/libsrc/nc.c

http://github.com/jbeezley/wrf-fire
C | 1610 lines | 1146 code | 269 blank | 195 comment | 328 complexity | a8ee6de0d482c8a53ac4892848cc4bb9 MD5 | raw file
Possible License(s): AGPL-1.0
  1. /*
  2. * Copyright 1996, University Corporation for Atmospheric Research
  3. * See netcdf/COPYRIGHT file for copying and redistribution conditions.
  4. */
  5. /* $Id: nc.c,v 2.143 2006/01/28 20:01:19 ed Exp $ */
  6. #include "nc.h"
  7. #include "rnd.h"
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <assert.h>
  11. #include "ncx.h"
  12. #if defined(LOCKNUMREC) /* && _CRAYMPP */
  13. # include <mpp/shmem.h>
  14. # include <intrinsics.h>
  15. #endif
  16. /* list of open netcdf's */
  17. static NC *NClist = NULL;
  18. /* This is the default create format for nc_create and nc__create. */
  19. int default_create_format = NC_FORMAT_CLASSIC;
  20. /* These have to do with version numbers. */
  21. #define MAGIC_NUM_LEN 4
  22. #define VER_CLASSIC 1
  23. #define VER_64BIT_OFFSET 2
  24. #define VER_HDF5 3
  25. static void
  26. add_to_NCList(NC *ncp)
  27. {
  28. assert(ncp != NULL);
  29. ncp->prev = NULL;
  30. if(NClist != NULL)
  31. NClist->prev = ncp;
  32. ncp->next = NClist;
  33. NClist = ncp;
  34. }
  35. static void
  36. del_from_NCList(NC *ncp)
  37. {
  38. assert(ncp != NULL);
  39. if(NClist == ncp)
  40. {
  41. assert(ncp->prev == NULL);
  42. NClist = ncp->next;
  43. }
  44. else
  45. {
  46. assert(ncp->prev != NULL);
  47. ncp->prev->next = ncp->next;
  48. }
  49. if(ncp->next != NULL)
  50. ncp->next->prev = ncp->prev;
  51. ncp->next = NULL;
  52. ncp->prev = NULL;
  53. }
  54. int
  55. NC_check_id(int ncid, NC **ncpp)
  56. {
  57. NC *ncp;
  58. if(ncid >= 0)
  59. {
  60. for(ncp = NClist; ncp != NULL; ncp = ncp->next)
  61. {
  62. if(ncp->nciop->fd == ncid)
  63. {
  64. *ncpp = ncp;
  65. return NC_NOERR; /* normal return */
  66. }
  67. }
  68. }
  69. /* else, not found */
  70. return NC_EBADID;
  71. }
  72. static void
  73. free_NC(NC *ncp)
  74. {
  75. if(ncp == NULL)
  76. return;
  77. free_NC_dimarrayV(&ncp->dims);
  78. free_NC_attrarrayV(&ncp->attrs);
  79. free_NC_vararrayV(&ncp->vars);
  80. #if _CRAYMPP && defined(LOCKNUMREC)
  81. shfree(ncp);
  82. #else
  83. free(ncp);
  84. #endif /* _CRAYMPP && LOCKNUMREC */
  85. }
  86. static NC *
  87. new_NC(const size_t *chunkp)
  88. {
  89. NC *ncp;
  90. #if _CRAYMPP && defined(LOCKNUMREC)
  91. ncp = (NC *) shmalloc(sizeof(NC));
  92. #else
  93. ncp = (NC *) malloc(sizeof(NC));
  94. #endif /* _CRAYMPP && LOCKNUMREC */
  95. if(ncp == NULL)
  96. return NULL;
  97. (void) memset(ncp, 0, sizeof(NC));
  98. ncp->xsz = MIN_NC_XSZ;
  99. assert(ncp->xsz == ncx_len_NC(ncp,0));
  100. ncp->chunk = chunkp != NULL ? *chunkp : NC_SIZEHINT_DEFAULT;
  101. return ncp;
  102. }
  103. static NC *
  104. dup_NC(const NC *ref)
  105. {
  106. NC *ncp;
  107. #if _CRAYMPP && defined(LOCKNUMREC)
  108. ncp = (NC *) shmalloc(sizeof(NC));
  109. #else
  110. ncp = (NC *) malloc(sizeof(NC));
  111. #endif /* _CRAYMPP && LOCKNUMREC */
  112. if(ncp == NULL)
  113. return NULL;
  114. (void) memset(ncp, 0, sizeof(NC));
  115. if(dup_NC_dimarrayV(&ncp->dims, &ref->dims) != NC_NOERR)
  116. goto err;
  117. if(dup_NC_attrarrayV(&ncp->attrs, &ref->attrs) != NC_NOERR)
  118. goto err;
  119. if(dup_NC_vararrayV(&ncp->vars, &ref->vars) != NC_NOERR)
  120. goto err;
  121. ncp->xsz = ref->xsz;
  122. ncp->begin_var = ref->begin_var;
  123. ncp->begin_rec = ref->begin_rec;
  124. ncp->recsize = ref->recsize;
  125. NC_set_numrecs(ncp, NC_get_numrecs(ref));
  126. return ncp;
  127. err:
  128. free_NC(ncp);
  129. return NULL;
  130. }
  131. /*
  132. * Verify that this is a user nc_type
  133. * Formerly
  134. NCcktype()
  135. * Sense of the return is changed.
  136. */
  137. int
  138. nc_cktype(nc_type type)
  139. {
  140. switch((int)type){
  141. case NC_BYTE:
  142. case NC_CHAR:
  143. case NC_SHORT:
  144. case NC_INT:
  145. case NC_FLOAT:
  146. case NC_DOUBLE:
  147. return(NC_NOERR);
  148. }
  149. return(NC_EBADTYPE);
  150. }
  151. /*
  152. * How many objects of 'type'
  153. * will fit into xbufsize?
  154. */
  155. size_t
  156. ncx_howmany(nc_type type, size_t xbufsize)
  157. {
  158. switch(type){
  159. case NC_BYTE:
  160. case NC_CHAR:
  161. return xbufsize;
  162. case NC_SHORT:
  163. return xbufsize/X_SIZEOF_SHORT;
  164. case NC_INT:
  165. return xbufsize/X_SIZEOF_INT;
  166. case NC_FLOAT:
  167. return xbufsize/X_SIZEOF_FLOAT;
  168. case NC_DOUBLE:
  169. return xbufsize/X_SIZEOF_DOUBLE;
  170. }
  171. assert("ncx_howmany: Bad type" == 0);
  172. return(0);
  173. }
  174. #define D_RNDUP(x, align) _RNDUP(x, (off_t)(align))
  175. /*
  176. * Compute each variable's 'begin' offset,
  177. * update 'begin_rec' as well.
  178. */
  179. static int
  180. NC_begins(NC *ncp,
  181. size_t h_minfree, size_t v_align,
  182. size_t v_minfree, size_t r_align)
  183. {
  184. size_t ii;
  185. int sizeof_off_t;
  186. off_t index = 0;
  187. NC_var **vpp;
  188. NC_var *last = NULL;
  189. if(v_align == NC_ALIGN_CHUNK)
  190. v_align = ncp->chunk;
  191. if(r_align == NC_ALIGN_CHUNK)
  192. r_align = ncp->chunk;
  193. if (fIsSet(ncp->flags, NC_64BIT_OFFSET)) {
  194. sizeof_off_t = 8;
  195. } else {
  196. sizeof_off_t = 4;
  197. }
  198. ncp->xsz = ncx_len_NC(ncp,sizeof_off_t);
  199. if(ncp->vars.nelems == 0)
  200. return NC_NOERR;
  201. /* only (re)calculate begin_var if there is not sufficient space in header
  202. or start of non-record variables is not aligned as requested by valign */
  203. if (ncp->begin_var < ncp->xsz + h_minfree ||
  204. ncp->begin_var != D_RNDUP(ncp->begin_var, v_align) )
  205. {
  206. index = (off_t) ncp->xsz;
  207. ncp->begin_var = D_RNDUP(index, v_align);
  208. if(ncp->begin_var < index + h_minfree)
  209. {
  210. ncp->begin_var = D_RNDUP(index + (off_t)h_minfree, v_align);
  211. }
  212. }
  213. index = ncp->begin_var;
  214. /* loop thru vars, first pass is for the 'non-record' vars */
  215. vpp = ncp->vars.value;
  216. for(ii = 0; ii < ncp->vars.nelems ; ii++, vpp++)
  217. {
  218. if( IS_RECVAR(*vpp) )
  219. {
  220. /* skip record variables on this pass */
  221. continue;
  222. }
  223. #if 0
  224. fprintf(stderr, " VAR %d %s: %ld\n", ii, (*vpp)->name->cp, (long)index);
  225. #endif
  226. if( sizeof_off_t == 4 && (index > X_OFF_MAX || index < 0) )
  227. {
  228. return NC_EVARSIZE;
  229. }
  230. (*vpp)->begin = index;
  231. index += (*vpp)->len;
  232. }
  233. /* only (re)calculate begin_rec if there is not sufficient
  234. space at end of non-record variables or if start of record
  235. variables is not aligned as requested by r_align */
  236. if (ncp->begin_rec < index + v_minfree ||
  237. ncp->begin_rec != D_RNDUP(ncp->begin_rec, r_align) )
  238. {
  239. ncp->begin_rec = D_RNDUP(index, r_align);
  240. if(ncp->begin_rec < index + v_minfree)
  241. {
  242. ncp->begin_rec = D_RNDUP(index + (off_t)v_minfree, r_align);
  243. }
  244. }
  245. index = ncp->begin_rec;
  246. ncp->recsize = 0;
  247. /* loop thru vars, second pass is for the 'record' vars */
  248. vpp = (NC_var **)ncp->vars.value;
  249. for(ii = 0; ii < ncp->vars.nelems; ii++, vpp++)
  250. {
  251. if( !IS_RECVAR(*vpp) )
  252. {
  253. /* skip non-record variables on this pass */
  254. continue;
  255. }
  256. #if 0
  257. fprintf(stderr, " REC %d %s: %ld\n", ii, (*vpp)->name->cp, (long)index);
  258. #endif
  259. if( sizeof_off_t == 4 && (index > X_OFF_MAX || index < 0) )
  260. {
  261. return NC_EVARSIZE;
  262. }
  263. (*vpp)->begin = index;
  264. index += (*vpp)->len;
  265. /* check if record size must fit in 32-bits */
  266. #if SIZEOF_OFF_T == SIZEOF_SIZE_T && SIZEOF_SIZE_T == 4
  267. if( ncp->recsize > X_UINT_MAX - (*vpp)->len )
  268. {
  269. return NC_EVARSIZE;
  270. }
  271. #endif
  272. ncp->recsize += (*vpp)->len;
  273. last = (*vpp);
  274. }
  275. /*
  276. * for special case of exactly one record variable, pack value
  277. */
  278. if(last != NULL && ncp->recsize == last->len)
  279. ncp->recsize = *last->dsizes * last->xsz;
  280. if(NC_IsNew(ncp))
  281. NC_set_numrecs(ncp, 0);
  282. return NC_NOERR;
  283. }
  284. /*
  285. * Read just the numrecs member.
  286. * (A relatively expensive way to do things.)
  287. */
  288. int
  289. read_numrecs(NC *ncp)
  290. {
  291. int status = NC_NOERR;
  292. const void *xp = NULL;
  293. size_t nrecs = NC_get_numrecs(ncp);
  294. assert(!NC_indef(ncp));
  295. #define NC_NUMRECS_OFFSET 4
  296. #define NC_NUMRECS_EXTENT 4
  297. status = ncp->nciop->get(ncp->nciop,
  298. NC_NUMRECS_OFFSET, NC_NUMRECS_EXTENT, 0, (void **)&xp);
  299. /* cast away const */
  300. if(status != NC_NOERR)
  301. return status;
  302. status = ncx_get_size_t(&xp, &nrecs);
  303. (void) ncp->nciop->rel(ncp->nciop, NC_NUMRECS_OFFSET, 0);
  304. if(status == NC_NOERR)
  305. {
  306. NC_set_numrecs(ncp, nrecs);
  307. fClr(ncp->flags, NC_NDIRTY);
  308. }
  309. return status;
  310. }
  311. /*
  312. * Write out just the numrecs member.
  313. * (A relatively expensive way to do things.)
  314. */
  315. int
  316. write_numrecs(NC *ncp)
  317. {
  318. int status = NC_NOERR;
  319. void *xp = NULL;
  320. assert(!NC_readonly(ncp));
  321. assert(!NC_indef(ncp));
  322. status = ncp->nciop->get(ncp->nciop,
  323. NC_NUMRECS_OFFSET, NC_NUMRECS_EXTENT, RGN_WRITE, &xp);
  324. if(status != NC_NOERR)
  325. return status;
  326. {
  327. const size_t nrecs = NC_get_numrecs(ncp);
  328. status = ncx_put_size_t(&xp, &nrecs);
  329. }
  330. (void) ncp->nciop->rel(ncp->nciop, NC_NUMRECS_OFFSET, RGN_MODIFIED);
  331. if(status == NC_NOERR)
  332. fClr(ncp->flags, NC_NDIRTY);
  333. return status;
  334. }
  335. /*
  336. * Read in the header
  337. * It is expensive.
  338. */
  339. static int
  340. read_NC(NC *ncp)
  341. {
  342. int status = NC_NOERR;
  343. free_NC_dimarrayV(&ncp->dims);
  344. free_NC_attrarrayV(&ncp->attrs);
  345. free_NC_vararrayV(&ncp->vars);
  346. status = nc_get_NC(ncp);
  347. if(status == NC_NOERR)
  348. fClr(ncp->flags, NC_NDIRTY | NC_HDIRTY);
  349. return status;
  350. }
  351. /*
  352. * Write out the header
  353. */
  354. static int
  355. write_NC(NC *ncp)
  356. {
  357. int status = NC_NOERR;
  358. assert(!NC_readonly(ncp));
  359. status = ncx_put_NC(ncp, NULL, 0, 0);
  360. if(status == NC_NOERR)
  361. fClr(ncp->flags, NC_NDIRTY | NC_HDIRTY);
  362. return status;
  363. }
  364. /*
  365. * Write the header or the numrecs if necessary.
  366. */
  367. int
  368. NC_sync(NC *ncp)
  369. {
  370. assert(!NC_readonly(ncp));
  371. if(NC_hdirty(ncp))
  372. {
  373. return write_NC(ncp);
  374. }
  375. /* else */
  376. if(NC_ndirty(ncp))
  377. {
  378. return write_numrecs(ncp);
  379. }
  380. /* else */
  381. return NC_NOERR;
  382. }
  383. /*
  384. * Initialize the 'non-record' variables.
  385. */
  386. static int
  387. fillerup(NC *ncp)
  388. {
  389. int status = NC_NOERR;
  390. size_t ii;
  391. NC_var **varpp;
  392. assert(!NC_readonly(ncp));
  393. assert(NC_dofill(ncp));
  394. /* loop thru vars */
  395. varpp = ncp->vars.value;
  396. for(ii = 0; ii < ncp->vars.nelems; ii++, varpp++)
  397. {
  398. if(IS_RECVAR(*varpp))
  399. {
  400. /* skip record variables */
  401. continue;
  402. }
  403. status = fill_NC_var(ncp, *varpp, 0);
  404. if(status != NC_NOERR)
  405. break;
  406. }
  407. return status;
  408. }
  409. /* Begin endef */
  410. /*
  411. */
  412. static int
  413. fill_added_recs(NC *gnu, NC *old)
  414. {
  415. NC_var ** const gnu_varpp = (NC_var **)gnu->vars.value;
  416. const int old_nrecs = (int) NC_get_numrecs(old);
  417. int recno = 0;
  418. for(; recno < old_nrecs; recno++)
  419. {
  420. int varid = (int)old->vars.nelems;
  421. for(; varid < (int)gnu->vars.nelems; varid++)
  422. {
  423. const NC_var *const gnu_varp = *(gnu_varpp + varid);
  424. if(!IS_RECVAR(gnu_varp))
  425. {
  426. /* skip non-record variables */
  427. continue;
  428. }
  429. /* else */
  430. {
  431. const int status = fill_NC_var(gnu, gnu_varp, recno);
  432. if(status != NC_NOERR)
  433. return status;
  434. }
  435. }
  436. }
  437. return NC_NOERR;
  438. }
  439. /*
  440. */
  441. static int
  442. fill_added(NC *gnu, NC *old)
  443. {
  444. NC_var ** const gnu_varpp = (NC_var **)gnu->vars.value;
  445. int varid = (int)old->vars.nelems;
  446. for(; varid < (int)gnu->vars.nelems; varid++)
  447. {
  448. const NC_var *const gnu_varp = *(gnu_varpp + varid);
  449. if(IS_RECVAR(gnu_varp))
  450. {
  451. /* skip record variables */
  452. continue;
  453. }
  454. /* else */
  455. {
  456. const int status = fill_NC_var(gnu, gnu_varp, 0);
  457. if(status != NC_NOERR)
  458. return status;
  459. }
  460. }
  461. return NC_NOERR;
  462. }
  463. /*
  464. * Move the records "out".
  465. * Fill as needed.
  466. */
  467. static int
  468. move_recs_r(NC *gnu, NC *old)
  469. {
  470. int status;
  471. int recno;
  472. int varid;
  473. NC_var **gnu_varpp = (NC_var **)gnu->vars.value;
  474. NC_var **old_varpp = (NC_var **)old->vars.value;
  475. NC_var *gnu_varp;
  476. NC_var *old_varp;
  477. off_t gnu_off;
  478. off_t old_off;
  479. const size_t old_nrecs = NC_get_numrecs(old);
  480. /* Don't parallelize this loop */
  481. for(recno = (int)old_nrecs -1; recno >= 0; recno--)
  482. {
  483. /* Don't parallelize this loop */
  484. for(varid = (int)old->vars.nelems -1; varid >= 0; varid--)
  485. {
  486. gnu_varp = *(gnu_varpp + varid);
  487. if(!IS_RECVAR(gnu_varp))
  488. {
  489. /* skip non-record variables on this pass */
  490. continue;
  491. }
  492. /* else */
  493. /* else, a pre-existing variable */
  494. old_varp = *(old_varpp + varid);
  495. gnu_off = gnu_varp->begin + (off_t)(gnu->recsize * recno);
  496. old_off = old_varp->begin + (off_t)(old->recsize * recno);
  497. if(gnu_off == old_off)
  498. continue; /* nothing to do */
  499. assert(gnu_off > old_off);
  500. status = gnu->nciop->move(gnu->nciop, gnu_off, old_off,
  501. old_varp->len, 0);
  502. if(status != NC_NOERR)
  503. return status;
  504. }
  505. }
  506. NC_set_numrecs(gnu, old_nrecs);
  507. return NC_NOERR;
  508. }
  509. /*
  510. * Move the "non record" variables "out".
  511. * Fill as needed.
  512. */
  513. static int
  514. move_vars_r(NC *gnu, NC *old)
  515. {
  516. int status;
  517. int varid;
  518. NC_var **gnu_varpp = (NC_var **)gnu->vars.value;
  519. NC_var **old_varpp = (NC_var **)old->vars.value;
  520. NC_var *gnu_varp;
  521. NC_var *old_varp;
  522. off_t gnu_off;
  523. off_t old_off;
  524. /* Don't parallelize this loop */
  525. for(varid = (int)old->vars.nelems -1;
  526. varid >= 0; varid--)
  527. {
  528. gnu_varp = *(gnu_varpp + varid);
  529. if(IS_RECVAR(gnu_varp))
  530. {
  531. /* skip record variables on this pass */
  532. continue;
  533. }
  534. /* else */
  535. old_varp = *(old_varpp + varid);
  536. gnu_off = gnu_varp->begin;
  537. old_off = old_varp->begin;
  538. if(gnu_off == old_off)
  539. continue; /* nothing to do */
  540. assert(gnu_off > old_off);
  541. status = gnu->nciop->move(gnu->nciop, gnu_off, old_off,
  542. old_varp->len, 0);
  543. if(status != NC_NOERR)
  544. return status;
  545. }
  546. return NC_NOERR;
  547. }
  548. /*
  549. * Given a valid ncp, return NC_EVARSIZE if any variable has a bad len
  550. * (product of non-rec dim sizes too large), else return NC_NOERR.
  551. */
  552. static int
  553. NC_check_vlens(NC *ncp)
  554. {
  555. NC_var **vpp;
  556. /* maximum permitted variable size (or size of one record's worth
  557. of a record variable) in bytes. This is different for format 1
  558. and format 2. */
  559. size_t vlen_max;
  560. size_t ii;
  561. size_t large_vars_count;
  562. size_t rec_vars_count;
  563. int last;
  564. if(ncp->vars.nelems == 0)
  565. return NC_NOERR;
  566. if ((ncp->flags & NC_64BIT_OFFSET) && sizeof(off_t) > 4) {
  567. /* CDF2 format and LFS */
  568. vlen_max = X_UINT_MAX - 3; /* "- 3" handles rounded-up size */
  569. } else {
  570. /* CDF1 format */
  571. vlen_max = X_INT_MAX - 3;
  572. }
  573. /* Loop through vars, first pass is for non-record variables. */
  574. large_vars_count = 0;
  575. rec_vars_count = 0;
  576. vpp = ncp->vars.value;
  577. for (ii = 0; ii < ncp->vars.nelems; ii++, vpp++) {
  578. if( !IS_RECVAR(*vpp) ) {
  579. last = 0;
  580. if( NC_check_vlen(*vpp, vlen_max) == 0 ) {
  581. large_vars_count++;
  582. last = 1;
  583. }
  584. } else {
  585. rec_vars_count++;
  586. }
  587. }
  588. /* OK if last non-record variable size too large, since not used to
  589. compute an offset */
  590. if( large_vars_count > 1) { /* only one "too-large" variable allowed */
  591. return NC_EVARSIZE;
  592. }
  593. /* and it has to be the last one */
  594. if( large_vars_count == 1 && last == 0) {
  595. return NC_EVARSIZE;
  596. }
  597. if( rec_vars_count > 0 ) {
  598. /* and if it's the last one, there can't be any record variables */
  599. if( large_vars_count == 1 && last == 1) {
  600. return NC_EVARSIZE;
  601. }
  602. /* Loop through vars, second pass is for record variables. */
  603. large_vars_count = 0;
  604. vpp = ncp->vars.value;
  605. for (ii = 0; ii < ncp->vars.nelems; ii++, vpp++) {
  606. if( IS_RECVAR(*vpp) ) {
  607. last = 0;
  608. if( NC_check_vlen(*vpp, vlen_max) == 0 ) {
  609. large_vars_count++;
  610. last = 1;
  611. }
  612. }
  613. }
  614. /* OK if last record variable size too large, since not used to
  615. compute an offset */
  616. if( large_vars_count > 1) { /* only one "too-large" variable allowed */
  617. return NC_EVARSIZE;
  618. }
  619. /* and it has to be the last one */
  620. if( large_vars_count == 1 && last == 0) {
  621. return NC_EVARSIZE;
  622. }
  623. }
  624. return NC_NOERR;
  625. }
  626. /*
  627. * End define mode.
  628. * Common code for ncendef, ncclose(endef)
  629. * Flushes I/O buffers.
  630. */
  631. static int
  632. NC_endef(NC *ncp,
  633. size_t h_minfree, size_t v_align,
  634. size_t v_minfree, size_t r_align)
  635. {
  636. int status = NC_NOERR;
  637. assert(!NC_readonly(ncp));
  638. assert(NC_indef(ncp));
  639. status = NC_check_vlens(ncp);
  640. if(status != NC_NOERR)
  641. return status;
  642. status = NC_begins(ncp, h_minfree, v_align, v_minfree, r_align);
  643. if(status != NC_NOERR)
  644. return status;
  645. if(ncp->old != NULL)
  646. {
  647. /* a plain redef, not a create */
  648. assert(!NC_IsNew(ncp));
  649. assert(fIsSet(ncp->flags, NC_INDEF));
  650. assert(ncp->begin_rec >= ncp->old->begin_rec);
  651. assert(ncp->begin_var >= ncp->old->begin_var);
  652. if(ncp->vars.nelems != 0)
  653. {
  654. if(ncp->begin_rec > ncp->old->begin_rec)
  655. {
  656. status = move_recs_r(ncp, ncp->old);
  657. if(status != NC_NOERR)
  658. return status;
  659. if(ncp->begin_var > ncp->old->begin_var)
  660. {
  661. status = move_vars_r(ncp, ncp->old);
  662. if(status != NC_NOERR)
  663. return status;
  664. }
  665. /* else if (ncp->begin_var == ncp->old->begin_var) { NOOP } */
  666. }
  667. else
  668. { /* Even if (ncp->begin_rec == ncp->old->begin_rec)
  669. and (ncp->begin_var == ncp->old->begin_var)
  670. might still have added a new record variable */
  671. if(ncp->recsize > ncp->old->recsize)
  672. {
  673. status = move_recs_r(ncp, ncp->old);
  674. if(status != NC_NOERR)
  675. return status;
  676. }
  677. }
  678. }
  679. }
  680. status = write_NC(ncp);
  681. if(status != NC_NOERR)
  682. return status;
  683. if(NC_dofill(ncp))
  684. {
  685. if(NC_IsNew(ncp))
  686. {
  687. status = fillerup(ncp);
  688. if(status != NC_NOERR)
  689. return status;
  690. }
  691. else if(ncp->vars.nelems > ncp->old->vars.nelems)
  692. {
  693. status = fill_added(ncp, ncp->old);
  694. if(status != NC_NOERR)
  695. return status;
  696. status = fill_added_recs(ncp, ncp->old);
  697. if(status != NC_NOERR)
  698. return status;
  699. }
  700. }
  701. if(ncp->old != NULL)
  702. {
  703. free_NC(ncp->old);
  704. ncp->old = NULL;
  705. }
  706. fClr(ncp->flags, NC_CREAT | NC_INDEF);
  707. return ncp->nciop->sync(ncp->nciop);
  708. }
  709. #ifdef LOCKNUMREC
  710. static int
  711. NC_init_pe(NC *ncp, int basepe) {
  712. if (basepe < 0 || basepe >= _num_pes()) {
  713. return NC_EINVAL; /* invalid base pe */
  714. }
  715. /* initialize common values */
  716. ncp->lock[LOCKNUMREC_VALUE] = 0;
  717. ncp->lock[LOCKNUMREC_LOCK] = 0;
  718. ncp->lock[LOCKNUMREC_SERVING] = 0;
  719. ncp->lock[LOCKNUMREC_BASEPE] = basepe;
  720. return NC_NOERR;
  721. }
  722. #endif
  723. /*
  724. * Compute the expected size of the file.
  725. */
  726. int
  727. NC_calcsize(NC *ncp, off_t *calcsizep)
  728. {
  729. NC_var **vpp = (NC_var **)ncp->vars.value;
  730. NC_var *const *const end = &vpp[ncp->vars.nelems];
  731. NC_var *last_fix = NULL; /* last "non-record" var */
  732. NC_var *last_rec = NULL; /* last "record" var */
  733. /*NC_var *last_var;*/
  734. int status;
  735. int numrecvars = 0; /* number of record variables */
  736. if(ncp->vars.nelems == 0) { /* no non-record variables and
  737. no record variables */
  738. *calcsizep = ncp->xsz; /* size of header */
  739. return NC_NOERR;
  740. }
  741. for( /*NADA*/; vpp < end; vpp++) {
  742. status = NC_var_shape(*vpp, &ncp->dims);
  743. if(status != NC_NOERR)
  744. return status;
  745. if(IS_RECVAR(*vpp)) {
  746. last_rec = *vpp;
  747. numrecvars++;
  748. } else {
  749. last_fix = *vpp;
  750. }
  751. }
  752. if(numrecvars == 0) {
  753. assert(last_fix != NULL);
  754. *calcsizep = last_fix->begin + last_fix->len;
  755. /*last_var = last_fix;*/
  756. } else { /* we have at least one record variable */
  757. *calcsizep = ncp->begin_rec + ncp->numrecs * ncp->recsize;
  758. /*last_var = last_rec;*/
  759. }
  760. return NC_NOERR;
  761. }
  762. /* Public */
  763. int
  764. nc__create(const char * path, int ioflags, size_t initialsz,
  765. size_t *chunksizehintp, int *ncid_ptr)
  766. {
  767. return nc__create_mp(path, ioflags, initialsz, 0,
  768. chunksizehintp, ncid_ptr);
  769. }
  770. int
  771. nc__create_mp(const char * path, int ioflags, size_t initialsz, int basepe,
  772. size_t *chunksizehintp, int *ncid_ptr)
  773. {
  774. NC *ncp;
  775. int status;
  776. void *xp = NULL;
  777. int sizeof_off_t = 0;
  778. #if ALWAYS_NC_SHARE /* DEBUG */
  779. fSet(ioflags, NC_SHARE);
  780. #endif
  781. ncp = new_NC(chunksizehintp);
  782. if(ncp == NULL)
  783. return NC_ENOMEM;
  784. #if defined(LOCKNUMREC) /* && _CRAYMPP */
  785. if (status = NC_init_pe(ncp, basepe)) {
  786. return status;
  787. }
  788. #else
  789. /*
  790. * !_CRAYMPP, only pe 0 is valid
  791. */
  792. if(basepe != 0)
  793. return NC_EINVAL;
  794. #endif
  795. assert(ncp->flags == 0);
  796. /* Apply default create format. */
  797. if (default_create_format == NC_FORMAT_64BIT)
  798. ioflags |= NC_64BIT_OFFSET;
  799. if (fIsSet(ioflags, NC_64BIT_OFFSET)) {
  800. fSet(ncp->flags, NC_64BIT_OFFSET);
  801. sizeof_off_t = 8;
  802. } else {
  803. sizeof_off_t = 4;
  804. }
  805. assert(ncp->xsz == ncx_len_NC(ncp,sizeof_off_t));
  806. status = ncio_create(path, ioflags,
  807. initialsz,
  808. 0, ncp->xsz, &ncp->chunk,
  809. &ncp->nciop, &xp);
  810. if(status != NC_NOERR)
  811. {
  812. /* translate error status */
  813. if(status == EEXIST)
  814. status = NC_EEXIST;
  815. goto unwind_alloc;
  816. }
  817. fSet(ncp->flags, NC_CREAT);
  818. if(fIsSet(ncp->nciop->ioflags, NC_SHARE))
  819. {
  820. /*
  821. * NC_SHARE implies sync up the number of records as well.
  822. * (File format version one.)
  823. * Note that other header changes are not shared
  824. * automatically. Some sort of IPC (external to this package)
  825. * would be used to trigger a call to nc_sync().
  826. */
  827. fSet(ncp->flags, NC_NSYNC);
  828. }
  829. status = ncx_put_NC(ncp, &xp, sizeof_off_t, ncp->xsz);
  830. if(status != NC_NOERR)
  831. goto unwind_ioc;
  832. add_to_NCList(ncp);
  833. if(chunksizehintp != NULL)
  834. *chunksizehintp = ncp->chunk;
  835. *ncid_ptr = ncp->nciop->fd;
  836. return NC_NOERR;
  837. unwind_ioc:
  838. (void) ncio_close(ncp->nciop, 1); /* N.B.: unlink */
  839. ncp->nciop = NULL;
  840. /*FALLTHRU*/
  841. unwind_alloc:
  842. free_NC(ncp);
  843. return status;
  844. }
  845. /* This function sets a default create flag that will be logically
  846. or'd to whatever flags are passed into nc_create for all future
  847. calls to nc_create.
  848. Valid default create flags are NC_64BIT_OFFSET, NC_CLOBBER,
  849. NC_LOCK, NC_SHARE. */
  850. int
  851. nc_set_default_format(int format, int *old_formatp)
  852. {
  853. /* Return existing format if desired. */
  854. if (old_formatp)
  855. *old_formatp = default_create_format;
  856. /* Make sure only valid format is set. */
  857. #ifdef USE_NETCDF4
  858. if (format != NC_FORMAT_CLASSIC && format != NC_FORMAT_64BIT &&
  859. format != NC_FORMAT_NETCDF4 && format != NC_FORMAT_NETCDF4_CLASSIC)
  860. return NC_EINVAL;
  861. #else
  862. if (format != NC_FORMAT_CLASSIC && format != NC_FORMAT_64BIT)
  863. return NC_EINVAL;
  864. #endif
  865. default_create_format = format;
  866. return NC_NOERR;
  867. }
  868. int
  869. nc_create(const char * path, int ioflags, int *ncid_ptr)
  870. {
  871. return nc__create(path, ioflags, 0, NULL, ncid_ptr);
  872. }
  873. int
  874. nc__open(const char * path, int ioflags,
  875. size_t *chunksizehintp, int *ncid_ptr)
  876. {
  877. return nc__open_mp(path, ioflags, 0,
  878. chunksizehintp, ncid_ptr);
  879. }
  880. int
  881. nc__open_mp(const char * path, int ioflags, int basepe,
  882. size_t *chunksizehintp, int *ncid_ptr)
  883. {
  884. NC *ncp;
  885. int status;
  886. #if ALWAYS_NC_SHARE /* DEBUG */
  887. fSet(ioflags, NC_SHARE);
  888. #endif
  889. ncp = new_NC(chunksizehintp);
  890. if(ncp == NULL)
  891. return NC_ENOMEM;
  892. #if defined(LOCKNUMREC) /* && _CRAYMPP */
  893. if (status = NC_init_pe(ncp, basepe)) {
  894. return status;
  895. }
  896. #else
  897. /*
  898. * !_CRAYMPP, only pe 0 is valid
  899. */
  900. if(basepe != 0)
  901. return NC_EINVAL;
  902. #endif
  903. status = ncio_open(path, ioflags,
  904. 0, 0, &ncp->chunk,
  905. &ncp->nciop, 0);
  906. if(status)
  907. goto unwind_alloc;
  908. assert(ncp->flags == 0);
  909. if(fIsSet(ncp->nciop->ioflags, NC_SHARE))
  910. {
  911. /*
  912. * NC_SHARE implies sync up the number of records as well.
  913. * (File format version one.)
  914. * Note that other header changes are not shared
  915. * automatically. Some sort of IPC (external to this package)
  916. * would be used to trigger a call to nc_sync().
  917. */
  918. fSet(ncp->flags, NC_NSYNC);
  919. }
  920. status = nc_get_NC(ncp);
  921. if(status != NC_NOERR)
  922. goto unwind_ioc;
  923. add_to_NCList(ncp);
  924. if(chunksizehintp != NULL)
  925. *chunksizehintp = ncp->chunk;
  926. *ncid_ptr = ncp->nciop->fd;
  927. return NC_NOERR;
  928. unwind_ioc:
  929. (void) ncio_close(ncp->nciop, 0);
  930. ncp->nciop = NULL;
  931. /*FALLTHRU*/
  932. unwind_alloc:
  933. free_NC(ncp);
  934. return status;
  935. }
  936. int
  937. nc_open(const char * path, int ioflags, int *ncid_ptr)
  938. {
  939. return nc__open(path, ioflags, NULL, ncid_ptr);
  940. }
  941. int
  942. nc__enddef(int ncid,
  943. size_t h_minfree, size_t v_align,
  944. size_t v_minfree, size_t r_align)
  945. {
  946. int status;
  947. NC *ncp;
  948. status = NC_check_id(ncid, &ncp);
  949. if(status != NC_NOERR)
  950. return status;
  951. if(!NC_indef(ncp))
  952. return(NC_ENOTINDEFINE);
  953. return (NC_endef(ncp, h_minfree, v_align, v_minfree, r_align));
  954. }
  955. int
  956. nc_enddef(int ncid)
  957. {
  958. int status;
  959. NC *ncp;
  960. status = NC_check_id(ncid, &ncp);
  961. if(status != NC_NOERR)
  962. return status;
  963. if(!NC_indef(ncp))
  964. return(NC_ENOTINDEFINE);
  965. /* return(NC_endef(ncp, 0, 4096, 0, 4096)); */
  966. return (NC_endef(ncp, 0, 1, 0, 1));
  967. }
  968. int
  969. nc_close(int ncid)
  970. {
  971. int status = NC_NOERR;
  972. NC *ncp;
  973. status = NC_check_id(ncid, &ncp);
  974. if(status != NC_NOERR)
  975. return status;
  976. if(NC_indef(ncp))
  977. {
  978. status = NC_endef(ncp, 0, 1, 0, 1); /* TODO: defaults */
  979. if(status != NC_NOERR )
  980. {
  981. (void) nc_abort(ncid);
  982. return status;
  983. }
  984. }
  985. else if(!NC_readonly(ncp))
  986. {
  987. status = NC_sync(ncp);
  988. }
  989. /*
  990. * If file opened for writing and file size is different from
  991. * what it should be (due to previous use of NOFILL mode),
  992. * change it to correct size, as reported by NC_calcsize().
  993. */
  994. {
  995. off_t filesize; /* current size of open file */
  996. off_t calcsize; /* calculated file size, from header */
  997. status = ncio_filesize(ncp->nciop, &filesize);
  998. if(status != ENOERR)
  999. return status;
  1000. status = NC_calcsize(ncp, &calcsize);
  1001. if(status != NC_NOERR)
  1002. return status;
  1003. if(filesize < calcsize && !NC_readonly(ncp)) {
  1004. status = ncio_pad_length(ncp->nciop, calcsize);
  1005. if(status != ENOERR)
  1006. return status;
  1007. }
  1008. }
  1009. (void) ncio_close(ncp->nciop, 0);
  1010. ncp->nciop = NULL;
  1011. del_from_NCList(ncp);
  1012. free_NC(ncp);
  1013. return status;
  1014. }
  1015. int
  1016. nc_delete(const char * path)
  1017. {
  1018. return nc_delete_mp(path, 0);
  1019. }
  1020. int
  1021. nc_delete_mp(const char * path, int basepe)
  1022. {
  1023. NC *ncp;
  1024. int status;
  1025. size_t chunk = 512;
  1026. ncp = new_NC(&chunk);
  1027. if(ncp == NULL)
  1028. return NC_ENOMEM;
  1029. #if defined(LOCKNUMREC) /* && _CRAYMPP */
  1030. if (status = NC_init_pe(ncp, basepe)) {
  1031. return status;
  1032. }
  1033. #else
  1034. /*
  1035. * !_CRAYMPP, only pe 0 is valid
  1036. */
  1037. if(basepe != 0)
  1038. return NC_EINVAL;
  1039. #endif
  1040. status = ncio_open(path, NC_NOWRITE,
  1041. 0, 0, &ncp->chunk,
  1042. &ncp->nciop, 0);
  1043. if(status)
  1044. goto unwind_alloc;
  1045. assert(ncp->flags == 0);
  1046. status = nc_get_NC(ncp);
  1047. if(status != NC_NOERR)
  1048. {
  1049. /* Not a netcdf file, don't delete */
  1050. /* ??? is this the right semantic? what if it was just too big? */
  1051. (void) ncio_close(ncp->nciop, 0);
  1052. }
  1053. else
  1054. {
  1055. /* ncio_close does the unlink */
  1056. status = ncio_close(ncp->nciop, 1); /* ncio_close does the unlink */
  1057. }
  1058. ncp->nciop = NULL;
  1059. unwind_alloc:
  1060. free_NC(ncp);
  1061. return status;
  1062. }
  1063. /*
  1064. * In data mode, same as ncclose.
  1065. * In define mode, restore previous definition.
  1066. * In create, remove the file.
  1067. */
  1068. int
  1069. nc_abort(int ncid)
  1070. {
  1071. int status;
  1072. NC *ncp;
  1073. int doUnlink = 0;
  1074. status = NC_check_id(ncid, &ncp);
  1075. if(status != NC_NOERR)
  1076. return status;
  1077. doUnlink = NC_IsNew(ncp);
  1078. if(ncp->old != NULL)
  1079. {
  1080. /* a plain redef, not a create */
  1081. assert(!NC_IsNew(ncp));
  1082. assert(fIsSet(ncp->flags, NC_INDEF));
  1083. free_NC(ncp->old);
  1084. ncp->old = NULL;
  1085. fClr(ncp->flags, NC_INDEF);
  1086. }
  1087. else if(!NC_readonly(ncp))
  1088. {
  1089. status = NC_sync(ncp);
  1090. if(status != NC_NOERR)
  1091. return status;
  1092. }
  1093. (void) ncio_close(ncp->nciop, doUnlink);
  1094. ncp->nciop = NULL;
  1095. del_from_NCList(ncp);
  1096. free_NC(ncp);
  1097. return NC_NOERR;
  1098. }
  1099. int
  1100. nc_redef(int ncid)
  1101. {
  1102. int status;
  1103. NC *ncp;
  1104. status = NC_check_id(ncid, &ncp);
  1105. if(status != NC_NOERR)
  1106. return status;
  1107. if(NC_readonly(ncp))
  1108. return NC_EPERM;
  1109. if(NC_indef(ncp))
  1110. return NC_EINDEFINE;
  1111. if(fIsSet(ncp->nciop->ioflags, NC_SHARE))
  1112. {
  1113. /* read in from disk */
  1114. status = read_NC(ncp);
  1115. if(status != NC_NOERR)
  1116. return status;
  1117. }
  1118. ncp->old = dup_NC(ncp);
  1119. if(ncp->old == NULL)
  1120. return NC_ENOMEM;
  1121. fSet(ncp->flags, NC_INDEF);
  1122. return NC_NOERR;
  1123. }
  1124. int
  1125. nc_inq(int ncid,
  1126. int *ndimsp,
  1127. int *nvarsp,
  1128. int *nattsp,
  1129. int *xtendimp)
  1130. {
  1131. int status;
  1132. NC *ncp;
  1133. status = NC_check_id(ncid, &ncp);
  1134. if(status != NC_NOERR)
  1135. return status;
  1136. if(ndimsp != NULL)
  1137. *ndimsp = (int) ncp->dims.nelems;
  1138. if(nvarsp != NULL)
  1139. *nvarsp = (int) ncp->vars.nelems;
  1140. if(nattsp != NULL)
  1141. *nattsp = (int) ncp->attrs.nelems;
  1142. if(xtendimp != NULL)
  1143. *xtendimp = find_NC_Udim(&ncp->dims, NULL);
  1144. return NC_NOERR;
  1145. }
  1146. int
  1147. nc_inq_ndims(int ncid, int *ndimsp)
  1148. {
  1149. int status;
  1150. NC *ncp;
  1151. status = NC_check_id(ncid, &ncp);
  1152. if(status != NC_NOERR)
  1153. return status;
  1154. if(ndimsp != NULL)
  1155. *ndimsp = (int) ncp->dims.nelems;
  1156. return NC_NOERR;
  1157. }
  1158. int
  1159. nc_inq_nvars(int ncid, int *nvarsp)
  1160. {
  1161. int status;
  1162. NC *ncp;
  1163. status = NC_check_id(ncid, &ncp);
  1164. if(status != NC_NOERR)
  1165. return status;
  1166. if(nvarsp != NULL)
  1167. *nvarsp = (int) ncp->vars.nelems;
  1168. return NC_NOERR;
  1169. }
  1170. int
  1171. nc_inq_natts(int ncid, int *nattsp)
  1172. {
  1173. int status;
  1174. NC *ncp;
  1175. status = NC_check_id(ncid, &ncp);
  1176. if(status != NC_NOERR)
  1177. return status;
  1178. if(nattsp != NULL)
  1179. *nattsp = (int) ncp->attrs.nelems;
  1180. return NC_NOERR;
  1181. }
  1182. int
  1183. nc_inq_unlimdim(int ncid, int *xtendimp)
  1184. {
  1185. int status;
  1186. NC *ncp;
  1187. status = NC_check_id(ncid, &ncp);
  1188. if(status != NC_NOERR)
  1189. return status;
  1190. if(xtendimp != NULL)
  1191. *xtendimp = find_NC_Udim(&ncp->dims, NULL);
  1192. return NC_NOERR;
  1193. }
  1194. int
  1195. nc_sync(int ncid)
  1196. {
  1197. int status;
  1198. NC *ncp;
  1199. status = NC_check_id(ncid, &ncp);
  1200. if(status != NC_NOERR)
  1201. return status;
  1202. if(NC_indef(ncp))
  1203. return NC_EINDEFINE;
  1204. if(NC_readonly(ncp))
  1205. {
  1206. return read_NC(ncp);
  1207. }
  1208. /* else, read/write */
  1209. status = NC_sync(ncp);
  1210. if(status != NC_NOERR)
  1211. return status;
  1212. return ncp->nciop->sync(ncp->nciop);
  1213. }
  1214. int
  1215. nc_set_fill(int ncid,
  1216. int fillmode, int *old_mode_ptr)
  1217. {
  1218. int status;
  1219. NC *ncp;
  1220. int oldmode;
  1221. status = NC_check_id(ncid, &ncp);
  1222. if(status != NC_NOERR)
  1223. return status;
  1224. if(NC_readonly(ncp))
  1225. return NC_EPERM;
  1226. oldmode = fIsSet(ncp->flags, NC_NOFILL) ? NC_NOFILL : NC_FILL;
  1227. if(fillmode == NC_NOFILL)
  1228. {
  1229. fSet(ncp->flags, NC_NOFILL);
  1230. }
  1231. else if(fillmode == NC_FILL)
  1232. {
  1233. if(fIsSet(ncp->flags, NC_NOFILL))
  1234. {
  1235. /*
  1236. * We are changing back to fill mode
  1237. * so do a sync
  1238. */
  1239. status = NC_sync(ncp);
  1240. if(status != NC_NOERR)
  1241. return status;
  1242. }
  1243. fClr(ncp->flags, NC_NOFILL);
  1244. }
  1245. else
  1246. {
  1247. return NC_EINVAL; /* Invalid fillmode */
  1248. }
  1249. if(old_mode_ptr != NULL)
  1250. *old_mode_ptr = oldmode;
  1251. return NC_NOERR;
  1252. }
  1253. #ifdef LOCKNUMREC
  1254. /* create function versions of the NC_*_numrecs macros */
  1255. size_t NC_get_numrecs(const NC *ncp) {
  1256. shmem_t numrec;
  1257. shmem_short_get(&numrec, (shmem_t *) ncp->lock + LOCKNUMREC_VALUE, 1,
  1258. ncp->lock[LOCKNUMREC_BASEPE]);
  1259. return (size_t) numrec;
  1260. }
  1261. void NC_set_numrecs(NC *ncp, size_t nrecs) {
  1262. shmem_t numrec = (shmem_t) nrecs;
  1263. /* update local value too */
  1264. ncp->lock[LOCKNUMREC_VALUE] = (ushmem_t) numrec;
  1265. shmem_short_put((shmem_t *) ncp->lock + LOCKNUMREC_VALUE, &numrec, 1,
  1266. ncp->lock[LOCKNUMREC_BASEPE]);
  1267. }
  1268. void NC_increase_numrecs(NC *ncp, size_t nrecs) {
  1269. /* this is only called in one place that's already protected
  1270. * by a lock ... so don't worry about it */
  1271. if (nrecs > NC_get_numrecs(ncp))
  1272. NC_set_numrecs(ncp, nrecs);
  1273. }
  1274. #endif /* LOCKNUMREC */
  1275. /* everyone in communicator group will be executing this */
  1276. /*ARGSUSED*/
  1277. int
  1278. nc_set_base_pe(int ncid, int pe)
  1279. {
  1280. #if _CRAYMPP && defined(LOCKNUMREC)
  1281. int status;
  1282. NC *ncp;
  1283. shmem_t numrecs;
  1284. if ((status = NC_check_id(ncid, &ncp)) != NC_NOERR) {
  1285. return status;
  1286. }
  1287. if (pe < 0 || pe >= _num_pes()) {
  1288. return NC_EINVAL; /* invalid base pe */
  1289. }
  1290. numrecs = (shmem_t) NC_get_numrecs(ncp);
  1291. ncp->lock[LOCKNUMREC_VALUE] = (ushmem_t) numrecs;
  1292. /* update serving & lock values for a "smooth" transition */
  1293. /* note that the "real" server will being doing this as well */
  1294. /* as all the rest in the group */
  1295. /* must have syncronization before & after this step */
  1296. shmem_short_get(
  1297. (shmem_t *) ncp->lock + LOCKNUMREC_SERVING,
  1298. (shmem_t *) ncp->lock + LOCKNUMREC_SERVING,
  1299. 1, ncp->lock[LOCKNUMREC_BASEPE]);
  1300. shmem_short_get(
  1301. (shmem_t *) ncp->lock + LOCKNUMREC_LOCK,
  1302. (shmem_t *) ncp->lock + LOCKNUMREC_LOCK,
  1303. 1, ncp->lock[LOCKNUMREC_BASEPE]);
  1304. /* complete transition */
  1305. ncp->lock[LOCKNUMREC_BASEPE] = (ushmem_t) pe;
  1306. #endif /* _CRAYMPP && LOCKNUMREC */
  1307. return NC_NOERR;
  1308. }
  1309. /*ARGSUSED*/
  1310. int
  1311. nc_inq_base_pe(int ncid, int *pe)
  1312. {
  1313. #if _CRAYMPP && defined(LOCKNUMREC)
  1314. int status;
  1315. NC *ncp;
  1316. if ((status = NC_check_id(ncid, &ncp)) != NC_NOERR) {
  1317. return status;
  1318. }
  1319. *pe = (int) ncp->lock[LOCKNUMREC_BASEPE];
  1320. #else
  1321. /*
  1322. * !_CRAYMPP, only pe 0 is valid
  1323. */
  1324. *pe = 0;
  1325. #endif /* _CRAYMPP && LOCKNUMREC */
  1326. return NC_NOERR;
  1327. }
  1328. int
  1329. nc_inq_format(int ncid, int *formatp)
  1330. {
  1331. int status;
  1332. NC *ncp;
  1333. status = NC_check_id(ncid, &ncp);
  1334. if(status != NC_NOERR)
  1335. return status;
  1336. /* only need to check for netCDF-3 variants, since this is never called for netCDF-4
  1337. files */
  1338. *formatp = fIsSet(ncp->flags, NC_64BIT_OFFSET) ? NC_FORMAT_64BIT
  1339. : NC_FORMAT_CLASSIC;
  1340. return NC_NOERR;
  1341. }