source: XIOS/dev/dev_cmip6_omp/extern/src_netcdf4/daputil.c @ 1606

Last change on this file since 1606 was 409, checked in by ymipsl, 11 years ago

Add improved nectdf internal library src

YM

  • Property svn:eol-style set to native
File size: 19.2 KB
Line 
1/*********************************************************************
2 *   Copyright 1993, UCAR/Unidata
3 *   See netcdf/COPYRIGHT file for copying and redistribution conditions.
4 *   $Header: /upc/share/CVS/netcdf-3/libncdap3/daputil.c,v 1.47 2010/05/21 23:24:15 dmh Exp $
5 *********************************************************************/
6
7#include "config.h"
8
9#include <sys/time.h>
10
11#include "oc.h"
12extern int oc_dumpnode(OClink, OCobject);
13
14#include "ncdap3.h"
15#include "dapalign.h"
16#include "dapodom.h"
17
18#define LBRACKET '['
19#define RBRACKET ']'
20
21
22/**************************************************/
23/**
24 * Provide a hidden interface to allow utilities
25 * to check if a given path name is really an ncdap3 url.
26 * If no, return null, else return basename of the url
27 * minus any extension.
28 */
29
30int
31nc__testurl(const char* path, char** basenamep)
32{
33    NC_URI* uri;
34    int ok = nc_uriparse(path,&uri);
35    if(ok) {
36        char* slash = strrchr(uri->file, '/');
37        char* dot;
38        if(slash == NULL) slash = (char*)path; else slash++;
39        slash = nulldup(slash);
40        dot = strrchr(slash, '.');
41        if(dot != NULL &&  dot != slash) *dot = '\0';
42        if(basenamep) *basenamep=slash ; else free(slash);
43        nc_urifree(uri);
44    }
45    return ok;
46}
47
48/**************************************************/
49
50/*
51Given a legal dap name with arbitrary characters,
52convert to equivalent legal cdf name
53With the new name policy for netcdf, this procedure
54does nothing.
55*/
56
57char*
58cdflegalname3(char* dapname)
59{
60    return nulldup(dapname);
61}
62
63/* Define the type conversion of the DAP variables
64   to the external netCDF variable type.
65   The proper way is to, for example, convert unsigned short
66   to an int to maintain the values.
67   Unfortuneately, libnc-dap does not do this:
68   it translates the types directly. For example
69   libnc-dap upgrades the DAP byte type, which is unsigned char,
70   to NC_BYTE, which signed char.
71   Oh well.
72   For netcdf-4, we can do proper type conversion.
73*/
74nc_type
75nctypeconvert(NCDAPCOMMON* drno, nc_type nctype)
76{
77    nc_type upgrade = NC_NAT;
78    if(drno->controls.flags & NCF_NC3) {
79        /* libnc-dap mimic invariant is to maintain type size */
80        switch (nctype) {
81        case NC_CHAR:    upgrade = NC_CHAR; break;
82        case NC_BYTE:    upgrade = NC_BYTE; break;
83        case NC_UBYTE:   upgrade = NC_BYTE; break;
84        case NC_SHORT:   upgrade = NC_SHORT; break;
85        case NC_USHORT:  upgrade = NC_SHORT; break;
86        case NC_INT:     upgrade = NC_INT; break;
87        case NC_UINT:    upgrade = NC_INT; break;
88        case NC_INT64:   upgrade = NC_INT64; break;
89        case NC_UINT64:  upgrade = NC_UINT64; break;
90        case NC_FLOAT:   upgrade = NC_FLOAT; break;
91        case NC_DOUBLE:  upgrade = NC_DOUBLE; break;
92        case NC_URL:
93        case NC_STRING:  upgrade = NC_CHAR; break;
94        default: break;
95        }
96    } else if(drno->controls.flags & NCF_NC4) {
97        /* netcdf-4 conversion is more correct */
98        switch (nctype) {
99        case NC_CHAR:    upgrade = NC_CHAR; break;
100        case NC_BYTE:    upgrade = NC_BYTE; break;
101        case NC_UBYTE:   upgrade = NC_UBYTE; break;
102        case NC_SHORT:   upgrade = NC_SHORT; break;
103        case NC_USHORT:  upgrade = NC_USHORT; break;
104        case NC_INT:     upgrade = NC_INT; break;
105        case NC_UINT:    upgrade = NC_UINT; break;
106        case NC_INT64:   upgrade = NC_INT64; break;
107        case NC_UINT64:  upgrade = NC_UINT64; break;
108        case NC_FLOAT:   upgrade = NC_FLOAT; break;
109        case NC_DOUBLE:  upgrade = NC_DOUBLE; break;
110        case NC_URL:
111        case NC_STRING:  upgrade = NC_STRING; break;
112        default: break;
113        }
114    }
115    return upgrade;
116}
117
118nc_type
119octypetonc(OCtype etype)
120{
121    switch (etype) {
122    case OC_Char:       return NC_CHAR;
123    case OC_Byte:       return NC_UBYTE;
124    case OC_UByte:      return NC_UBYTE;
125    case OC_Int16:      return NC_SHORT;
126    case OC_UInt16:     return NC_USHORT;
127    case OC_Int32:      return NC_INT;
128    case OC_UInt32:     return NC_UINT;
129    case OC_Int64:      return NC_INT64;
130    case OC_UInt64:     return NC_UINT64;
131    case OC_Float32:    return NC_FLOAT;
132    case OC_Float64:    return NC_DOUBLE;
133    case OC_String:     return NC_STRING;
134    case OC_URL:        return NC_STRING;
135    case OC_Dataset:    return NC_Dataset;
136    case OC_Sequence:   return NC_Sequence;
137    case OC_Structure:  return NC_Structure;
138    case OC_Grid:       return NC_Grid;
139    case OC_Dimension:  return NC_Dimension;
140    case OC_Primitive:  return NC_Primitive;
141    default: break;
142    }
143    return NC_NAT;
144}
145
146OCtype
147nctypetodap(nc_type nctype)
148{
149    switch (nctype) {
150    case NC_CHAR:       return OC_Char;
151    case NC_BYTE:       return OC_Byte;
152    case NC_UBYTE:      return OC_UByte;
153    case NC_SHORT:      return OC_Int16;
154    case NC_USHORT:     return OC_UInt16;
155    case NC_INT:        return OC_Int32;
156    case NC_UINT:       return OC_UInt32;
157    case NC_INT64:      return OC_Int64;
158    case NC_UINT64:     return OC_UInt64;
159    case NC_FLOAT:      return OC_Float32;
160    case NC_DOUBLE:     return OC_Float64;
161    case NC_STRING:     return OC_String;
162    default : break;
163    }
164    return OC_NAT;
165}
166
167size_t
168nctypesizeof(nc_type nctype)
169{
170    switch (nctype) {
171    case NC_CHAR:       return sizeof(char);
172    case NC_BYTE:       return sizeof(signed char);
173    case NC_UBYTE:      return sizeof(unsigned char);
174    case NC_SHORT:      return sizeof(short);
175    case NC_USHORT:     return sizeof(unsigned short);
176    case NC_INT:        return sizeof(int);
177    case NC_UINT:       return sizeof(unsigned int);
178    case NC_INT64:      return sizeof(long long);
179    case NC_UINT64:     return sizeof(unsigned long long);
180    case NC_FLOAT:      return sizeof(float);
181    case NC_DOUBLE:     return sizeof(double);
182    case NC_STRING:     return sizeof(char*);
183    default: PANIC("nctypesizeof");
184    }
185    return 0;
186}
187
188char*
189nctypetostring(nc_type nctype)
190{
191    switch (nctype) {
192    case NC_NAT:        return "NC_NAT";
193    case NC_BYTE:       return "NC_BYTE";
194    case NC_CHAR:       return "NC_CHAR";
195    case NC_SHORT:      return "NC_SHORT";
196    case NC_INT:        return "NC_INT";
197    case NC_FLOAT:      return "NC_FLOAT";
198    case NC_DOUBLE:     return "NC_DOUBLE";
199    case NC_UBYTE:      return "NC_UBYTE";
200    case NC_USHORT:     return "NC_USHORT";
201    case NC_UINT:       return "NC_UINT";
202    case NC_INT64:      return "NC_INT64";
203    case NC_UINT64:     return "NC_UINT64";
204    case NC_STRING:     return "NC_STRING";
205    case NC_VLEN:       return "NC_VLEN";
206    case NC_OPAQUE:     return "NC_OPAQUE";
207    case NC_ENUM:       return "NC_ENUM";
208    case NC_COMPOUND:   return "NC_COMPOUND";
209    case NC_URL:        return "NC_URL";
210    case NC_SET:        return "NC_SET";
211    case NC_Dataset:    return "NC_Dataset";
212    case NC_Sequence:   return "NC_Sequence";
213    case NC_Structure:  return "NC_Structure";
214    case NC_Grid:       return "NC_Grid";
215    case NC_Dimension:  return "NC_Dimension";
216    case NC_Primitive:  return "NC_Primitive";
217    default: break;
218    }
219    return NULL;
220}
221
222
223/* Pad a buffer */
224int
225alignbuffer3(NCbytes* buf, int alignment)
226{
227    int pad;
228    unsigned long len;
229    if(buf == NULL) return 0;
230    len = ncbyteslength(buf);
231    pad = nccpadding(len,alignment);
232
233#ifdef TEST
234    for(;pad > 0;pad--)
235        ncbytesappend(buf,0x3a); /* 0x3a was chosen at random */
236#else
237    ncbytessetlength(buf,len+pad);
238#endif
239    return 1;
240}
241
242size_t
243dimproduct3(NClist* dimensions)
244{
245    size_t size = 1;
246    unsigned int i;
247    if(dimensions == NULL) return size;
248    for(i=0;i<nclistlength(dimensions);i++) {
249        CDFnode* dim = (CDFnode*)nclistget(dimensions,i);
250        size *= dim->dim.declsize;
251    }
252    return size;
253}
254
255
256/* Return value of param or NULL if not found */
257const char*
258paramvalue34(NCDAPCOMMON* nccomm, const char* key)
259{
260    const char* value;
261
262    if(nccomm == NULL || key == NULL) return 0;
263    if(!nc_urilookup(nccomm->oc.url,key,&value))
264        return NULL;
265    return value;
266}
267
268static const char* checkseps = "+,:;";
269
270/* Search for substring in value of param. If substring == NULL; then just
271   check if param is defined.
272*/
273int
274paramcheck34(NCDAPCOMMON* nccomm, const char* key, const char* subkey)
275{
276    const char* value;
277    char* p;
278
279    if(nccomm == NULL || key == NULL) return 0;
280    if(!nc_urilookup(nccomm->oc.url,key,&value))
281        return 0;
282    if(subkey == NULL) return 1;
283    p = strstr(value,subkey);
284    if(p == NULL) return 0;
285    p += strlen(subkey);
286    if(*p != '\0' && strchr(checkseps,*p) == NULL) return 0;
287    return 1;
288}
289
290
291/* This is NOT UNION */ 
292int
293nclistconcat(NClist* l1, NClist* l2)
294{
295    unsigned int i;
296    for(i=0;i<nclistlength(l2);i++) nclistpush(l1,nclistget(l2,i));
297    return 1;
298}
299
300int
301nclistminus(NClist* l1, NClist* l2)
302{
303    unsigned int i,len,found;
304    len = nclistlength(l2);
305    found = 0;
306    for(i=0;i<len;i++) {
307        if(nclistdeleteall(l1,nclistget(l2,i))) found = 1;
308    }
309    return found;
310}
311
312int
313nclistdeleteall(NClist* l, ncelem elem)
314{
315    int i; /* do not make unsigned */
316    unsigned int len,found;
317    found = 0;
318    len = nclistlength(l);
319    for(i=len-1;i>=0;i--) {
320        ncelem test = nclistget(l,i);
321        if(test==elem) {
322            nclistremove(l,i);
323            found=1;
324        }
325    }
326    return found;   
327}
328
329/* Collect the set of container nodes ending in "container"*/
330void
331collectnodepath3(CDFnode* node, NClist* path, int withdataset)
332{
333    if(node == NULL) return;
334    nclistpush(path,(ncelem)node);
335    while(node->container != NULL) {
336        node = node->container;
337        if(!withdataset && node->nctype == NC_Dataset) break;
338        nclistinsert(path,0,(ncelem)node);
339    }
340}
341
342/* Like collectnodepath3, but in ocspace */
343void
344collectocpath(OCconnection conn, OCobject node, NClist* path)
345{
346    OCobject container;
347    OCtype octype;
348    if(node == OCNULL) return;
349    oc_inq_class(conn,node,&octype);
350    if(octype == OC_Dataset) return;
351    oc_inq_container(conn,node,&container);
352    if(container != OCNULL)
353        collectocpath(conn,container,path);
354    nclistpush(path,(ncelem)node);
355}
356
357char*
358makeocpathstring3(OCconnection conn, OCobject node, const char* sep)
359{
360    int slen,i,len,first,seplen;
361    char* pathname;
362    OCtype octype;
363    NClist* ocpath = nclistnew();
364
365    collectocpath(conn,node,ocpath);
366    len = nclistlength(ocpath);
367    assert(len > 0); /* dataset at least */
368
369    oc_inq_type(conn,node,&octype);
370    if(octype == OC_Dataset)
371        {pathname = nulldup(""); goto done;} /* Dataset */
372
373    seplen = strlen(sep);
374    for(slen=0,i=0;i<len;i++) {
375        OCobject node = (OCobject)nclistget(ocpath,i);
376        char* name;
377        oc_inq_type(conn,node,&octype);
378        if(octype == OC_Dataset) continue;
379        oc_inq_name(conn,node,&name);
380        slen += (name == NULL? 0 : strlen(name));
381        slen += seplen;
382        nullfree(name);
383    }
384    slen += 1;   /* for null terminator*/
385    pathname = (char*)malloc(slen);
386    MEMCHECK(pathname,NULL);
387    pathname[0] = '\0';   
388    for(first=1,i=0;i<len;i++) {
389        OCobject node = (OCobject)nclistget(ocpath,i);
390        char* name;
391        oc_inq_type(conn,node,&octype);
392        if(octype == OC_Dataset) continue;
393        oc_inq_name(conn,node,&name);
394        if(!first) strcat(pathname,sep);
395        if(name != NULL) strcat(pathname,name);
396        nullfree(name);
397        first = 0;
398    }
399done:
400    nclistfree(ocpath);
401    return pathname;
402}
403
404char*
405makepathstring3(NClist* path, const char* separator, int flags)
406{
407    int slen,i,len,first,seplen;
408    char* pathname;
409
410    len = nclistlength(path);
411    ASSERT(len > 0); /* dataset at least */
412    seplen = strlen(separator);
413    ASSERT(seplen > 0);
414    for(slen=0,i=0;i<len;i++) {
415        CDFnode* node = (CDFnode*)nclistget(path,i);
416        if(node->nctype == NC_Dataset) continue;
417        slen += strlen(node->ncbasename);
418        slen += seplen; 
419    }
420    slen += 1;   /* for null terminator*/
421    pathname = (char*)malloc(slen);
422    MEMCHECK(pathname,NULL);
423    pathname[0] = '\0';   
424    for(first=1,i=0;i<len;i++) {
425        CDFnode* node = (CDFnode*)nclistget(path,i);
426        char* name;
427        if(!node->elided || (flags & PATHELIDE)==0) {
428            if(node->nctype != NC_Dataset) {
429                name = node->ncbasename;
430                if(!first) strcat(pathname,separator);
431                strcat(pathname,name);
432                first = 0;
433            }
434        }
435    }
436    return pathname;
437}
438
439
440/* convert path to string using the ncname field */
441char*
442makecdfpathstring3(CDFnode* var, const char* separator)
443{
444    char* spath;
445    NClist* path = nclistnew();
446    collectnodepath3(var,path,WITHDATASET); /* <= note */
447    spath = makepathstring3(path,separator,PATHNC);
448    nclistfree(path);
449    return spath;
450}
451
452/* Collect the set names of container nodes ending in "container"*/
453void
454clonenodenamepath3(CDFnode* node, NClist* path, int withdataset)
455{
456    if(node == NULL) return;
457    /* stop at the dataset container as well*/
458    if(node->nctype != NC_Dataset)
459        clonenodenamepath3(node->container,path,withdataset);
460    if(node->nctype != NC_Dataset || withdataset)
461        nclistpush(path,(ncelem)nulldup(node->ncbasename));
462}
463
464char*
465simplepathstring3(NClist* names,  char* separator)
466{
467    int i;
468    size_t len;
469    char* result;
470    if(nclistlength(names) == 0) return nulldup("");
471    for(len=0,i=0;i<nclistlength(names);i++) {
472        char* name = (char*)nclistget(names,i);
473        len += strlen(name);
474        len += strlen(separator);
475    }
476    len++; /* null terminator */
477    result = (char*)malloc(len);
478    result[0] = '\0';
479    for(i=0;i<nclistlength(names);i++) {
480        char* segment = (char*)nclistget(names,i);
481        if(i > 0) strcat(result,separator);
482        strcat(result,segment);
483    }
484    return result;
485}
486
487/* Define a number of location tests */
488
489/* Is node contained (transitively) in a sequence ? */
490BOOL
491dapinsequence(CDFnode* node)
492{
493    if(node == NULL || node->container == NULL) return TRUE;
494    for(node=node->container;node->nctype != NC_Dataset;node=node->container) {
495       if(node->nctype == NC_Sequence) return TRUE;
496    }
497    return FALSE;
498}
499
500/* Is node a map field of a grid? */
501BOOL
502dapgridmap(CDFnode* node)
503{
504    if(node != NULL && node->container != NULL
505       && node->container->nctype == NC_Grid) {
506        CDFnode* array = (CDFnode*)nclistget(node->container->subnodes,0);
507        return (node != array);
508    }
509    return FALSE;
510}
511
512/* Is node an array field of a grid? */
513BOOL
514dapgridarray(CDFnode* node)
515{
516    if(node != NULL && node->container != NULL
517       && node->container->nctype == NC_Grid) {
518        CDFnode* array = (CDFnode*)nclistget(node->container->subnodes,0);
519        return (node == array);
520    }
521    return FALSE;
522}
523
524BOOL
525dapgridelement(CDFnode* node)
526{
527    return dapgridarray(node)
528           || dapgridmap(node);
529}
530
531/* Is node a top-level grid node? */
532BOOL
533daptopgrid(CDFnode* grid)
534{
535    if(grid == NULL || grid->nctype != NC_Grid) return FALSE;
536    return daptoplevel(grid);
537}
538
539/* Is node a top-level sequence node? */
540BOOL
541daptopseq(CDFnode* seq)
542{
543    if(seq == NULL || seq->nctype != NC_Sequence) return FALSE;
544    return daptoplevel(seq);
545}
546
547/* Is node a top-level node? */
548BOOL
549daptoplevel(CDFnode* node)
550{
551    if(node->container == NULL 
552       || node->container->nctype != NC_Dataset) return FALSE;
553    return TRUE;
554}
555
556unsigned int
557modeldecode(int translation, const char* smodel,
558            const struct NCTMODEL* models,
559            unsigned int dfalt)
560{
561    for(;models->translation;models++) {
562        if(translation != models->translation) continue;
563        if(smodel == models->model
564           || (models->model != NULL && strcasecmp(smodel,models->model)==0)) {
565            /* We have a match */
566            return models->flags;
567        }
568    }
569    return dfalt;
570}
571
572unsigned long
573getlimitnumber(const char* limit)
574{
575    size_t slen;
576    unsigned long multiplier = 1;
577    unsigned long lu;
578
579    if(limit == NULL) return 0;
580    slen = strlen(limit);
581    if(slen == 0) return 0;
582    switch (limit[slen-1]) {
583    case 'G': case 'g': multiplier = GIGBYTE; break;
584    case 'M': case 'm': multiplier = MEGBYTE; break;
585    case 'K': case 'k': multiplier = KILBYTE; break;
586    default: break;
587    }
588    sscanf(limit,"%lu",&lu);
589    return (lu*multiplier);
590}
591
592void
593dapexpandescapes(char *termstring)
594{
595    char *s, *t, *endp;
596   
597    /* expand "\" escapes, e.g. "\t" to tab character;
598       will only shorten string length, never increase it
599    */
600    s = termstring;
601    t = termstring;
602    while(*t) {
603        if (*t == '\\') {
604            t++;
605            switch (*t) {
606              case 'a':
607                *s++ = '\007'; t++; /* will use '\a' when STDC */
608                break;
609              case 'b':
610                *s++ = '\b'; t++;
611                break;
612              case 'f':
613                *s++ = '\f'; t++;
614                break;
615              case 'n':
616                *s++ = '\n'; t++;
617                break;
618              case 'r':
619                *s++ = '\r'; t++;
620                break;
621              case 't':
622                *s++ = '\t'; t++;
623                break;
624              case 'v':
625                *s++ = '\v'; t++;
626                break;
627              case '\\':
628                *s++ = '\\'; t++;
629                break;
630              case '?':
631                *s++ = '\177'; t++;
632                break;
633              case 'x':
634                t++; /* now t points to one or more hex digits */
635                *s++ = (char) strtol(t, &endp, 16);
636                t = endp;
637                break;
638              case '0':
639              case '1':
640              case '2':
641              case '3':
642              case '4':
643              case '5':
644              case '6':
645              case '7': {
646                /* t should now point to 3 octal digits */
647                int c;
648                c = t[0];
649                if(c == 0 || c < '0' || c > '7') goto normal;
650                c = t[1];
651                if(c == 0 || c < '0' || c > '7') goto normal;
652                c = t[2];
653                if(c == 0 || c < '0' || c > '7') goto normal;
654                c = ((t[0]-'0')<<6)+((t[1]-'0')<<3)+(t[2]-'0');
655                *s++ = (char)c;
656                t += 3;
657                } break;
658              default:
659                if(*t == 0)
660                    *s++ = '\\';
661                else
662                    *s++ = *t++;
663                break;
664            }
665        } else {
666normal:     *s++ = *t++;
667        }
668    }
669    *s = '\0';
670    return;
671}
672
673#ifdef HAVE_GETTIMEOFDAY
674static struct timeval time0;
675static struct timeval time1;
676
677static double
678deltatime()
679{
680    double t0, t1;
681    t0 = ((double)time0.tv_sec);
682    t0 += ((double)time0.tv_usec) / 1000000.0;
683    t1 = ((double)time1.tv_sec);
684    t1 += ((double)time1.tv_usec) / 1000000.0;
685    return (t1 - t0);
686}
687#endif
688
689/* Provide a wrapper for oc_fetch so we can log what it does */
690OCerror
691dap_fetch(NCDAPCOMMON* nccomm, OCconnection conn, const char* ce,
692             OCdxd dxd, OCobject* rootp)
693{
694    OCerror ocstat;
695    char* ext;
696    OCflags flags = 0;
697
698    if(dxd == OCDDS) ext = ".dds";
699    else if(dxd == OCDAS) ext = ".das";
700    else ext = ".dods";
701
702    if(ce != NULL && strlen(ce) == 0)
703        ce = NULL;
704
705    if(FLAGSET(nccomm->controls,NCF_UNCONSTRAINABLE)) {
706        ce = NULL;
707    }
708
709    if(FLAGSET(nccomm->controls,NCF_ONDISK)) {
710        flags |= OCONDISK;
711    }
712
713    if(SHOWFETCH) {
714        /* Build uri string minus the constraint */
715        char* baseurl = nc_uribuild(nccomm->oc.url,NULL,ext,0);
716        if(ce == NULL)
717            LOG1(NCLOGNOTE,"fetch: %s\n",baseurl);
718        else   
719            LOG2(NCLOGNOTE,"fetch: %s?%s\n",baseurl,ce);
720        nullfree(baseurl);
721#ifdef HAVE_GETTIMEOFDAY
722        gettimeofday(&time0,NULL);
723#endif
724    }
725    ocstat = oc_fetchf(conn,ce,dxd,flags,rootp);
726    if(FLAGSET(nccomm->controls,NCF_SHOWFETCH)) {
727#ifdef HAVE_GETTIMEOFDAY
728        double secs;
729        gettimeofday(&time1,NULL);
730        secs = deltatime();
731        nclog(NCLOGNOTE,"fetch complete: %0.3f secs",secs);
732#else
733        nclog(NCLOGNOTE,"fetch complete.");
734#endif
735    }
736#ifdef DEBUG2
737fprintf(stderr,"fetch: dds:\n");
738oc_dumpnode(conn,*rootp);
739#endif
740    return ocstat;
741}
742
743/* Check a name to see if it contains illegal dap characters
744*/
745
746static char* badchars = "./";
747
748
749int
750dap_badname(char* name)
751{
752    char* p;
753    if(name == NULL) return 0;
754    for(p=badchars;*p;p++) {
755        if(strchr(name,*p) != NULL) return 1;
756    }
757    return 0;
758}
759
760/* Check a name to see if it contains illegal dap characters
761   and repair them
762*/
763
764char*
765dap_repairname(char* name)
766{
767    char* newname;
768    char *p, *q; int c;
769
770    if(name == NULL) return NULL;
771    /* assume that dap_badname was called on this name and returned 1 */
772    newname = (char*)malloc(1+(3*strlen(name))); /* max needed */
773    newname[0] = '\0'; /* so we can use strcat */
774    for(p=name,q=newname;(c=*p);p++) {
775        if(strchr(badchars,c) != NULL) {
776            char newchar[8];
777            snprintf(newchar,sizeof(newchar),"%%%hhx",c);
778            strcat(newname,newchar);
779            q += 3; /*strlen(newchar)*/
780        } else
781            *q++ = c;
782        *q = '\0'; /* so we can always do strcat */
783    }
784    *q = '\0'; /* ensure trailing null */
785    return newname;
786}
Note: See TracBrowser for help on using the repository browser.