dapdump.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  1. /*********************************************************************
  2. * Copyright 1993, UCAR/Unidata
  3. * See netcdf/COPYRIGHT file for copying and redistribution conditions.
  4. * $Header: /upc/share/CVS/netcdf-3/libncdap3/dapdump.c,v 1.21 2010/05/26 21:43:31 dmh Exp $
  5. *********************************************************************/
  6. #include "config.h"
  7. #ifdef USE_PARALLEL
  8. #include "netcdf_par.h"
  9. #endif
  10. #include "ncdap3.h"
  11. #include "dapdump.h"
  12. #include "dceconstraints.h"
  13. #define CHECK(n) if((n) != NC_NOERR) {return (n);} else {}
  14. static void dumptreer(CDFnode* root, NCbytes* buf, int indent, int visible);
  15. int
  16. dumpmetadata(int ncid, NChdr** hdrp)
  17. {
  18. int stat,i,j,k;
  19. NChdr* hdr = (NChdr*)calloc(1,sizeof(NChdr));
  20. MEMCHECK(hdr,NC_ENOMEM);
  21. hdr->ncid = ncid;
  22. hdr->content = ncbytesnew();
  23. if(hdrp) *hdrp = hdr;
  24. stat = nc_inq(hdr->ncid,
  25. &hdr->ndims,
  26. &hdr->nvars,
  27. &hdr->ngatts,
  28. &hdr->unlimid);
  29. CHECK(stat);
  30. if(ncdap3debug > 0) {
  31. fprintf(stdout,"ncid=%d ngatts=%d ndims=%d nvars=%d unlimid=%d\n",
  32. hdr->ncid,hdr->ngatts,hdr->ndims,hdr->nvars,hdr->unlimid);
  33. }
  34. hdr->gatts = (NCattribute*)calloc(1,hdr->ngatts*sizeof(NCattribute));
  35. MEMCHECK(hdr->gatts,NC_ENOMEM);
  36. if(hdr->ngatts > 0)
  37. fprintf(stdout,"global attributes:\n");
  38. for(i=0;i<hdr->ngatts;i++) {
  39. NCattribute* att = &hdr->gatts[i];
  40. char attname[NC_MAX_NAME];
  41. nc_type nctype;
  42. size_t typesize;
  43. size_t nvalues;
  44. stat = nc_inq_attname(hdr->ncid,NC_GLOBAL,i,attname);
  45. CHECK(stat);
  46. att->name = nulldup(attname);
  47. stat = nc_inq_att(hdr->ncid,NC_GLOBAL,att->name,&nctype,&nvalues);
  48. CHECK(stat);
  49. att->etype = nctypetodap(nctype);
  50. typesize = nctypesizeof(att->etype);
  51. fprintf(stdout,"\t[%d]: name=%s type=%s values(%lu)=",
  52. i,att->name,nctypetostring(octypetonc(att->etype)),
  53. (unsigned long)nvalues);
  54. if(nctype == NC_CHAR) {
  55. size_t len = typesize*nvalues;
  56. char* values = (char*)malloc(len+1);/* for null terminate*/
  57. MEMCHECK(values,NC_ENOMEM);
  58. stat = nc_get_att(hdr->ncid,NC_GLOBAL,att->name,values);
  59. CHECK(stat);
  60. values[len] = '\0';
  61. fprintf(stdout," '%s'",values);
  62. } else {
  63. size_t len = typesize*nvalues;
  64. char* values = (char*)malloc(len);
  65. MEMCHECK(values,NC_ENOMEM);
  66. stat = nc_get_att(hdr->ncid,NC_GLOBAL,att->name,values);
  67. CHECK(stat);
  68. for(k=0;k<nvalues;k++) {
  69. fprintf(stdout," ");
  70. dumpdata1(octypetonc(att->etype),k,values);
  71. }
  72. }
  73. fprintf(stdout,"\n");
  74. }
  75. hdr->dims = (Dim*)malloc(hdr->ndims*sizeof(Dim));
  76. MEMCHECK(hdr->dims,NC_ENOMEM);
  77. for(i=0;i<hdr->ndims;i++) {
  78. hdr->dims[i].dimid = i;
  79. stat = nc_inq_dim(hdr->ncid,
  80. hdr->dims[i].dimid,
  81. hdr->dims[i].name,
  82. &hdr->dims[i].size);
  83. CHECK(stat);
  84. fprintf(stdout,"dim[%d]: name=%s size=%lu\n",
  85. i,hdr->dims[i].name,(unsigned long)hdr->dims[i].size);
  86. }
  87. hdr->vars = (Var*)malloc(hdr->nvars*sizeof(Var));
  88. MEMCHECK(hdr->vars,NC_ENOMEM);
  89. for(i=0;i<hdr->nvars;i++) {
  90. Var* var = &hdr->vars[i];
  91. nc_type nctype;
  92. var->varid = i;
  93. stat = nc_inq_var(hdr->ncid,
  94. var->varid,
  95. var->name,
  96. &nctype,
  97. &var->ndims,
  98. var->dimids,
  99. &var->natts);
  100. CHECK(stat);
  101. var->nctype = (nctype);
  102. fprintf(stdout,"var[%d]: name=%s type=%s |dims|=%d",
  103. i,
  104. var->name,
  105. nctypetostring(var->nctype),
  106. var->ndims);
  107. fprintf(stdout," dims={");
  108. for(j=0;j<var->ndims;j++) {
  109. fprintf(stdout," %d",var->dimids[j]);
  110. }
  111. fprintf(stdout,"}\n");
  112. var->atts = (NCattribute*)malloc(var->natts*sizeof(NCattribute));
  113. MEMCHECK(var->atts,NC_ENOMEM);
  114. for(j=0;j<var->natts;j++) {
  115. NCattribute* att = &var->atts[j];
  116. char attname[NC_MAX_NAME];
  117. size_t typesize;
  118. char* values;
  119. nc_type nctype;
  120. size_t nvalues;
  121. stat = nc_inq_attname(hdr->ncid,var->varid,j,attname);
  122. CHECK(stat);
  123. att->name = nulldup(attname);
  124. stat = nc_inq_att(hdr->ncid,var->varid,att->name,&nctype,&nvalues);
  125. CHECK(stat);
  126. att->etype = nctypetodap(nctype);
  127. typesize = nctypesizeof(att->etype);
  128. values = (char*)malloc(typesize*nvalues);
  129. MEMCHECK(values,NC_ENOMEM);
  130. stat = nc_get_att(hdr->ncid,var->varid,att->name,values);
  131. CHECK(stat);
  132. fprintf(stdout,"\tattr[%d]: name=%s type=%s values(%lu)=",
  133. j,att->name,nctypetostring(octypetonc(att->etype)),(unsigned long)nvalues);
  134. for(k=0;k<nvalues;k++) {
  135. fprintf(stdout," ");
  136. dumpdata1(octypetonc(att->etype),k,values);
  137. }
  138. fprintf(stdout,"\n");
  139. }
  140. }
  141. fflush(stdout);
  142. return NC_NOERR;
  143. }
  144. void
  145. dumpdata1(nc_type nctype, size_t index, char* data)
  146. {
  147. switch (nctype) {
  148. case NC_CHAR:
  149. fprintf(stdout,"'%c' %hhd",data[index],data[index]);
  150. break;
  151. case NC_BYTE:
  152. fprintf(stdout,"%hdB",((signed char*)data)[index]);
  153. break;
  154. case NC_UBYTE:
  155. fprintf(stdout,"%huB",((unsigned char*)data)[index]);
  156. break;
  157. case NC_SHORT:
  158. fprintf(stdout,"%hdS",((short*)data)[index]);
  159. break;
  160. case NC_USHORT:
  161. fprintf(stdout,"%hdUS",((unsigned short*)data)[index]);
  162. break;
  163. case NC_INT:
  164. fprintf(stdout,"%d",((int*)data)[index]);
  165. break;
  166. case NC_UINT:
  167. fprintf(stdout,"%uU",((unsigned int*)data)[index]);
  168. break;
  169. case NC_FLOAT:
  170. fprintf(stdout,"%#gF",((float*)data)[index]);
  171. break;
  172. case NC_DOUBLE:
  173. fprintf(stdout,"%#gD",((double*)data)[index]);
  174. break;
  175. case NC_STRING:
  176. fprintf(stdout,"\"%s\"",((char**)data)[index]);
  177. break;
  178. default:
  179. fprintf(stdout,"Unknown type: %i",nctype);
  180. break;
  181. }
  182. fflush(stdout);
  183. }
  184. /* Following should be kept consistent with
  185. the makeXXXstring3 routines in constraints3.c
  186. */
  187. /* Convert an NCprojection instance into a string
  188. that can be used with the url
  189. */
  190. char*
  191. dumpprojections(NClist* projections)
  192. {
  193. char* tmp;
  194. int v = dceverbose;
  195. dceverbose = 1;
  196. tmp = dcelisttostring(projections,",");
  197. dceverbose = v;
  198. return tmp;
  199. }
  200. char*
  201. dumpprojection(DCEprojection* proj)
  202. {
  203. char* tmp;
  204. int v = dceverbose;
  205. dceverbose = 1;
  206. tmp = dcetostring((DCEnode*)proj);
  207. dceverbose = v;
  208. return tmp;
  209. }
  210. char*
  211. dumpselections(NClist* selections)
  212. {
  213. return dcelisttostring(selections,"&");
  214. }
  215. char*
  216. dumpselection(DCEselection* sel)
  217. {
  218. return dcetostring((DCEnode*)sel);
  219. }
  220. char*
  221. dumpconstraint(DCEconstraint* con)
  222. {
  223. char* tmp;
  224. int v = dceverbose;
  225. dceverbose = 1;
  226. tmp = dcetostring((DCEnode*)con);
  227. dceverbose = v;
  228. return tmp;
  229. }
  230. char*
  231. dumpsegments(NClist* segments)
  232. {
  233. return dcelisttostring(segments,".");
  234. }
  235. char*
  236. dumppath(CDFnode* leaf)
  237. {
  238. NClist* path = nclistnew();
  239. NCbytes* buf = ncbytesnew();
  240. char* result;
  241. int i;
  242. if(leaf == NULL) return nulldup("");
  243. collectnodepath3(leaf,path,!WITHDATASET);
  244. for(i=0;i<nclistlength(path);i++) {
  245. CDFnode* node = (CDFnode*)nclistget(path,i);
  246. if(i > 0) ncbytescat(buf,".");
  247. ncbytescat(buf,node->ncbasename);
  248. }
  249. result = ncbytesdup(buf);
  250. ncbytesfree(buf);
  251. nclistfree(path);
  252. return result;
  253. }
  254. static void
  255. dumpindent(int indent, NCbytes* buf)
  256. {
  257. static char* indentstr = " ";
  258. int i;
  259. for(i=0;i<indent;i++) ncbytescat(buf,indentstr);
  260. }
  261. static void
  262. dumptreer1(CDFnode* root, NCbytes* buf, int indent, char* tag, int visible)
  263. {
  264. int i;
  265. dumpindent(indent,buf);
  266. ncbytescat(buf,tag);
  267. ncbytescat(buf," {\n");
  268. for(i=0;i<nclistlength(root->subnodes);i++) {
  269. CDFnode* node = (CDFnode*)nclistget(root->subnodes,i);
  270. if(visible && !root->visible) continue;
  271. if(root->nctype == NC_Grid) {
  272. if(i==0) {
  273. dumpindent(indent+1,buf);
  274. ncbytescat(buf,"Array:\n");
  275. } else if(i==1) {
  276. dumpindent(indent+1,buf);
  277. ncbytescat(buf,"Maps:\n");
  278. }
  279. dumptreer(node,buf,indent+2,visible);
  280. } else {
  281. dumptreer(node,buf,indent+1,visible);
  282. }
  283. }
  284. dumpindent(indent,buf);
  285. ncbytescat(buf,"} ");
  286. ncbytescat(buf,root->ncbasename);
  287. }
  288. static void
  289. dumptreer(CDFnode* root, NCbytes* buf, int indent, int visible)
  290. {
  291. int i;
  292. char* primtype = NULL;
  293. NClist* dimset = NULL;
  294. if(visible && !root->visible) return;
  295. switch (root->nctype) {
  296. case NC_Dataset:
  297. dumptreer1(root,buf,indent,"Dataset",visible);
  298. break;
  299. case NC_Sequence:
  300. dumptreer1(root,buf,indent,"Sequence",visible);
  301. break;
  302. case NC_Structure:
  303. dumptreer1(root,buf,indent,"Structure",visible);
  304. break;
  305. case NC_Grid:
  306. dumptreer1(root,buf,indent,"Grid",visible);
  307. break;
  308. case NC_Primitive:
  309. switch (root->etype) {
  310. case NC_BYTE: primtype = "byte"; break;
  311. case NC_CHAR: primtype = "char"; break;
  312. case NC_SHORT: primtype = "short"; break;
  313. case NC_INT: primtype = "int"; break;
  314. case NC_FLOAT: primtype = "float"; break;
  315. case NC_DOUBLE: primtype = "double"; break;
  316. case NC_UBYTE: primtype = "ubyte"; break;
  317. case NC_USHORT: primtype = "ushort"; break;
  318. case NC_UINT: primtype = "uint"; break;
  319. case NC_INT64: primtype = "int64"; break;
  320. case NC_UINT64: primtype = "uint64"; break;
  321. case NC_STRING: primtype = "string"; break;
  322. default: break;
  323. }
  324. dumpindent(indent,buf);
  325. ncbytescat(buf,primtype);
  326. ncbytescat(buf," ");
  327. ncbytescat(buf,root->ncbasename);
  328. break;
  329. default: break;
  330. }
  331. if(nclistlength(root->array.dimsetplus) > 0) dimset = root->array.dimsetplus;
  332. else if(nclistlength(root->array.dimset0) > 0) dimset = root->array.dimset0;
  333. if(dimset != NULL) {
  334. for(i=0;i<nclistlength(dimset);i++) {
  335. CDFnode* dim = (CDFnode*)nclistget(dimset,i);
  336. char tmp[64];
  337. ncbytescat(buf,"[");
  338. if(dim->ncbasename != NULL) {
  339. ncbytescat(buf,dim->ncbasename);
  340. ncbytescat(buf,"=");
  341. }
  342. snprintf(tmp,sizeof(tmp),"%lu",(unsigned long)dim->dim.declsize);
  343. ncbytescat(buf,tmp);
  344. ncbytescat(buf,"]");
  345. }
  346. }
  347. ncbytescat(buf,";\n");
  348. }
  349. char*
  350. dumptree(CDFnode* root)
  351. {
  352. NCbytes* buf = ncbytesnew();
  353. char* result;
  354. dumptreer(root,buf,0,0);
  355. result = ncbytesdup(buf);
  356. ncbytesfree(buf);
  357. return result;
  358. }
  359. char*
  360. dumpvisible(CDFnode* root)
  361. {
  362. NCbytes* buf = ncbytesnew();
  363. char* result;
  364. dumptreer(root,buf,0,1);
  365. result = ncbytesdup(buf);
  366. ncbytesfree(buf);
  367. return result;
  368. }
  369. /* Provide detailed data on a CDFnode */
  370. char*
  371. dumpnode(CDFnode* node)
  372. {
  373. NCbytes* buf = ncbytesnew();
  374. char* result;
  375. int i;
  376. char* nctype = NULL;
  377. char* primtype = NULL;
  378. char tmp[1024];
  379. switch (node->nctype) {
  380. case NC_Dataset: nctype = "Dataset"; break;
  381. case NC_Sequence: nctype = "Sequence"; break;
  382. case NC_Structure: nctype = "Structure"; break;
  383. case NC_Grid: nctype = "Grid"; break;
  384. case NC_Primitive:
  385. switch (node->etype) {
  386. case NC_BYTE: primtype = "byte"; break;
  387. case NC_CHAR: primtype = "char"; break;
  388. case NC_SHORT: primtype = "short"; break;
  389. case NC_INT: primtype = "int"; break;
  390. case NC_FLOAT: primtype = "float"; break;
  391. case NC_DOUBLE: primtype = "double"; break;
  392. case NC_UBYTE: primtype = "ubyte"; break;
  393. case NC_USHORT: primtype = "ushort"; break;
  394. case NC_UINT: primtype = "uint"; break;
  395. case NC_INT64: primtype = "int64"; break;
  396. case NC_UINT64: primtype = "uint64"; break;
  397. case NC_STRING: primtype = "string"; break;
  398. default: break;
  399. }
  400. break;
  401. default: break;
  402. }
  403. snprintf(tmp,sizeof(tmp),"%s %s {\n",
  404. (nctype?nctype:primtype),node->ocname);
  405. ncbytescat(buf,tmp);
  406. snprintf(tmp,sizeof(tmp),"ocnode=%lx\n",(unsigned long)node->ocnode);
  407. ncbytescat(buf,tmp);
  408. snprintf(tmp,sizeof(tmp),"container=%s\n",
  409. (node->container?node->container->ocname:"null"));
  410. ncbytescat(buf,tmp);
  411. snprintf(tmp,sizeof(tmp),"root=%s\n",
  412. (node->root?node->root->ocname:"null"));
  413. ncbytescat(buf,tmp);
  414. snprintf(tmp,sizeof(tmp),"ncbasename=%s\n",node->ncbasename);
  415. ncbytescat(buf,tmp);
  416. snprintf(tmp,sizeof(tmp),"ncfullname=%s\n",node->ncfullname);
  417. ncbytescat(buf,tmp);
  418. snprintf(tmp,sizeof(tmp),"|subnodes|=%d\n",nclistlength(node->subnodes));
  419. ncbytescat(buf,tmp);
  420. snprintf(tmp,sizeof(tmp),"externaltype=%d\n",node->externaltype);
  421. ncbytescat(buf,tmp);
  422. snprintf(tmp,sizeof(tmp),"ncid=%d\n",node->ncid);
  423. ncbytescat(buf,tmp);
  424. snprintf(tmp,sizeof(tmp),"maxstringlength=%ld\n",node->maxstringlength);
  425. ncbytescat(buf,tmp);
  426. snprintf(tmp,sizeof(tmp),"sequencelimit=%ld\n",node->sequencelimit);
  427. ncbytescat(buf,tmp);
  428. snprintf(tmp,sizeof(tmp),"usesequence=%d\n",node->usesequence);
  429. ncbytescat(buf,tmp);
  430. snprintf(tmp,sizeof(tmp),"elided=%d\n",node->elided);
  431. ncbytescat(buf,tmp);
  432. snprintf(tmp,sizeof(tmp),"visible=%d\n",node->visible);
  433. ncbytescat(buf,tmp);
  434. snprintf(tmp,sizeof(tmp),"attachment=%s\n",
  435. (node->attachment?node->attachment->ocname:"null"));
  436. ncbytescat(buf,tmp);
  437. snprintf(tmp,sizeof(tmp),"rank=%u\n",nclistlength(node->array.dimset0));
  438. ncbytescat(buf,tmp);
  439. for(i=0;i<nclistlength(node->array.dimset0);i++) {
  440. CDFnode* dim = (CDFnode*)nclistget(node->array.dimset0,i);
  441. snprintf(tmp,sizeof(tmp),"dims[%d]={\n",i);
  442. ncbytescat(buf,tmp);
  443. snprintf(tmp,sizeof(tmp)," ocname=%s\n",dim->ocname);
  444. ncbytescat(buf,tmp);
  445. snprintf(tmp,sizeof(tmp)," ncbasename=%s\n",dim->ncbasename);
  446. ncbytescat(buf,tmp);
  447. snprintf(tmp,sizeof(tmp)," dimflags=%u\n",
  448. (unsigned int)dim->dim.dimflags);
  449. ncbytescat(buf,tmp);
  450. snprintf(tmp,sizeof(tmp)," declsize=%lu\n",
  451. (unsigned long)dim->dim.declsize);
  452. ncbytescat(buf,tmp);
  453. snprintf(tmp,sizeof(tmp)," }\n");
  454. ncbytescat(buf,tmp);
  455. }
  456. result = ncbytesdup(buf);
  457. ncbytesfree(buf);
  458. return result;
  459. }
  460. char*
  461. dumpalign(NCalignment* ncalign)
  462. {
  463. char* result;
  464. char tmp[1024];
  465. if(ncalign == NULL)
  466. result = nulldup("NCalignment{size=-- alignment=-- offset=--}");
  467. else {
  468. snprintf(tmp,sizeof(tmp),"NCalignment{size=%lu alignment=%lu offset=%lu}",
  469. ncalign->size,ncalign->alignment,ncalign->offset);
  470. result = nulldup(tmp);
  471. }
  472. return result;
  473. }
  474. char*
  475. dumpcachenode(NCcachenode* node)
  476. {
  477. char* result = NULL;
  478. char tmp[8192];
  479. int i;
  480. NCbytes* buf;
  481. if(node == NULL) return strdup("cachenode{null}");
  482. buf = ncbytesnew();
  483. result = buildconstraintstring3(node->constraint);
  484. snprintf(tmp,sizeof(tmp),"cachenode%s(%lx){size=%lu; constraint=%s; vars=",
  485. node->prefetch?"*":"",
  486. (unsigned long)node,
  487. (unsigned long)node->xdrsize,
  488. result);
  489. ncbytescat(buf,tmp);
  490. if(nclistlength(node->vars)==0)
  491. ncbytescat(buf,"null");
  492. else for(i=0;i<nclistlength(node->vars);i++) {
  493. CDFnode* var = (CDFnode*)nclistget(node->vars,i);
  494. if(i > 0) ncbytescat(buf,",");
  495. ncbytescat(buf,makecdfpathstring3(var,"."));
  496. }
  497. ncbytescat(buf,"}");
  498. result = ncbytesdup(buf);
  499. ncbytesfree(buf);
  500. return result;
  501. }
  502. char*
  503. dumpcache(NCcache* cache)
  504. {
  505. char* result = NULL;
  506. char tmp[8192];
  507. int i;
  508. NCbytes* buf;
  509. if(cache == NULL) return strdup("cache{null}");
  510. buf = ncbytesnew();
  511. snprintf(tmp,sizeof(tmp),"cache{limit=%lu; size=%lu;\n",
  512. (unsigned long)cache->cachelimit,
  513. (unsigned long)cache->cachesize);
  514. ncbytescat(buf,tmp);
  515. if(cache->prefetch) {
  516. ncbytescat(buf,"\tprefetch=");
  517. ncbytescat(buf,dumpcachenode(cache->prefetch));
  518. ncbytescat(buf,"\n");
  519. }
  520. if(nclistlength(cache->nodes) > 0) {
  521. for(i=0;i<nclistlength(cache->nodes);i++) {
  522. NCcachenode* node = (NCcachenode*)nclistget(cache->nodes,i);
  523. ncbytescat(buf,"\t");
  524. ncbytescat(buf,dumpcachenode(node));
  525. ncbytescat(buf,"\n");
  526. }
  527. }
  528. ncbytescat(buf,"}");
  529. result = ncbytesdup(buf);
  530. ncbytesfree(buf);
  531. return result;
  532. }
  533. /* This should be consistent with makeslicestring3 in constraints3.c */
  534. char*
  535. dumpslice(DCEslice* slice)
  536. {
  537. char buf[8192];
  538. char tmp[8192];
  539. size_t last = (slice->first+slice->length)-1;
  540. buf[0] = '\0';
  541. if(last > slice->declsize && slice->declsize > 0)
  542. last = slice->declsize - 1;
  543. if(slice->count == 1) {
  544. snprintf(tmp,sizeof(tmp),"[%lu]",
  545. (unsigned long)slice->first);
  546. } else if(slice->stride == 1) {
  547. snprintf(tmp,sizeof(tmp),"[%lu:%lu]",
  548. (unsigned long)slice->first,
  549. (unsigned long)last);
  550. } else {
  551. snprintf(tmp,sizeof(tmp),"[%lu:%lu:%lu]",
  552. (unsigned long)slice->first,
  553. (unsigned long)slice->stride,
  554. (unsigned long)last);
  555. }
  556. strcat(buf,tmp);
  557. return strdup(tmp);
  558. }
  559. char*
  560. dumpslices(DCEslice* slice, unsigned int rank)
  561. {
  562. int i;
  563. NCbytes* buf;
  564. char* result = NULL;
  565. buf = ncbytesnew();
  566. for(i=0;i<rank;i++,slice++) {
  567. ncbytescat(buf,dumpslice(slice));
  568. }
  569. result = ncbytesdup(buf);
  570. ncbytesfree(buf);
  571. return result;
  572. }