PageRenderTime 63ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/other/netcdf_write_matrix/src/ncgen/genlib.c

http://github.com/jbeezley/wrf-fire
C | 1916 lines | 1568 code | 181 blank | 167 comment | 281 complexity | 6b95d8652fefa7d90683b7f774104869 MD5 | raw file
Possible License(s): AGPL-1.0
  1. /*********************************************************************
  2. * Copyright 1993, UCAR/Unidata
  3. * See netcdf/COPYRIGHT file for copying and redistribution conditions.
  4. * $Header: /upc/share/CVS/netcdf-3/ncgen/genlib.c,v 1.45 2005/11/16 18:04:48 ed Exp $
  5. *********************************************************************/
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <ctype.h> /* for isprint() */
  10. #ifndef NO_STDARG
  11. #include <stdarg.h>
  12. #else
  13. /* try varargs instead */
  14. #include <varargs.h>
  15. #endif /* !NO_STDARG */
  16. #include <netcdf.h>
  17. #include "generic.h"
  18. #include "ncgen.h"
  19. #include "genlib.h"
  20. extern char *netcdf_name; /* output netCDF filename, if on command line. */
  21. extern int netcdf_flag;
  22. extern int c_flag;
  23. extern int fortran_flag;
  24. extern int cmode_modifier;
  25. extern int nofill_flag;
  26. int lineno = 1;
  27. int derror_count = 0;
  28. /* create netCDF from in-memory structure */
  29. static void
  30. gen_netcdf(
  31. char *filename) /* name for output netcdf file */
  32. {
  33. int idim, ivar, iatt;
  34. int dimid;
  35. int varid;
  36. int stat;
  37. stat = nc_create(filename, cmode_modifier, &ncid);
  38. check_err(stat);
  39. /* define dimensions from info in dims array */
  40. for (idim = 0; idim < ndims; idim++) {
  41. stat = nc_def_dim(ncid, dims[idim].name, dims[idim].size, &dimid);
  42. check_err(stat);
  43. }
  44. /* define variables from info in vars array */
  45. for (ivar = 0; ivar < nvars; ivar++) {
  46. stat = nc_def_var(ncid,
  47. vars[ivar].name,
  48. vars[ivar].type,
  49. vars[ivar].ndims,
  50. vars[ivar].dims,
  51. &varid);
  52. check_err(stat);
  53. }
  54. /* define attributes from info in atts array */
  55. for (iatt = 0; iatt < natts; iatt++) {
  56. varid = (atts[iatt].var == -1) ? NC_GLOBAL : atts[iatt].var;
  57. switch(atts[iatt].type) {
  58. case NC_BYTE:
  59. stat = nc_put_att_schar(ncid, varid, atts[iatt].name,
  60. atts[iatt].type, atts[iatt].len,
  61. (signed char *) atts[iatt].val);
  62. break;
  63. case NC_CHAR:
  64. stat = nc_put_att_text(ncid, varid, atts[iatt].name,
  65. atts[iatt].len,
  66. (char *) atts[iatt].val);
  67. break;
  68. case NC_SHORT:
  69. stat = nc_put_att_short(ncid, varid, atts[iatt].name,
  70. atts[iatt].type, atts[iatt].len,
  71. (short *) atts[iatt].val);
  72. break;
  73. case NC_INT:
  74. stat = nc_put_att_int(ncid, varid, atts[iatt].name,
  75. atts[iatt].type, atts[iatt].len,
  76. (int *) atts[iatt].val);
  77. break;
  78. case NC_FLOAT:
  79. stat = nc_put_att_float(ncid, varid, atts[iatt].name,
  80. atts[iatt].type, atts[iatt].len,
  81. (float *) atts[iatt].val);
  82. break;
  83. case NC_DOUBLE:
  84. stat = nc_put_att_double(ncid, varid, atts[iatt].name,
  85. atts[iatt].type, atts[iatt].len,
  86. (double *) atts[iatt].val);
  87. break;
  88. default:
  89. stat = NC_EBADTYPE;
  90. }
  91. check_err(stat);
  92. }
  93. if (nofill_flag) {
  94. stat = nc_set_fill(ncid, NC_NOFILL, 0); /* don't initialize with fill values */
  95. check_err(stat);
  96. }
  97. stat = nc_enddef(ncid);
  98. check_err(stat);
  99. }
  100. /*
  101. * Given a netcdf type, a pointer to a vector of values of that type,
  102. * and the index of the vector element desired, returns a pointer to a
  103. * malloced string representing the value in C.
  104. */
  105. static char *
  106. cstring(
  107. nc_type type, /* netCDF type code */
  108. void *valp, /* pointer to vector of values */
  109. int num) /* element of vector desired */
  110. {
  111. static char *cp, *sp, ch;
  112. signed char *bytep;
  113. short *shortp;
  114. int *intp;
  115. float *floatp;
  116. double *doublep;
  117. switch (type) {
  118. case NC_CHAR:
  119. sp = cp = (char *) emalloc (7);
  120. *cp++ = '\'';
  121. ch = *((char *)valp + num);
  122. switch (ch) {
  123. case '\b': *cp++ = '\\'; *cp++ = 'b'; break;
  124. case '\f': *cp++ = '\\'; *cp++ = 'f'; break;
  125. case '\n': *cp++ = '\\'; *cp++ = 'n'; break;
  126. case '\r': *cp++ = '\\'; *cp++ = 'r'; break;
  127. case '\t': *cp++ = '\\'; *cp++ = 't'; break;
  128. case '\v': *cp++ = '\\'; *cp++ = 'v'; break;
  129. case '\\': *cp++ = '\\'; *cp++ = '\\'; break;
  130. case '\'': *cp++ = '\\'; *cp++ = '\''; break;
  131. default:
  132. if (!isprint((unsigned char)ch)) {
  133. static char octs[] = "01234567";
  134. int rem = ((unsigned char)ch)%64;
  135. *cp++ = '\\';
  136. *cp++ = octs[((unsigned char)ch)/64]; /* to get, e.g. '\177' */
  137. *cp++ = octs[rem/8];
  138. *cp++ = octs[rem%8];
  139. } else {
  140. *cp++ = ch;
  141. }
  142. break;
  143. }
  144. *cp++ = '\'';
  145. *cp = '\0';
  146. return sp;
  147. case NC_BYTE:
  148. cp = (char *) emalloc (7);
  149. bytep = (signed char *)valp;
  150. /* Need to convert '\377' to -1, for example, on all platforms */
  151. (void) sprintf(cp,"%d", (signed char) *(bytep+num));
  152. return cp;
  153. case NC_SHORT:
  154. cp = (char *) emalloc (10);
  155. shortp = (short *)valp;
  156. (void) sprintf(cp,"%d",* (shortp + num));
  157. return cp;
  158. case NC_INT:
  159. cp = (char *) emalloc (20);
  160. intp = (int *)valp;
  161. (void) sprintf(cp,"%d",* (intp + num));
  162. return cp;
  163. case NC_FLOAT:
  164. cp = (char *) emalloc (20);
  165. floatp = (float *)valp;
  166. (void) sprintf(cp,"%.8g",* (floatp + num));
  167. return cp;
  168. case NC_DOUBLE:
  169. cp = (char *) emalloc (20);
  170. doublep = (double *)valp;
  171. (void) sprintf(cp,"%.16g",* (doublep + num));
  172. return cp;
  173. default:
  174. derror("cstring: bad type code");
  175. return 0;
  176. }
  177. }
  178. /*
  179. * Generate C code for creating netCDF from in-memory structure.
  180. */
  181. static void
  182. gen_c(
  183. const char *filename)
  184. {
  185. int idim, ivar, iatt, jatt, maxdims;
  186. int vector_atts;
  187. char *val_string;
  188. char stmnt[C_MAX_STMNT];
  189. /* wrap in main program */
  190. cline("#include <stdio.h>");
  191. cline("#include <stdlib.h>");
  192. cline("#include <netcdf.h>");
  193. cline("");
  194. cline("void");
  195. cline("check_err(const int stat, const int line, const char *file) {");
  196. cline(" if (stat != NC_NOERR) {");
  197. cline(" (void) fprintf(stderr, \"line %d of %s: %s\\n\", line, file, nc_strerror(stat));");
  198. cline(" exit(1);");
  199. cline(" }");
  200. cline("}");
  201. cline("");
  202. cline("int");
  203. sprintf(stmnt, "main() {\t\t\t/* create %s */", filename);
  204. cline(stmnt);
  205. /* create necessary declarations */
  206. cline("");
  207. cline(" int stat;\t\t\t/* return status */");
  208. cline(" int ncid;\t\t\t/* netCDF id */");
  209. if (ndims > 0) {
  210. cline("");
  211. cline(" /* dimension ids */");
  212. for (idim = 0; idim < ndims; idim++) {
  213. sprintf(stmnt, " int %s_dim;", dims[idim].lname);
  214. cline(stmnt);
  215. }
  216. cline("");
  217. cline(" /* dimension lengths */");
  218. for (idim = 0; idim < ndims; idim++) {
  219. if (dims[idim].size == NC_UNLIMITED) {
  220. sprintf(stmnt, " size_t %s_len = NC_UNLIMITED;",
  221. dims[idim].lname);
  222. } else {
  223. sprintf(stmnt, " size_t %s_len = %lu;",
  224. dims[idim].lname,
  225. (unsigned long) dims[idim].size);
  226. }
  227. cline(stmnt);
  228. }
  229. }
  230. maxdims = 0; /* most dimensions of any variable */
  231. for (ivar = 0; ivar < nvars; ivar++)
  232. if (vars[ivar].ndims > maxdims)
  233. maxdims = vars[ivar].ndims;
  234. if (nvars > 0) {
  235. cline("");
  236. cline(" /* variable ids */");
  237. for (ivar = 0; ivar < nvars; ivar++) {
  238. sprintf(stmnt, " int %s_id;", vars[ivar].lname);
  239. cline(stmnt);
  240. }
  241. cline("");
  242. cline(" /* rank (number of dimensions) for each variable */");
  243. for (ivar = 0; ivar < nvars; ivar++) {
  244. sprintf(stmnt, "# define RANK_%s %d", vars[ivar].lname,
  245. vars[ivar].ndims);
  246. cline(stmnt);
  247. }
  248. if (maxdims > 0) { /* we have dimensioned variables */
  249. cline("");
  250. cline(" /* variable shapes */");
  251. for (ivar = 0; ivar < nvars; ivar++) {
  252. if (vars[ivar].ndims > 0) {
  253. sprintf(stmnt, " int %s_dims[RANK_%s];",
  254. vars[ivar].lname, vars[ivar].lname);
  255. cline(stmnt);
  256. }
  257. }
  258. }
  259. }
  260. /* determine if we need any attribute vectors */
  261. vector_atts = 0;
  262. for (iatt = 0; iatt < natts; iatt++) {
  263. if (atts[iatt].type != NC_CHAR) {
  264. vector_atts = 1;
  265. break;
  266. }
  267. }
  268. if (vector_atts) {
  269. cline("");
  270. cline(" /* attribute vectors */");
  271. for (iatt = 0; iatt < natts; iatt++) {
  272. if (atts[iatt].type != NC_CHAR) {
  273. sprintf(stmnt,
  274. " %s %s_%s[%lu];",
  275. ncatype(atts[iatt].type),
  276. atts[iatt].var == -1 ? "cdf" : vars[atts[iatt].var].lname,
  277. atts[iatt].lname,
  278. (unsigned long) atts[iatt].len);
  279. cline(stmnt);
  280. }
  281. }
  282. }
  283. /* create netCDF file, uses NC_CLOBBER mode */
  284. cline("");
  285. cline(" /* enter define mode */");
  286. if (!cmode_modifier) {
  287. sprintf(stmnt,
  288. " stat = nc_create(\"%s\", NC_CLOBBER, &ncid);",
  289. filename);
  290. } else if (cmode_modifier & NC_64BIT_OFFSET) {
  291. sprintf(stmnt,
  292. " stat = nc_create(\"%s\", NC_CLOBBER|NC_64BIT_OFFSET, &ncid);",
  293. filename);
  294. #ifdef USE_NETCDF4
  295. } else if (cmode_modifier & NC_CLASSIC_MODEL) {
  296. sprintf(stmnt,
  297. " stat = nc_create(\"%s\", NC_CLOBBER|NC_NETCDF4|NC_CLASSIC_MODEL, &ncid);",
  298. filename);
  299. } else if (cmode_modifier & NC_NETCDF4) {
  300. sprintf(stmnt,
  301. " stat = nc_create(\"%s\", NC_CLOBBER|NC_NETCDF4, &ncid);",
  302. filename);
  303. #endif
  304. } else {
  305. derror("unknown cmode modifier");
  306. }
  307. cline(stmnt);
  308. cline(" check_err(stat,__LINE__,__FILE__);");
  309. /* define dimensions from info in dims array */
  310. if (ndims > 0) {
  311. cline("");
  312. cline(" /* define dimensions */");
  313. }
  314. for (idim = 0; idim < ndims; idim++) {
  315. sprintf(stmnt,
  316. " stat = nc_def_dim(ncid, \"%s\", %s_len, &%s_dim);",
  317. dims[idim].name, dims[idim].lname, dims[idim].lname);
  318. cline(stmnt);
  319. cline(" check_err(stat,__LINE__,__FILE__);");
  320. }
  321. /* define variables from info in vars array */
  322. if (nvars > 0) {
  323. cline("");
  324. cline(" /* define variables */");
  325. for (ivar = 0; ivar < nvars; ivar++) {
  326. cline("");
  327. for (idim = 0; idim < vars[ivar].ndims; idim++) {
  328. sprintf(stmnt,
  329. " %s_dims[%d] = %s_dim;",
  330. vars[ivar].lname,
  331. idim,
  332. dims[vars[ivar].dims[idim]].lname);
  333. cline(stmnt);
  334. }
  335. if (vars[ivar].ndims > 0) { /* a dimensioned variable */
  336. sprintf(stmnt,
  337. " stat = nc_def_var(ncid, \"%s\", %s, RANK_%s, %s_dims, &%s_id);",
  338. vars[ivar].name,
  339. nctype(vars[ivar].type),
  340. vars[ivar].lname,
  341. vars[ivar].lname,
  342. vars[ivar].lname);
  343. } else { /* a scalar */
  344. sprintf(stmnt,
  345. " stat = nc_def_var(ncid, \"%s\", %s, RANK_%s, 0, &%s_id);",
  346. vars[ivar].name,
  347. nctype(vars[ivar].type),
  348. vars[ivar].lname,
  349. vars[ivar].lname);
  350. }
  351. cline(stmnt);
  352. cline(" check_err(stat,__LINE__,__FILE__);");
  353. }
  354. }
  355. /* define attributes from info in atts array */
  356. if (natts > 0) {
  357. cline("");
  358. cline(" /* assign attributes */");
  359. for (iatt = 0; iatt < natts; iatt++) {
  360. if (atts[iatt].type == NC_CHAR) { /* string */
  361. val_string = cstrstr((char *) atts[iatt].val, atts[iatt].len);
  362. sprintf(stmnt,
  363. " stat = nc_put_att_text(ncid, %s%s, \"%s\", %lu, %s);",
  364. atts[iatt].var == -1 ? "NC_GLOBAL" : vars[atts[iatt].var].lname,
  365. atts[iatt].var == -1 ? "" : "_id",
  366. atts[iatt].name,
  367. (unsigned long) atts[iatt].len,
  368. val_string);
  369. cline(stmnt);
  370. free (val_string);
  371. }
  372. else { /* vector attribute */
  373. for (jatt = 0; jatt < atts[iatt].len ; jatt++) {
  374. val_string = cstring(atts[iatt].type,atts[iatt].val,jatt);
  375. sprintf(stmnt, " %s_%s[%d] = %s;",
  376. atts[iatt].var == -1 ? "cdf" : vars[atts[iatt].var].lname,
  377. atts[iatt].lname,
  378. jatt,
  379. val_string);
  380. cline(stmnt);
  381. free (val_string);
  382. }
  383. sprintf(stmnt,
  384. " stat = nc_put_att_%s(ncid, %s%s, \"%s\", %s, %lu, %s_%s);",
  385. ncatype(atts[iatt].type),
  386. atts[iatt].var == -1 ? "NC_GLOBAL" : vars[atts[iatt].var].lname,
  387. atts[iatt].var == -1 ? "" : "_id",
  388. atts[iatt].name,
  389. nctype(atts[iatt].type),
  390. (unsigned long) atts[iatt].len,
  391. atts[iatt].var == -1 ? "cdf" : vars[atts[iatt].var].lname,
  392. atts[iatt].lname);
  393. cline(stmnt);
  394. }
  395. cline(" check_err(stat,__LINE__,__FILE__);");
  396. }
  397. }
  398. if (nofill_flag) {
  399. cline(" /* don't initialize variables with fill values */");
  400. cline(" stat = nc_set_fill(ncid, NC_NOFILL, 0);");
  401. cline(" check_err(stat,__LINE__,__FILE__);");
  402. }
  403. cline("");
  404. cline(" /* leave define mode */");
  405. cline(" stat = nc_enddef (ncid);");
  406. cline(" check_err(stat,__LINE__,__FILE__);");
  407. }
  408. /* return Fortran type name for netCDF type, given type code */
  409. static const char *
  410. ncftype(
  411. nc_type type) /* netCDF type code */
  412. {
  413. switch (type) {
  414. case NC_BYTE:
  415. return "integer";
  416. case NC_CHAR:
  417. return "character";
  418. case NC_SHORT:
  419. return "integer";
  420. case NC_INT:
  421. #ifdef MSDOS
  422. return "integer*4";
  423. #else
  424. return "integer";
  425. #endif
  426. case NC_FLOAT:
  427. return "real";
  428. #ifdef _CRAY
  429. case NC_DOUBLE:
  430. return "real"; /* we don't support CRAY 128-bit doubles */
  431. #else
  432. case NC_DOUBLE:
  433. return "double precision";
  434. #endif
  435. default:
  436. derror("ncftype: bad type code");
  437. return 0;
  438. }
  439. }
  440. /* return Fortran type suffix for netCDF type, given type code */
  441. const char *
  442. nfstype(
  443. nc_type type) /* netCDF type code */
  444. {
  445. switch (type) {
  446. case NC_BYTE:
  447. return "int1";
  448. case NC_CHAR:
  449. return "text";
  450. case NC_SHORT:
  451. return "int2";
  452. case NC_INT:
  453. return "int";
  454. case NC_FLOAT:
  455. return "real";
  456. case NC_DOUBLE:
  457. return "double";
  458. default:
  459. derror("nfstype: bad type code");
  460. return 0;
  461. }
  462. }
  463. /* Return Fortran function suffix for netCDF type, given type code.
  464. * This should correspond to the Fortran type name in ncftype().
  465. */
  466. const char *
  467. nfftype(
  468. nc_type type) /* netCDF type code */
  469. {
  470. switch (type) {
  471. case NC_BYTE:
  472. return "int";
  473. case NC_CHAR:
  474. return "text";
  475. case NC_SHORT:
  476. return "int";
  477. case NC_INT:
  478. return "int";
  479. case NC_FLOAT:
  480. return "real";
  481. #ifdef _CRAY
  482. case NC_DOUBLE:
  483. return "real"; /* we don't support CRAY 128-bit doubles */
  484. #else
  485. case NC_DOUBLE:
  486. return "double";
  487. #endif
  488. default:
  489. derror("nfstype: bad type code");
  490. return 0;
  491. }
  492. }
  493. /* return FORTRAN name for netCDF type, given type code */
  494. static const char *
  495. ftypename(
  496. nc_type type) /* netCDF type code */
  497. {
  498. switch (type) {
  499. case NC_BYTE:
  500. return "NF_INT1";
  501. case NC_CHAR:
  502. return "NF_CHAR";
  503. case NC_SHORT:
  504. return "NF_INT2";
  505. case NC_INT:
  506. return "NF_INT";
  507. case NC_FLOAT:
  508. return "NF_REAL";
  509. case NC_DOUBLE:
  510. return "NF_DOUBLE";
  511. default:
  512. derror("ftypename: bad type code");
  513. return 0;
  514. }
  515. }
  516. /*
  517. * Generate FORTRAN code for creating netCDF from in-memory structure.
  518. */
  519. static void
  520. gen_fortran(
  521. const char *filename)
  522. {
  523. int idim, ivar, iatt, jatt, itype, maxdims;
  524. int vector_atts;
  525. char *val_string;
  526. char stmnt[FORT_MAX_STMNT];
  527. char s2[NC_MAX_NAME + 10];
  528. char *sp;
  529. /* Need how many netCDF types there are, because we create an array
  530. * for each type of attribute. */
  531. int ntypes = 6; /* number of netCDF types, NC_BYTE, ... */
  532. nc_type types[6]; /* at least ntypes */
  533. size_t max_atts[NC_DOUBLE + 1];
  534. types[0] = NC_BYTE;
  535. types[1] = NC_CHAR;
  536. types[2] = NC_SHORT;
  537. types[3] = NC_INT;
  538. types[4] = NC_FLOAT;
  539. types[5] = NC_DOUBLE;
  540. fline("program fgennc");
  541. fline("include 'netcdf.inc'");
  542. /* create necessary declarations */
  543. fline("* error status return");
  544. fline("integer iret");
  545. fline("* netCDF id");
  546. fline("integer ncid");
  547. if (nofill_flag) {
  548. fline("* to save old fill mode before changing it temporarily");
  549. fline("integer oldmode");
  550. }
  551. if (ndims > 0) {
  552. fline("* dimension ids");
  553. for (idim = 0; idim < ndims; idim++) {
  554. sprintf(stmnt, "integer %s_dim", dims[idim].lname);
  555. fline(stmnt);
  556. }
  557. fline("* dimension lengths");
  558. for (idim = 0; idim < ndims; idim++) {
  559. sprintf(stmnt, "integer %s_len", dims[idim].lname);
  560. fline(stmnt);
  561. }
  562. for (idim = 0; idim < ndims; idim++) {
  563. if (dims[idim].size == NC_UNLIMITED) {
  564. sprintf(stmnt, "parameter (%s_len = NF_UNLIMITED)",
  565. dims[idim].lname);
  566. } else {
  567. sprintf(stmnt, "parameter (%s_len = %lu)",
  568. dims[idim].lname,
  569. (unsigned long) dims[idim].size);
  570. }
  571. fline(stmnt);
  572. }
  573. }
  574. maxdims = 0; /* most dimensions of any variable */
  575. for (ivar = 0; ivar < nvars; ivar++)
  576. if (vars[ivar].ndims > maxdims)
  577. maxdims = vars[ivar].ndims;
  578. if (nvars > 0) {
  579. fline("* variable ids");
  580. for (ivar = 0; ivar < nvars; ivar++) {
  581. sprintf(stmnt, "integer %s_id", vars[ivar].lname);
  582. fline(stmnt);
  583. }
  584. fline("* rank (number of dimensions) for each variable");
  585. for (ivar = 0; ivar < nvars; ivar++) {
  586. sprintf(stmnt, "integer %s_rank", vars[ivar].lname);
  587. fline(stmnt);
  588. }
  589. for (ivar = 0; ivar < nvars; ivar++) {
  590. sprintf(stmnt, "parameter (%s_rank = %d)", vars[ivar].lname,
  591. vars[ivar].ndims);
  592. fline(stmnt);
  593. }
  594. fline("* variable shapes");
  595. for (ivar = 0; ivar < nvars; ivar++) {
  596. if (vars[ivar].ndims > 0) {
  597. sprintf(stmnt, "integer %s_dims(%s_rank)",
  598. vars[ivar].lname, vars[ivar].lname);
  599. fline(stmnt);
  600. }
  601. }
  602. }
  603. /* declarations for variables to be initialized */
  604. if (nvars > 0) { /* we have variables */
  605. fline("* data variables");
  606. for (ivar = 0; ivar < nvars; ivar++) {
  607. struct vars *v = &vars[ivar];
  608. /* Generate declarations here for non-record data variables only.
  609. Record variables are declared in separate subroutine later,
  610. when we know how big they are. */
  611. if (v->ndims > 0 && v->dims[0] == rec_dim) {
  612. continue;
  613. }
  614. /* Make declarations for non-text variables only;
  615. for text variables, just include string in nf_put_var call */
  616. if (v->type == NC_CHAR) {
  617. continue;
  618. }
  619. if (v->ndims == 0) { /* scalar */
  620. sprintf(stmnt, "%s %s", ncftype(v->type),
  621. v->lname);
  622. } else {
  623. sprintf(stmnt, "%s %s(", ncftype(v->type),
  624. v->lname);
  625. /* reverse dimensions for FORTRAN */
  626. for (idim = v->ndims-1; idim >= 0; idim--) {
  627. sprintf(s2, "%s_len, ",
  628. dims[v->dims[idim]].lname);
  629. strcat(stmnt, s2);
  630. }
  631. sp = strrchr(stmnt, ',');
  632. if(sp != NULL) {
  633. *sp = '\0';
  634. }
  635. strcat(stmnt, ")");
  636. }
  637. fline(stmnt);
  638. }
  639. }
  640. /* determine what attribute vectors needed */
  641. for (itype = 0; itype < ntypes; itype++)
  642. max_atts[(int)types[itype]] = 0;
  643. vector_atts = 0;
  644. for (iatt = 0; iatt < natts; iatt++) {
  645. if (atts[iatt].len > max_atts[(int) atts[iatt].type]) {
  646. max_atts[(int)atts[iatt].type] = atts[iatt].len;
  647. vector_atts = 1;
  648. }
  649. }
  650. if (vector_atts) {
  651. fline("* attribute vectors");
  652. for (itype = 0; itype < ntypes; itype++) {
  653. if (types[itype] != NC_CHAR && max_atts[(int)types[itype]] > 0) {
  654. sprintf(stmnt, "%s %sval(%lu)", ncftype(types[itype]),
  655. nfstype(types[itype]),
  656. (unsigned long) max_atts[(int)types[itype]]);
  657. fline(stmnt);
  658. }
  659. }
  660. }
  661. /* create netCDF file, uses NC_CLOBBER mode */
  662. fline("* enter define mode");
  663. if (!cmode_modifier) {
  664. sprintf(stmnt, "iret = nf_create(\'%s\', NF_CLOBBER, ncid)", filename);
  665. } else if (cmode_modifier & NC_64BIT_OFFSET) {
  666. sprintf(stmnt, "iret = nf_create(\'%s\', OR(NF_CLOBBER,NF_64BIT_OFFSET), ncid)", filename);
  667. #ifdef USE_NETCDF4
  668. } else if (cmode_modifier & NC_CLASSIC_MODEL) {
  669. sprintf(stmnt, "iret = nf_create(\'%s\', OR(NF_CLOBBER,NC_NETCDF4,NC_CLASSIC_MODEL), ncid)", filename);
  670. } else if (cmode_modifier & NC_NETCDF4) {
  671. sprintf(stmnt, "iret = nf_create(\'%s\', OR(NF_CLOBBER,NF_NETCDF4), ncid)", filename);
  672. #endif
  673. } else {
  674. derror("unknown cmode modifier");
  675. }
  676. fline(stmnt);
  677. fline("call check_err(iret)");
  678. /* define dimensions from info in dims array */
  679. if (ndims > 0)
  680. fline("* define dimensions");
  681. for (idim = 0; idim < ndims; idim++) {
  682. if (dims[idim].size == NC_UNLIMITED)
  683. sprintf(stmnt, "iret = nf_def_dim(ncid, \'%s\', NF_UNLIMITED, %s_dim)",
  684. dims[idim].name, dims[idim].lname);
  685. else
  686. sprintf(stmnt, "iret = nf_def_dim(ncid, \'%s\', %lu, %s_dim)",
  687. dims[idim].name, (unsigned long) dims[idim].size,
  688. dims[idim].lname);
  689. fline(stmnt);
  690. fline("call check_err(iret)");
  691. }
  692. /* define variables from info in vars array */
  693. if (nvars > 0) {
  694. fline("* define variables");
  695. for (ivar = 0; ivar < nvars; ivar++) {
  696. for (idim = 0; idim < vars[ivar].ndims; idim++) {
  697. sprintf(stmnt, "%s_dims(%d) = %s_dim",
  698. vars[ivar].lname,
  699. vars[ivar].ndims - idim, /* reverse dimensions */
  700. dims[vars[ivar].dims[idim]].lname);
  701. fline(stmnt);
  702. }
  703. if (vars[ivar].ndims > 0) { /* a dimensioned variable */
  704. sprintf(stmnt,
  705. "iret = nf_def_var(ncid, \'%s\', %s, %s_rank, %s_dims, %s_id)",
  706. vars[ivar].name,
  707. ftypename(vars[ivar].type),
  708. vars[ivar].lname,
  709. vars[ivar].lname,
  710. vars[ivar].lname);
  711. } else { /* a scalar */
  712. sprintf(stmnt,
  713. "iret = nf_def_var(ncid, \'%s\', %s, %s_rank, 0, %s_id)",
  714. vars[ivar].name,
  715. ftypename(vars[ivar].type),
  716. vars[ivar].lname,
  717. vars[ivar].lname);
  718. }
  719. fline(stmnt);
  720. fline("call check_err(iret)");
  721. }
  722. }
  723. /* define attributes from info in atts array */
  724. if (natts > 0) {
  725. fline("* assign attributes");
  726. for (iatt = 0; iatt < natts; iatt++) {
  727. if (atts[iatt].type == NC_CHAR) { /* string */
  728. val_string = fstrstr((char *) atts[iatt].val, atts[iatt].len);
  729. sprintf(stmnt,
  730. "iret = nf_put_att_text(ncid, %s%s, \'%s\', %lu, %s)",
  731. atts[iatt].var == -1 ? "NF_GLOBAL" : vars[atts[iatt].var].lname,
  732. atts[iatt].var == -1 ? "" : "_id",
  733. atts[iatt].name,
  734. (unsigned long) atts[iatt].len,
  735. val_string);
  736. fline(stmnt);
  737. fline("call check_err(iret)");
  738. free(val_string);
  739. } else {
  740. for (jatt = 0; jatt < atts[iatt].len ; jatt++) {
  741. val_string = fstring(atts[iatt].type,atts[iatt].val,jatt);
  742. sprintf(stmnt, "%sval(%d) = %s",
  743. nfstype(atts[iatt].type),
  744. jatt+1,
  745. val_string);
  746. fline(stmnt);
  747. free (val_string);
  748. }
  749. sprintf(stmnt,
  750. "iret = nf_put_att_%s(ncid, %s%s, \'%s\', %s, %lu, %sval)",
  751. nfftype(atts[iatt].type),
  752. atts[iatt].var == -1 ? "NCGLOBAL" : vars[atts[iatt].var].lname,
  753. atts[iatt].var == -1 ? "" : "_id",
  754. atts[iatt].name,
  755. ftypename(atts[iatt].type),
  756. (unsigned long) atts[iatt].len,
  757. nfstype(atts[iatt].type));
  758. fline(stmnt);
  759. fline("call check_err(iret)");
  760. }
  761. }
  762. }
  763. if (nofill_flag) {
  764. fline("* don't initialize variables with fill values");
  765. fline("iret = nf_set_fill(ncid, NF_NOFILL, oldmode)");
  766. fline("call check_err(iret)");
  767. }
  768. fline("* leave define mode");
  769. fline("iret = nf_enddef(ncid)");
  770. fline("call check_err(iret)");
  771. }
  772. /*
  773. * Output a C statement.
  774. */
  775. void
  776. cline(
  777. const char *stmnt)
  778. {
  779. FILE *cout = stdout;
  780. fputs(stmnt, cout);
  781. fputs("\n", cout);
  782. }
  783. /*
  784. * From a long line FORTRAN statment, generates the necessary FORTRAN
  785. * lines with continuation characters in column 6. If stmnt starts with "*",
  786. * it is treated as a one-line comment. Statement labels are *not* handled,
  787. * but since we don't generate any labels, we don't care.
  788. */
  789. void
  790. fline(
  791. const char *stmnt)
  792. {
  793. FILE *fout = stdout;
  794. int len = (int) strlen(stmnt);
  795. int line = 0;
  796. static char cont[] = { /* continuation characters */
  797. ' ', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  798. '+', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  799. '+', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
  800. if(stmnt[0] == '*') {
  801. fputs(stmnt, fout);
  802. fputs("\n", fout);
  803. return;
  804. }
  805. while (len > 0) {
  806. if (line >= FORT_MAX_LINES)
  807. derror("FORTRAN statement too long: %s",stmnt);
  808. (void) fprintf(fout, " %c", cont[line++]);
  809. (void) fprintf(fout, "%.66s\n", stmnt);
  810. len -= 66;
  811. if (len > 0)
  812. stmnt += 66;
  813. }
  814. }
  815. /* return C name for netCDF type, given type code */
  816. const char *
  817. nctype(
  818. nc_type type) /* netCDF type code */
  819. {
  820. switch (type) {
  821. case NC_BYTE:
  822. return "NC_BYTE";
  823. case NC_CHAR:
  824. return "NC_CHAR";
  825. case NC_SHORT:
  826. return "NC_SHORT";
  827. case NC_INT:
  828. return "NC_INT";
  829. case NC_FLOAT:
  830. return "NC_FLOAT";
  831. case NC_DOUBLE:
  832. return "NC_DOUBLE";
  833. default:
  834. derror("nctype: bad type code");
  835. return 0;
  836. }
  837. }
  838. /*
  839. * Return C type name for netCDF type, given type code.
  840. */
  841. const char *
  842. ncctype(
  843. nc_type type) /* netCDF type code */
  844. {
  845. switch (type) {
  846. case NC_BYTE:
  847. return "signed char";
  848. case NC_CHAR:
  849. return "char";
  850. case NC_SHORT:
  851. return "short";
  852. case NC_INT:
  853. return "int";
  854. case NC_FLOAT:
  855. return "float";
  856. case NC_DOUBLE:
  857. return "double";
  858. default:
  859. derror("ncctype: bad type code");
  860. return 0;
  861. }
  862. }
  863. /*
  864. * Return C type name for netCDF type suffix, given type code.
  865. */
  866. const char *
  867. ncstype(
  868. nc_type type) /* netCDF type code */
  869. {
  870. switch (type) {
  871. case NC_BYTE:
  872. return "schar";
  873. case NC_CHAR:
  874. return "text";
  875. case NC_SHORT:
  876. return "short";
  877. case NC_INT:
  878. return "int";
  879. case NC_FLOAT:
  880. return "float";
  881. case NC_DOUBLE:
  882. return "double";
  883. default:
  884. derror("ncstype: bad type code");
  885. return 0;
  886. }
  887. }
  888. /*
  889. * Return C type name for netCDF attribute container type, given type code.
  890. */
  891. const char *
  892. ncatype(
  893. nc_type type) /* netCDF type code */
  894. {
  895. switch (type) {
  896. case NC_BYTE:
  897. return "int"; /* avoids choosing between uchar and schar */
  898. case NC_CHAR:
  899. return "text";
  900. case NC_SHORT:
  901. return "short";
  902. case NC_INT:
  903. return "int";
  904. case NC_FLOAT:
  905. return "float";
  906. case NC_DOUBLE:
  907. return "double";
  908. default:
  909. derror("ncatype: bad type code");
  910. return 0;
  911. }
  912. }
  913. /* return internal size for values of specified netCDF type */
  914. size_t
  915. nctypesize(
  916. nc_type type) /* netCDF type code */
  917. {
  918. switch (type) {
  919. case NC_BYTE:
  920. return sizeof(char);
  921. case NC_CHAR:
  922. return sizeof(char);
  923. case NC_SHORT:
  924. return sizeof(short);
  925. case NC_INT:
  926. return sizeof(int);
  927. case NC_FLOAT:
  928. return sizeof(float);
  929. case NC_DOUBLE:
  930. return sizeof(double);
  931. default:
  932. derror("nctypesize: bad type code");
  933. return 0;
  934. }
  935. }
  936. /*
  937. * Given a netcdf numeric type, a pointer to a vector of values of that
  938. * type, and the index of the vector element desired, returns a pointer
  939. * to a malloced string representing the value in FORTRAN. Since this
  940. * may be used in a DATA statement, it must not include non-constant
  941. * expressions, such as "char(26)".
  942. */
  943. char *
  944. fstring(
  945. nc_type type, /* netCDF type code */
  946. void *valp, /* pointer to vector of values */
  947. int num) /* element of vector desired */
  948. {
  949. static char *cp;
  950. signed char *schp;
  951. short *shortp;
  952. int *intp;
  953. float *floatp;
  954. double *doublep;
  955. switch (type) {
  956. case NC_BYTE:
  957. cp = (char *) emalloc (10);
  958. schp = (signed char *)valp;
  959. sprintf(cp,"%d", schp[num]);
  960. return cp;
  961. case NC_SHORT:
  962. cp = (char *) emalloc (10);
  963. shortp = (short *)valp;
  964. (void) sprintf(cp,"%d",* (shortp + num));
  965. return cp;
  966. case NC_INT:
  967. cp = (char *) emalloc (20);
  968. intp = (int *)valp;
  969. (void) sprintf(cp,"%d",* (intp + num));
  970. return cp;
  971. case NC_FLOAT:
  972. cp = (char *) emalloc (20);
  973. floatp = (float *)valp;
  974. (void) sprintf(cp,"%.8g",* (floatp + num));
  975. return cp;
  976. case NC_DOUBLE:
  977. cp = (char *) emalloc (25);
  978. doublep = (double *)valp;
  979. (void) sprintf(cp,"%.16g",* (doublep + num));
  980. expe2d(cp); /* change 'e' to 'd' in exponent */
  981. return cp;
  982. default:
  983. derror("fstring: bad type code");
  984. return 0;
  985. }
  986. }
  987. /*
  988. * Given a pointer to a counted string, returns a pointer to a malloced string
  989. * representing the string as a C constant.
  990. */
  991. char *
  992. cstrstr(
  993. const char *valp, /* pointer to vector of characters*/
  994. size_t len) /* number of characters in valp */
  995. {
  996. static char *sp;
  997. char *cp;
  998. char *istr, *istr0; /* for null-terminated copy */
  999. int ii;
  1000. if(4*len+3 != (unsigned)(4*len+3)) {
  1001. derror("too much character data!");
  1002. exit(9);
  1003. }
  1004. sp = cp = (char *) emalloc(4*len+3);
  1005. if(len == 1 && *valp == 0) { /* empty string */
  1006. strcpy(sp,"\"\"");
  1007. return sp;
  1008. }
  1009. istr0 = istr = (char *) emalloc(len + 1);
  1010. for(ii = 0; ii < len; ii++) {
  1011. istr[ii] = valp[ii];
  1012. }
  1013. istr[len] = '\0';
  1014. *cp++ = '"';
  1015. for(ii = 0; ii < len; ii++) {
  1016. switch (*istr) {
  1017. case '\0': *cp++ = '\\'; *cp++ = '0'; *cp++ = '0'; *cp++ = '0'; break;
  1018. case '\b': *cp++ = '\\'; *cp++ = 'b'; break;
  1019. case '\f': *cp++ = '\\'; *cp++ = 'f'; break;
  1020. case '\n': *cp++ = '\\'; *cp++ = 'n'; break;
  1021. case '\r': *cp++ = '\\'; *cp++ = 'r'; break;
  1022. case '\t': *cp++ = '\\'; *cp++ = 't'; break;
  1023. case '\v': *cp++ = '\\'; *cp++ = 'v'; break;
  1024. case '\\': *cp++ = '\\'; *cp++ = '\\'; break;
  1025. case '\"': *cp++ = '\\'; *cp++ = '\"'; break;
  1026. default:
  1027. if (!isprint((unsigned char)*istr)) {
  1028. static char octs[] = "01234567";
  1029. int rem = ((unsigned char)*istr)%64;
  1030. *cp++ = '\\';
  1031. *cp++ = octs[((unsigned char)*istr)/64]; /* to get, e.g. '\177' */
  1032. *cp++ = octs[rem/8];
  1033. *cp++ = octs[rem%8];
  1034. } else {
  1035. *cp++ = *istr;
  1036. }
  1037. break;
  1038. }
  1039. istr++;
  1040. }
  1041. *cp++ = '"';
  1042. *cp = '\0';
  1043. free(istr0);
  1044. return sp;
  1045. }
  1046. /* Given a pointer to a counted string (not necessarily
  1047. * null-terminated), returns a pointer to a malloced string representing
  1048. * the string as a FORTRAN string expression. For example, the string
  1049. * "don't" would yield the FORTRAN string "'don''t'", and the string
  1050. * "ab\ncd" would yield "'ab'//char(10)//'cd'". The common
  1051. * interpretation of "\"-escaped characters is non-standard, so the
  1052. * generated Fortran may require adjustment in compilers that don't
  1053. * recognize "\" as anything special in a character context. */
  1054. char *
  1055. fstrstr(
  1056. const char *str, /* pointer to vector of characters */
  1057. size_t ilen) /* number of characters in istr */
  1058. {
  1059. static char *ostr;
  1060. char *cp, tstr[12];
  1061. int was_print = 0; /* true if last character was printable */
  1062. char *istr, *istr0; /* for null-terminated copy */
  1063. int ii;
  1064. if(12*ilen != (size_t)(12*ilen)) {
  1065. derror("too much character data!");
  1066. exit(9);
  1067. }
  1068. istr0 = istr = (char *) emalloc(ilen + 1);
  1069. for(ii = 0; ii < ilen; ii++) {
  1070. istr[ii] = str[ii];
  1071. }
  1072. istr[ilen] = '\0';
  1073. if (*istr == '\0') { /* empty string input, not legal in FORTRAN */
  1074. ostr = (char*) emalloc(strlen("char(0)") + 1);
  1075. strcpy(ostr, "char(0)");
  1076. free(istr0);
  1077. return ostr;
  1078. }
  1079. ostr = cp = (char *) emalloc(12*ilen);
  1080. *ostr = '\0';
  1081. if (isprint((unsigned char)*istr)) { /* handle first character in input */
  1082. *cp++ = '\'';
  1083. switch (*istr) {
  1084. case '\'':
  1085. *cp++ = '\'';
  1086. *cp++ = '\'';
  1087. break;
  1088. case '\\':
  1089. *cp++ = '\\';
  1090. *cp++ = '\\';
  1091. break;
  1092. default:
  1093. *cp++ = *istr;
  1094. break;
  1095. }
  1096. *cp = '\0';
  1097. was_print = 1;
  1098. } else {
  1099. sprintf(tstr, "char(%d)", (unsigned char)*istr);
  1100. strcat(cp, tstr);
  1101. cp += strlen(tstr);
  1102. was_print = 0;
  1103. }
  1104. istr++;
  1105. for(ii = 1; ii < ilen; ii++) { /* handle subsequent characters in input */
  1106. if (isprint((unsigned char)*istr)) {
  1107. if (! was_print) {
  1108. strcat(cp, "//'");
  1109. cp += 3;
  1110. }
  1111. switch (*istr) {
  1112. case '\'':
  1113. *cp++ = '\'';
  1114. *cp++ = '\'';
  1115. break;
  1116. case '\\':
  1117. *cp++ = '\\';
  1118. *cp++ = '\\';
  1119. break;
  1120. default:
  1121. *cp++ = *istr;
  1122. break;
  1123. }
  1124. *cp = '\0';
  1125. was_print = 1;
  1126. } else {
  1127. if (was_print) {
  1128. *cp++ = '\'';
  1129. *cp = '\0';
  1130. }
  1131. sprintf(tstr, "//char(%d)", (unsigned char)*istr);
  1132. strcat(cp, tstr);
  1133. cp += strlen(tstr);
  1134. was_print = 0;
  1135. }
  1136. istr++;
  1137. }
  1138. if (was_print)
  1139. *cp++ = '\'';
  1140. *cp = '\0';
  1141. free(istr0);
  1142. return ostr;
  1143. }
  1144. static void
  1145. cl_netcdf(void)
  1146. {
  1147. int stat = nc_close(ncid);
  1148. check_err(stat);
  1149. }
  1150. static void
  1151. cl_c(void)
  1152. {
  1153. cline(" stat = nc_close(ncid);");
  1154. cline(" check_err(stat,__LINE__,__FILE__);");
  1155. #ifndef vms
  1156. cline(" return 0;");
  1157. #else
  1158. cline(" return 1;");
  1159. #endif
  1160. cline("}");
  1161. }
  1162. /* Returns true if dimension used in at least one record variable,
  1163. otherwise false. This is an inefficient algorithm, but we don't call
  1164. it very often ... */
  1165. static int
  1166. used_in_rec_var(
  1167. int idim /* id of dimension */
  1168. ) {
  1169. int ivar;
  1170. for (ivar = 0; ivar < nvars; ivar++) {
  1171. if (vars[ivar].ndims > 0 && vars[ivar].dims[0] == rec_dim) {
  1172. int jdim;
  1173. for (jdim = 0; jdim < vars[ivar].ndims; jdim++) {
  1174. if (vars[ivar].dims[jdim] == idim)
  1175. return 1;
  1176. }
  1177. }
  1178. }
  1179. return 0;
  1180. }
  1181. /* Return name for Fortran fill constant of specified type */
  1182. static const char *
  1183. f_fill_name(
  1184. nc_type type
  1185. )
  1186. {
  1187. switch(type) {
  1188. case NC_BYTE:
  1189. return "NF_FILL_BYTE";
  1190. case NC_CHAR:
  1191. return "NF_FILL_CHAR";
  1192. case NC_SHORT:
  1193. return "NF_FILL_SHORT";
  1194. case NC_INT:
  1195. return "NF_FILL_INT";
  1196. case NC_FLOAT:
  1197. return "NF_FILL_FLOAT";
  1198. case NC_DOUBLE:
  1199. return "NF_FILL_DOUBLE";
  1200. }
  1201. derror("f_fill_name: bad type code");
  1202. return 0;
  1203. }
  1204. /* Generate Fortran for cleaning up and closing file */
  1205. static void
  1206. cl_fortran(void)
  1207. {
  1208. int ivar;
  1209. int idim;
  1210. char stmnt[FORT_MAX_STMNT];
  1211. char s2[FORT_MAX_STMNT];
  1212. char*sp;
  1213. int have_rec_var = 0;
  1214. /* do we have any record variables? */
  1215. for (ivar = 0; ivar < nvars; ivar++) {
  1216. struct vars *v = &vars[ivar];
  1217. if (v->ndims > 0 && v->dims[0] == rec_dim) {
  1218. have_rec_var = 1;
  1219. break;
  1220. }
  1221. }
  1222. if (have_rec_var) {
  1223. fline(" ");
  1224. fline("* Write record variables");
  1225. sprintf(stmnt, "call writerecs(ncid,");
  1226. /* generate parameter list for subroutine to write record vars */
  1227. for (ivar = 0; ivar < nvars; ivar++) {
  1228. struct vars *v = &vars[ivar];
  1229. /* if a record variable, include id in parameter list */
  1230. if (v->ndims > 0 && v->dims[0] == rec_dim) {
  1231. sprintf(s2, "%s_id,", v->lname);
  1232. strcat(stmnt, s2);
  1233. }
  1234. }
  1235. sp = strrchr(stmnt, ',');
  1236. if(sp != NULL) {
  1237. *sp = '\0';
  1238. }
  1239. strcat(stmnt, ")");
  1240. fline(stmnt);
  1241. }
  1242. fline(" ");
  1243. fline("iret = nf_close(ncid)");
  1244. fline("call check_err(iret)");
  1245. fline("end");
  1246. fline(" ");
  1247. if (have_rec_var) {
  1248. sprintf(stmnt, "subroutine writerecs(ncid,");
  1249. for (ivar = 0; ivar < nvars; ivar++) {
  1250. struct vars *v = &vars[ivar];
  1251. if (v->ndims > 0 && v->dims[0] == rec_dim) {
  1252. sprintf(s2, "%s_id,", v->lname);
  1253. strcat(stmnt, s2);
  1254. }
  1255. }
  1256. sp = strrchr(stmnt, ',');
  1257. if(sp != NULL) {
  1258. *sp = '\0';
  1259. }
  1260. strcat(stmnt, ")");
  1261. fline(stmnt);
  1262. fline(" ");
  1263. fline("* netCDF id");
  1264. fline("integer ncid");
  1265. fline("* variable ids");
  1266. for (ivar = 0; ivar < nvars; ivar++) {
  1267. struct vars *v = &vars[ivar];
  1268. if (v->ndims > 0 && v->dims[0] == rec_dim) {
  1269. sprintf(stmnt, "integer %s_id", v->lname);
  1270. fline(stmnt);
  1271. }
  1272. }
  1273. fline(" ");
  1274. fline("include 'netcdf.inc'");
  1275. /* create necessary declarations */
  1276. fline("* error status return");
  1277. fline("integer iret");
  1278. /* generate integer/parameter declarations for all dimensions
  1279. used in record variables, except record dimension. */
  1280. fline(" ");
  1281. fline("* netCDF dimension sizes for dimensions used with record variables");
  1282. for (idim = 0; idim < ndims; idim++) {
  1283. /* if used in a record variable and not record dimension */
  1284. if (used_in_rec_var(idim) && dims[idim].size != NC_UNLIMITED) {
  1285. sprintf(stmnt, "integer %s_len", dims[idim].lname);
  1286. fline(stmnt);
  1287. sprintf(stmnt, "parameter (%s_len = %lu)",
  1288. dims[idim].lname, (unsigned long) dims[idim].size);
  1289. fline(stmnt);
  1290. }
  1291. }
  1292. fline(" ");
  1293. fline("* rank (number of dimensions) for each variable");
  1294. for (ivar = 0; ivar < nvars; ivar++) {
  1295. struct vars *v = &vars[ivar];
  1296. if (v->ndims > 0 && v->dims[0] == rec_dim) {
  1297. sprintf(stmnt, "integer %s_rank", v->lname);
  1298. fline(stmnt);
  1299. }
  1300. }
  1301. for (ivar = 0; ivar < nvars; ivar++) {
  1302. struct vars *v = &vars[ivar];
  1303. if (v->ndims > 0 && v->dims[0] == rec_dim) {
  1304. sprintf(stmnt, "parameter (%s_rank = %d)", v->lname,
  1305. v->ndims);
  1306. fline(stmnt);
  1307. }
  1308. }
  1309. fline("* starts and counts for array sections of record variables");
  1310. for (ivar = 0; ivar < nvars; ivar++) {
  1311. struct vars *v = &vars[ivar];
  1312. if (v->ndims > 0 && v->dims[0] == rec_dim) {
  1313. sprintf(stmnt,
  1314. "integer %s_start(%s_rank), %s_count(%s_rank)",
  1315. v->lname, v->lname, v->lname, v->lname);
  1316. fline(stmnt);
  1317. }
  1318. }
  1319. fline(" ");
  1320. fline("* data variables");
  1321. for (ivar = 0; ivar < nvars; ivar++) {
  1322. struct vars *v = &vars[ivar];
  1323. if (v->ndims > 0 && v->dims[0] == rec_dim) {
  1324. char *sp;
  1325. fline(" ");
  1326. sprintf(stmnt, "integer %s_nr", v->lname);
  1327. fline(stmnt);
  1328. if (v->nrecs > 0) {
  1329. sprintf(stmnt, "parameter (%s_nr = %lu)",
  1330. v->lname, (unsigned long) v->nrecs);
  1331. } else {
  1332. sprintf(stmnt, "parameter (%s_nr = 1)",
  1333. v->lname);
  1334. }
  1335. fline(stmnt);
  1336. if (v->type != NC_CHAR) {
  1337. sprintf(stmnt, "%s %s(", ncftype(v->type),
  1338. v->lname);
  1339. /* reverse dimensions for FORTRAN */
  1340. for (idim = v->ndims-1; idim >= 0; idim--) {
  1341. if(v->dims[idim] == rec_dim) {
  1342. sprintf(s2, "%s_nr, ", v->lname);
  1343. } else {
  1344. sprintf(s2, "%s_len, ",
  1345. dims[v->dims[idim]].lname);
  1346. }
  1347. strcat(stmnt, s2);
  1348. }
  1349. sp = strrchr(stmnt, ',');
  1350. if(sp != NULL) {
  1351. *sp = '\0';
  1352. }
  1353. strcat(stmnt, ")");
  1354. fline(stmnt);
  1355. }
  1356. }
  1357. }
  1358. fline(" ");
  1359. /* Emit DATA statements after declarations, because f2c on Linux can't
  1360. handle interspersing them */
  1361. for (ivar = 0; ivar < nvars; ivar++) {
  1362. struct vars *v = &vars[ivar];
  1363. if (v->ndims > 0 && v->dims[0] == rec_dim && v->type != NC_CHAR) {
  1364. if (v->has_data) {
  1365. fline(v->data_stmnt);
  1366. } else { /* generate data statement for FILL record */
  1367. size_t rec_len = 1;
  1368. for (idim = 1; idim < v->ndims; idim++) {
  1369. rec_len *= dims[v->dims[idim]].size;
  1370. }
  1371. sprintf(stmnt,"data %s /%lu * %s/", v->lname,
  1372. (unsigned long) rec_len,
  1373. f_fill_name(v->type));
  1374. fline(stmnt);
  1375. }
  1376. }
  1377. }
  1378. fline(" ");
  1379. for (ivar = 0; ivar < nvars; ivar++) {
  1380. struct vars *v = &vars[ivar];
  1381. /* if a record variable, declare starts and counts */
  1382. if (v->ndims > 0 && v->dims[0] == rec_dim) {
  1383. if (!v->has_data)
  1384. continue;
  1385. sprintf(stmnt, "* store %s", v->name);
  1386. fline(stmnt);
  1387. for (idim = 0; idim < v->ndims; idim++) {
  1388. sprintf(stmnt, "%s_start(%d) = 1", v->lname, idim+1);
  1389. fline(stmnt);
  1390. }
  1391. for (idim = v->ndims-1; idim > 0; idim--) {
  1392. sprintf(stmnt, "%s_count(%d) = %s_len", v->lname,
  1393. v->ndims - idim, dims[v->dims[idim]].lname);
  1394. fline(stmnt);
  1395. }
  1396. sprintf(stmnt, "%s_count(%d) = %s_nr", v->lname,
  1397. v->ndims, v->lname);
  1398. fline(stmnt);
  1399. if (v->type != NC_CHAR) {
  1400. sprintf(stmnt,
  1401. "iret = nf_put_vara_%s(ncid, %s_id, %s_start, %s_count, %s)",
  1402. nfftype(v->type), v->lname, v->lname, v->lname, v->lname);
  1403. } else {
  1404. sprintf(stmnt,
  1405. "iret = nf_put_vara_%s(ncid, %s_id, %s_start, %s_count, %s)",
  1406. nfftype(v->type), v->lname, v->lname, v->lname,
  1407. v->data_stmnt);
  1408. }
  1409. fline(stmnt);
  1410. fline("call check_err(iret)");
  1411. }
  1412. }
  1413. fline(" ");
  1414. fline("end");
  1415. fline(" ");
  1416. }
  1417. fline("subroutine check_err(iret)");
  1418. fline("integer iret");
  1419. fline("include 'netcdf.inc'");
  1420. fline("if (iret .ne. NF_NOERR) then");
  1421. fline("print *, nf_strerror(iret)");
  1422. fline("stop");
  1423. fline("endif");
  1424. fline("end");
  1425. }
  1426. /* invoke netcdf calls (or generate C or Fortran code) to create netcdf
  1427. * from in-memory structure. */
  1428. void
  1429. define_netcdf(
  1430. const char *netcdfname)
  1431. {
  1432. char *filename; /* output file name */
  1433. if (netcdf_name) { /* name given on command line */
  1434. filename = netcdf_name;
  1435. } else { /* construct name from CDL name */
  1436. filename = (char *) emalloc(strlen(netcdfname) + 5);
  1437. (void) strcpy(filename,netcdfname);
  1438. if (netcdf_flag == -1)
  1439. (void) strcat(filename,".cdf"); /* old, deprecated extension */
  1440. else
  1441. (void) strcat(filename,".nc"); /* new, favored extension */
  1442. }
  1443. if (netcdf_flag)
  1444. gen_netcdf(filename); /* create netcdf */
  1445. if (c_flag) /* create C code to create netcdf */
  1446. gen_c(filename);
  1447. if (fortran_flag) /* create Fortran code to create netcdf */
  1448. gen_fortran(filename);
  1449. free(filename);
  1450. }
  1451. void
  1452. close_netcdf(void)
  1453. {
  1454. if (netcdf_flag)
  1455. cl_netcdf(); /* close netcdf */
  1456. if (c_flag) /* create C code to close netcdf */
  1457. cl_c();
  1458. if (fortran_flag) /* create Fortran code to close netcdf */
  1459. cl_fortran();
  1460. }
  1461. void
  1462. check_err(int stat) {
  1463. if (stat != NC_NOERR) {
  1464. fprintf(stderr, "ncgen: %s\n", nc_strerror(stat));
  1465. derror_count++;
  1466. }
  1467. }
  1468. /*
  1469. * For logging error conditions.
  1470. */
  1471. #ifndef NO_STDARG
  1472. void
  1473. derror(const char *fmt, ...)
  1474. #else
  1475. /*VARARGS1*/
  1476. void
  1477. derror(fmt, va_alist)
  1478. const char *fmt ; /* error-message printf-style format */
  1479. va_dcl /* variable number of error args, if any */
  1480. #endif /* !NO_STDARG */
  1481. {
  1482. va_list args ;
  1483. if (lineno == 1)
  1484. (void) fprintf(stderr,"%s: %s: ", progname, cdlname);
  1485. else
  1486. (void) fprintf(stderr,"%s: %s line %d: ", progname, cdlname, lineno);
  1487. #ifndef NO_STDARG
  1488. va_start(args ,fmt) ;
  1489. #else
  1490. va_start(args) ;
  1491. #endif /* !NO_STDARG */
  1492. (void) vfprintf(stderr,fmt,args) ;
  1493. va_end(args) ;
  1494. (void) fputc('\n',stderr) ;
  1495. (void) fflush(stderr); /* to ensure log files are current */
  1496. derror_count++;
  1497. }
  1498. void *
  1499. emalloc ( /* check return from malloc */
  1500. size_t size)
  1501. {
  1502. void *p;
  1503. p = (void *) malloc (size);
  1504. if (p == 0) {
  1505. derror ("out of memory\n");
  1506. exit(3);
  1507. }
  1508. return p;
  1509. }
  1510. void *
  1511. ecalloc ( /* check return from calloc */
  1512. size_t size)
  1513. {
  1514. void *p;
  1515. p = (void *) calloc (size, 1);
  1516. if (p == 0) {
  1517. derror ("out of memory\n");
  1518. exit(3);
  1519. }
  1520. return p;
  1521. }
  1522. void *
  1523. erealloc ( /* check return from realloc */
  1524. void *ptr,
  1525. size_t size) /* if 0, this is really a free */
  1526. {
  1527. void *p;
  1528. p = (void *) realloc (ptr, size);
  1529. if (p == 0 && size != 0) {
  1530. derror ("out of memory");
  1531. exit(3);
  1532. }
  1533. return p;
  1534. }
  1535. /*
  1536. * For generated Fortran, change 'e' to 'd' in exponent of double precision
  1537. * constants.
  1538. */
  1539. void
  1540. expe2d(
  1541. char *cp) /* string containing double constant */
  1542. {
  1543. char *expchar = strrchr(cp,'e');
  1544. if (expchar) {
  1545. *expchar = 'd';
  1546. }
  1547. }
  1548. /* Returns non-zero if n is a power of 2, 0 otherwise */
  1549. static
  1550. int
  1551. pow2(
  1552. int n)
  1553. {
  1554. int m = n;
  1555. int p = 1;
  1556. while (m > 0) {
  1557. m /= 2;
  1558. p *= 2;
  1559. }
  1560. return p == 2*n;
  1561. }
  1562. /*
  1563. * Grow an integer array as necessary.
  1564. *
  1565. * Assumption: nar never incremented by more than 1 from last call.
  1566. *
  1567. * Makes sure an array is within a factor of 2 of the size needed.
  1568. *
  1569. * Make sure *arpp points to enough space to hold nar integers. If not big
  1570. * enough, malloc more space, copy over existing stuff, free old. When
  1571. * called for first time, *arpp assumed to be uninitialized.
  1572. */
  1573. void
  1574. grow_iarray(
  1575. int nar, /* array must be at least this big */
  1576. int **arpp) /* address of start of int array */
  1577. {
  1578. if (nar == 0) {
  1579. *arpp = (int *) emalloc(1 * sizeof(int));
  1580. return;
  1581. }
  1582. if (! pow2(nar)) /* return unless nar is a power of two */
  1583. return;
  1584. *arpp = (int *) erealloc(*arpp, 2 * nar * sizeof(int));
  1585. }
  1586. /*
  1587. * Grow an array of variables as necessary.
  1588. *
  1589. * Assumption: nar never incremented by more than 1 from last call.
  1590. *
  1591. * Makes sure array is within a factor of 2 of the size needed.
  1592. *
  1593. * Make sure *arpp points to enough space to hold nar variables. If not big
  1594. * enough, malloc more space, copy over existing stuff, free old. When
  1595. * called for first time, *arpp assumed to be uninitialized.
  1596. */
  1597. void
  1598. grow_varray(
  1599. int nar, /* array must be at least this big */
  1600. struct vars **arpp) /* address of start of var array */
  1601. {
  1602. if (nar == 0) {
  1603. *arpp = (struct vars *) emalloc(1 * sizeof(struct vars));
  1604. return;
  1605. }
  1606. if (! pow2(nar)) /* return unless nar is a power of two */
  1607. return;
  1608. *arpp = (struct vars *) erealloc(*arpp, 2 * nar * sizeof(struct vars));
  1609. }
  1610. /*
  1611. * Grow an array of dimensions as necessary.
  1612. *
  1613. * Assumption: nar never incremented by more than 1 from last call.
  1614. *
  1615. * Makes sure array is within a factor of 2 of the size needed.
  1616. *
  1617. * Make sure *arpp points to enough space to hold nar dimensions. If not big
  1618. * enough, malloc more space, copy over existing stuff, free old. When
  1619. * called for first time, *arpp assumed to be uninitialized.
  1620. */
  1621. void
  1622. grow_darray(
  1623. int nar, /* array must be at least this big */
  1624. struct dims **arpp) /* address of start of var array */
  1625. {
  1626. if (nar == 0) {
  1627. *arpp = (struct dims *) emalloc(1 * sizeof(struct dims));
  1628. return;
  1629. }
  1630. if (! pow2(nar)) /* return unless nar is a power of two */
  1631. return;
  1632. *arpp = (struct dims *) erealloc(*arpp, 2 * nar * sizeof(struct dims));
  1633. }
  1634. /*
  1635. * Grow an array of attributes as necessary.
  1636. *
  1637. * Assumption: nar never incremented by more than 1 from last call.
  1638. *
  1639. * Makes sure array is within a factor of 2 of the size needed.
  1640. *
  1641. * Make sure *arpp points to enough space to hold nar attributes. If not big
  1642. * enough, malloc more space, copy over existing stuff, free old. When
  1643. * called for first time, *arpp assumed to be uninitialized.
  1644. */
  1645. void
  1646. grow_aarray(
  1647. int nar, /* array must be at least this big */
  1648. struct atts **arpp) /* address of start of var array */
  1649. {
  1650. if (nar == 0) {
  1651. *arpp = (struct atts *) emalloc(1 * sizeof(struct atts));
  1652. return;
  1653. }
  1654. if (! pow2(nar)) /* return unless nar is a power of two */
  1655. return;
  1656. *arpp = (struct atts *) erealloc(*arpp, 2 * nar * sizeof(struct atts));
  1657. }
  1658. /*
  1659. * Replace dashes and dots in name so it can be used in C and
  1660. * Fortran without causing syntax errors. Here we just replace each "-"
  1661. * in a name with "_dash_" and each "." with "_dot_", though any
  1662. * similar replacement that doesn't clash with existing names would
  1663. * work.
  1664. */
  1665. extern char*
  1666. decodify (
  1667. const char *name)
  1668. {
  1669. int count=0; /* number of minus signs in name */
  1670. char *newname;
  1671. const char *cp = name;
  1672. char *sp;
  1673. while(*cp != '\0') {
  1674. switch (*cp) {
  1675. case '-':
  1676. count += strlen("_dash_") - 1;
  1677. break;
  1678. case '.':
  1679. count += strlen("_dot_") - 1;
  1680. break;
  1681. case '@':
  1682. count += strlen("_at_") - 1;
  1683. break;
  1684. case '#':
  1685. count += strlen("_hash_") - 1;
  1686. break;
  1687. case '[':
  1688. count += strlen("_lbr_") - 1;
  1689. break;
  1690. case ']':
  1691. count += strlen("_rbr_") - 1;
  1692. break;
  1693. default:
  1694. break;
  1695. }
  1696. cp++;
  1697. }
  1698. newname = (char *) ecalloc(strlen(name) + count + 1);
  1699. cp = name;
  1700. sp = newname;
  1701. while(*cp != '\0') {
  1702. switch (*cp) {
  1703. case '-':
  1704. strcat(sp, "_dash_");
  1705. sp += strlen("_dash_");
  1706. break;
  1707. case '.':
  1708. strcat(sp, "_dot_");
  1709. sp += strlen("_dot_");
  1710. break;
  1711. case '@':
  1712. strcat(sp, "_at_");
  1713. sp += strlen("_at_");
  1714. break;
  1715. case '#':
  1716. strcat(sp, "_hash_");
  1717. sp += strlen("_hash_");
  1718. break;
  1719. case '[':
  1720. strcat(sp, "_lbr_");
  1721. sp += strlen("_lbr_");
  1722. break;
  1723. case ']':
  1724. strcat(sp, "_rbr_");
  1725. sp += strlen("_rbr_");
  1726. break;
  1727. default:
  1728. *sp++ = *cp;
  1729. break;
  1730. }
  1731. cp++;
  1732. }
  1733. *sp = '\0';
  1734. return newname;
  1735. }