1 /***************************************************************************
2                           dia2code.c  -  Global functions
3                              -------------------
4     begin                : Sat Dec 16 2000
5     copyright            : (C) 2000-2001 by Javier O'Hara
6     email                : joh314@users.sourceforge.net
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 #include "dia2code.h"
19 #include <errno.h>
20 
21 char * d2c_indentstring = "   ";
22 int d2c_indentposition = 0;
23 
24 int indentlevel = 0;
25 static int number_of_spaces_for_one_indentation = 2;
26 static int DBG_LEVEL = 4;
27 
dia2code_initializations()28 void dia2code_initializations()
29 {
30 }
31 
debug_setlevel(int newlevel)32 void debug_setlevel( int newlevel )
33 {
34     DBG_LEVEL = newlevel;
35 }
36 
37 /*
38  * a dummy logger / debugger function
39  */
debug(int level,char * fmt,...)40 void debug( int level, char *fmt, ... )
41 {
42     static char debug_buffer[HUGE_BUFFER];
43     va_list argptr;
44     //printf( "debug call\n" );
45     if( level != DBG_LEVEL )
46         return;
47     va_start(argptr, fmt);
48     vsprintf(debug_buffer, fmt, argptr);
49     va_end(argptr);
50     fprintf( stderr, "DBG %d: %s\n", level, debug_buffer );
51     fflush( stderr);
52     //printf( "END debug call\n" );
53 }
54 
55 /**
56  * This function returns the upper case char* of the one taken on input
57  * The char * received may be freed by the caller
58 */
strtoupper(char * s)59 char *strtoupper(char *s) {
60     char *tmp = strdup(s);
61     int i, n;
62     if (tmp == NULL) {
63         fprintf(stderr, "Out of memory\n");
64         exit(1);
65     }
66     n = strlen(tmp);
67     for (i = 0; i < n; i++) {
68         tmp[i] = toupper(tmp[i]);
69     }
70     return tmp;
71 }
72 
73 /**
74   * This function returns the lower case char* of the one taken on input
75   * The char * received may be freed by the caller
76 */
strtolower(char * s)77 char *strtolower(char *s) {
78     char *tmp = strdup(s);
79     int i, n;
80     if (tmp == NULL) {
81         fprintf(stderr, "Out of memory\n");
82         exit(1);
83     }
84     n = strlen(tmp);
85     for (i = 0; i < n; i++) {
86         tmp[i] = tolower(tmp[i]);
87     }
88     return tmp;
89 }
90 
91 /**
92   * This function returns the a char* that has the first
93   * character in upper case and the rest unchanged.
94   * The char * received may be freed by the caller
95 */
strtoupperfirst(char * s)96 char *strtoupperfirst(char *s) {
97     char *tmp = strdup(s);
98     int i, n;
99     if (tmp == NULL) {
100         fprintf(stderr, "Out of memory\n");
101         exit(1);
102     }
103     n = strlen(tmp);
104     tmp[0] = toupper(tmp[0]);
105     for (i = 1; i < n; i++) {
106         tmp[i] = tmp[i];
107     }
108     return tmp;
109 }
110 
111 
parse_class_names(const char * s)112 namelist parse_class_names(const char *s) {
113     char *cp, *token;
114     const char *delim = ",";
115     namelist list = NULL;
116 
117     cp = strdup(s);
118     if (cp == NULL) {
119         fprintf(stderr, "Out of memory\n");
120         exit(1);
121     }
122     token = strtok (cp, delim);
123     while ( token != NULL ) {
124         namenode *tmp = NEW (namenode);
125         if (tmp == NULL) {
126             fprintf(stderr, "Out of memory\n");
127             exit(1);
128         }
129         tmp->name = strdup(token);
130         if (tmp->name == NULL) {
131             fprintf(stderr, "Out of memory\n");
132             exit(1);
133         }
134         tmp->next = list;
135         list = tmp;
136         token = strtok (NULL, delim);
137     }
138     free(cp);
139     return list;
140 }
141 
parse_sql_options(const char * s)142 namelist parse_sql_options(const char *s) {
143   /* AI: same thing for now but it could change in the future */
144   return parse_class_names(s);
145 }
146 
is_present(namelist list,const char * name)147 int is_present(namelist list, const char *name) {
148     while (list != NULL) {
149         int len;
150         char* mask;
151         if ( ! strcmp(list->name, name) ) {
152             return 1;
153         }
154         len = strlen(list->name);
155         if (len >= 2 && len <= strlen(name)
156                 && (mask = strchr(list->name, '*')) != NULL
157                 && mask == strrchr(list->name, '*') ) {
158             len--;
159             if ( mask == list->name && ! strcmp(list->name+1, name+strlen(name)-len) ) {
160                 return 1;
161             }
162             if ( mask == list->name+len && ! strncmp(list->name, name, len) ) {
163                 return 1;
164             }
165         }
166         list = list->next;
167     }
168     return 0;
169 }
170 
my_malloc(size_t size)171 void * my_malloc( size_t size ) {
172     void * tmp;
173     tmp = malloc(size);
174     if (tmp == NULL) {
175         fprintf(stderr, "Out of memory\n");
176         exit(1);
177     }
178     /* safer zone */
179     memset (tmp, 0, size);
180     return tmp;
181 }
182 
183 
184 /*
185     Builds a package list from the hierarchy of parents of package.
186     The topmost package will be the first on the list and the initial
187     package will be the last.
188 */
make_package_list(umlpackage * package)189 umlpackagelist make_package_list(umlpackage * package){
190     umlpackagelist dummylist, tmplist=NULL;
191 
192     while ( package != NULL ){
193         dummylist = NEW (umlpackagenode);
194         dummylist->next = tmplist;
195         tmplist = dummylist;
196         tmplist->key = package;
197         package = package->parent;
198     }
199     return tmplist;
200 }
201 
copy_attributes(umlattrlist src)202 umlattrlist copy_attributes(umlattrlist src)
203 {
204     umlattrlist cpy = NULL, start = NULL;
205 
206     while (src != NULL)
207     {
208         umlattrlist tmp = NEW (umlattrnode);
209         tmp->key = src->key;
210         if (cpy == NULL) {
211             cpy = tmp;
212             start = tmp;
213         } else {
214             cpy->next = tmp;
215             cpy = tmp;
216         }
217         src = src->next;
218     }
219     if (cpy != NULL)
220         cpy->next = NULL;
221 
222     return start;
223 }
224 
225 
226 /**
227  * create a directory hierarchy for the package name
228  * batch.outdir is taken as root directory
229  * works with java-like package naming convention
230  * the directory path is stored in pkg->directory
231  * eg. org.foo.bar will create directory tree org/foo/bar
232  * @param the current batch
233  * @param the package pointer
234  * @return the full directory path eg. "<outdir>/org/foo/bar"
235  *
236  */
create_package_dir(const batch * batch,umlpackage * pkg)237 char *create_package_dir( const batch *batch, umlpackage *pkg )
238 {
239     char *fulldirname, *dirname, fulldirnamedup[BIG_BUFFER];
240     /* created directories permissions */
241     mode_t dir_mask = S_IRUSR | S_IWUSR | S_IXUSR |S_IRGRP | S_IXGRP;
242     if (pkg == NULL) {
243         return NULL;
244     }
245     if (batch->buildtree == 0 || pkg->name == NULL) {
246         pkg->directory = batch->outdir;
247     } else {
248         fulldirname = (char*)my_malloc(BIG_BUFFER);
249         sprintf(fulldirname, "%s", batch->outdir);
250         dirname = strdup(pkg->name);
251         dirname = strtok( dirname, "." );
252         while (dirname != NULL) {
253             sprintf( fulldirnamedup, "%s/%s", fulldirname, dirname );
254             sprintf( fulldirname, "%s", fulldirnamedup );
255             /* TODO : should create only if not existent */
256             mkdir( fulldirname, dir_mask );
257             dirname = strtok( NULL, "." );
258         }
259         /* set the package directory used later for source file creation */
260         pkg->directory = fulldirname;
261     }
262     return pkg->directory;
263 }
264 
set_number_of_spaces_for_one_indentation(int n)265 void set_number_of_spaces_for_one_indentation(int n)
266 {
267     number_of_spaces_for_one_indentation = n;
268 }
269 
spc()270 char *spc()
271 {
272    static char spcbuf[BIG_BUFFER];
273    int n_spaces = number_of_spaces_for_one_indentation * indentlevel;
274    if (n_spaces >= sizeof(spcbuf)) {
275        fprintf (stderr, "spc(): spaces buffer overflow\n");
276        exit (1);
277    }
278    memset (spcbuf, ' ', n_spaces);
279    spcbuf[n_spaces] = '\0';
280    return spcbuf;
281 }
282 
283 FILE *spec = NULL, *body = NULL;
284 
285 /* Auxiliary define for the emit/print functions  */
286 #define var_arg_to_str(first_arg) \
287     va_list vargu; \
288     char str[LARGE_BUFFER]; \
289     va_start (vargu, first_arg); \
290     vsnprintf (str, LARGE_BUFFER, first_arg, vargu); \
291     va_end (vargu)
292 
emit(char * msg,...)293 void emit (char *msg, ...)
294 {
295     var_arg_to_str (msg);
296     fputs (str, spec);
297 }
298 
ebody(char * msg,...)299 void ebody (char *msg, ...)
300 {
301     var_arg_to_str (msg);
302     if (body != NULL)
303         fputs (str, body);
304 }
305 
eboth(char * msg,...)306 void eboth (char *msg, ...)
307 {
308     var_arg_to_str (msg);
309     fputs (str, spec);
310     if (body != NULL)
311         fputs (str, body);
312 }
313 
314 
print(char * msg,...)315 void print (char *msg, ...)
316 {
317     var_arg_to_str (msg);
318     fprintf (spec, "%s%s", spc(), str);
319 }
320 
pbody(char * msg,...)321 void pbody (char *msg, ...)
322 {
323     var_arg_to_str (msg);
324     if (body != NULL)
325         fprintf (body, "%s%s", spc(), str);
326 }
327 
pboth(char * msg,...)328 void pboth (char *msg, ...)
329 {
330     var_arg_to_str (msg);
331     fprintf (spec, "%s%s", spc(), str);
332     if (body != NULL)
333         fprintf (body, "%s%s", spc(), str);
334 }
335 
336 char *file_ext = NULL;
337 char *body_file_ext = NULL;
338 
open_outfile(char * filename,batch * b)339 FILE * open_outfile (char *filename, batch *b)
340 {
341     static char outfilename[BIG_BUFFER];
342     FILE *o;
343     int tmpdirlgth, tmpfilelgth;
344 
345     if (b->outdir == NULL) {
346         b->outdir = ".";
347     }
348 
349     tmpdirlgth = strlen (b->outdir);
350     tmpfilelgth = strlen (filename);
351 
352     /* This prevents buffer overflows */
353     if (tmpfilelgth + tmpdirlgth > sizeof(outfilename) - 2) {
354         fprintf (stderr, "Sorry, name of file too long ...\n"
355                     "Try a smaller dir name\n");
356         exit (1);
357     }
358 
359     sprintf (outfilename, "%s/%s", b->outdir, filename);
360     o = fopen (outfilename, "r");
361     if (o != NULL && !b->clobber) {
362         fclose (o);
363         return NULL;
364     }
365     o = fopen (outfilename, "w");
366     if (o == NULL) {
367         fprintf (stderr, "Can't open file %s for writing\n", outfilename);
368         exit (1);
369     }
370     return o;
371 }
372 
373 
374 int
is_enum_stereo(char * stereo)375 is_enum_stereo (char *stereo)
376 {
377     return (!strcasecmp(stereo, "enum") ||
378             !strcasecmp (stereo, "enumeration") ||
379             !strcmp (stereo, "CORBAEnum"));
380 }
381 
382 int
is_struct_stereo(char * stereo)383 is_struct_stereo (char *stereo)
384 {
385     return (!strcasecmp(stereo, "struct") ||
386             !strcasecmp (stereo, "structure") ||
387             !strcmp (stereo, "CORBAStruct"));
388 }
389 
390 int
is_typedef_stereo(char * stereo)391 is_typedef_stereo (char *stereo)
392 {
393     return (!strcasecmp(stereo, "typedef") ||
394             !strcmp (stereo, "CORBATypedef"));
395 }
396 
397 int
is_const_stereo(char * stereo)398 is_const_stereo (char *stereo)
399 {
400     return (!strcasecmp(stereo, "const") ||
401             !strcasecmp (stereo, "constant") ||
402             !strcmp (stereo, "CORBAConstant"));
403 }
404 
405 /* Added by RK 2003-02-20
406    This should become part of the uml_class object. */
407 
408 struct endless_string_buf
409 {
410     char *buf;
411     struct endless_string_buf *next;
412 };
413 typedef struct endless_string_buf endless_string_buf;
414 
415 struct endless_string
416 {
417     endless_string_buf *start;
418     endless_string_buf *end;
419 };
420 typedef struct endless_string endless_string;
421 
dump_endless_string(FILE * f,endless_string * es)422 void dump_endless_string(FILE *f, endless_string *es)
423 {
424     endless_string_buf *esb = es->start;
425     while (esb != NULL)
426     {
427         fprintf(f, "%s", esb->buf); /* We do not d2c_fprintf the buffer, cause it's read in indented. */
428         esb = esb->next;
429     }
430 }
431 
new_endless_string()432 endless_string * new_endless_string()
433 {
434     endless_string *es = NEW (endless_string);
435     es->start = NULL;
436     es->end = NULL;
437     return es;
438 }
439 
destroy_endless_string(endless_string * es)440 void destroy_endless_string(endless_string * es)
441 {
442     endless_string_buf *esb = es->start;
443     endless_string_buf *esb_next;
444     while (esb != NULL)
445     {
446         if (esb->buf != NULL)
447             free(esb->buf);
448         esb_next = esb->next;
449         free(esb);
450         esb = esb_next;
451     }
452     free (es);
453 }
454 
append_endless_string(endless_string * es,char * s)455 void append_endless_string(endless_string * es, char *s)
456 {
457     endless_string_buf *esb = NEW (endless_string_buf);
458     esb->buf = strdup(s);
459     esb->next = NULL;
460     if (es->start == NULL)
461         es->start = esb;
462     if (es->end != NULL)
463         es->end->next = esb;
464     es->end = esb;
465 }
466 
467 struct d2c_impl{
468     char name[SMALL_BUFFER];
469     endless_string *impl;
470     int impl_len;
471     int in_source;
472     int in_class;
473     struct d2c_impl *next;
474 };
475 
476 typedef struct d2c_impl d2c_impl;
477 d2c_impl *d2c_impl_list = NULL;
478 
d2c_impl_list_destroy()479 void d2c_impl_list_destroy()
480 {
481     d2c_impl *p = d2c_impl_list;
482     while (p != NULL)
483     {
484         destroy_endless_string(p->impl);
485         d2c_impl_list = p;
486         p = p->next;
487         free(d2c_impl_list);
488     }
489     d2c_impl_list = NULL;
490 }
491 
d2c_impl_add(char * name)492 d2c_impl * d2c_impl_add(char *name)
493 {
494     d2c_impl *d2ci = NEW (d2c_impl);
495     strcpy(d2ci->name, name);
496     d2ci->impl = new_endless_string();
497     d2ci->impl_len = 0;
498     d2ci->in_source = 0;
499     d2ci->in_class = 0;
500     d2ci->next = d2c_impl_list;
501     d2c_impl_list = d2ci;
502 
503     return d2ci;
504 }
505 
d2c_impl_find(char * name)506 d2c_impl* d2c_impl_find(char *name)
507 {
508     d2c_impl *p = d2c_impl_list;
509     while (p != NULL)
510     {
511         if (strcmp(p->name, name) == 0)
512             return p;
513         p = p->next;
514     }
515     return NULL;
516 }
517 
d2c_impl_find_or_add(char * name)518 d2c_impl *d2c_impl_find_or_add(char *name)
519 {
520     d2c_impl *p = d2c_impl_find(name);
521     if (p == NULL)
522         p = d2c_impl_add(name);
523 
524     return p;
525 }
526 
527 #define IMPLEMENTATION "Implementation"
528 
d2c_impl_comment(FILE * f,char * nm,char * range,int preserve,char * comment_start,char * comment_end)529 void d2c_impl_comment(FILE *f, char *nm, char *range, int preserve, char *comment_start, char *comment_end)
530 {
531     d2c_fprintf(f, "%s ## %s %spreserve %s class %s %s\n",
532                    comment_start, IMPLEMENTATION, preserve?"":"no", range, nm, comment_end);
533 }
534 
535 #if defined (USE_DUMPIMPL)
d2c_dump_impl(FILE * f,char * section,char * name)536 void d2c_dump_impl(FILE *f, char *section, char *name)
537 {
538     char nm[LARGE_BUFFER];
539     d2c_impl *d2ci;
540 
541     sprintf(nm, "%s.%s", section, name);
542     d2ci = d2c_impl_find_or_add(nm);
543 
544     d2ci->in_class = 1;
545 
546     d2c_impl_comment(f, nm, "start", 1, "//", "");
547     dump_endless_string(f, d2ci->impl);
548     d2c_impl_comment(f, nm, "end", 1, "//", "");
549 }
550 #else
d2c_dump_impl(FILE * f,char * section,char * name)551 void d2c_dump_impl(FILE *f, char *section, char *name)
552 {
553 }
554 #endif
555 
d2c_deprecate_impl(FILE * f,char * comment_start,char * comment_end)556 void d2c_deprecate_impl(FILE *f, char *comment_start, char *comment_end)
557 {
558     d2c_impl *p = d2c_impl_list;
559     int cnt = 0;
560     endless_string_buf *esb;
561 
562     while (p != NULL)
563     {
564         if (p->in_class == 0 && p->in_source == 1)
565         {
566             fprintf(stderr, "Deprecating implementation %s\n", p->name);
567 
568             if (cnt == 0)
569             {
570                 d2c_fprintf(f, "\n%s WARNING: %s\n", comment_start, comment_end);
571                 d2c_fprintf(f, "%s The following code blocks will be deleted the next time code is generated. %s\n\n", comment_start, comment_end);
572             }
573             d2c_impl_comment(f, p->name, "start", 0, comment_start, comment_end);
574             esb = p->impl->start;
575             while (esb != NULL)
576             {
577                 /* We do not d2c_fprintf the buffer, cause it's read in indented. */
578                 fprintf(f, "// %s", esb->buf);
579                 esb = esb->next;
580             }
581 
582             d2c_impl_comment(f, p->name, "end", 0, comment_start, comment_end);
583             cnt++;
584         }
585         p = p->next;
586     }
587     if (cnt > 0)
588         fprintf(stderr, "Warning: %d implementation blocks have been deprecated; examime source files.\n", cnt);
589 }
590 
sscanfmt(int size)591 static char *sscanfmt(int size)
592 {
593     static char buf[10];
594     sprintf (buf, " %%%ds", size - 1);
595     return buf;
596 }
597 
d2c_parse_impl(FILE * f,char * cmt_start,char * cmt_end)598 void d2c_parse_impl(FILE *f, char *cmt_start, char *cmt_end)
599 {
600 #define IN_SOURCE 0
601 #define START_IMPL 1
602 #define IN_IMPL 2
603 #define END_IMPL 3
604 
605 #define STATE_WARNING(s) fprintf(stderr, "Warning: line %ld %s, state=%d, %p, %s\n", line, (s), state, d2ci, ((d2ci != NULL) ? d2ci->name : "<no section>"));
606 
607     char s[HUGE_BUFFER];
608     char s_comment[LARGE_BUFFER], s_dbl_hash[SMALL_BUFFER], s_implementation[BIG_BUFFER],
609          s_preserve[SMALL_BUFFER], s_marker[SMALL_BUFFER], s_class[LARGE_BUFFER], s_name[LARGE_BUFFER];
610     int state = IN_SOURCE;
611     int count;
612     d2c_impl *d2ci=NULL;
613     endless_string *es=NULL;
614     long line = 0;
615     int preserve=0;
616     char fmtbuf[SMALL_BUFFER];
617 
618     d2c_impl_list_destroy();
619 
620     while (fgets(s, HUGE_BUFFER - 1, f) != NULL)
621     {
622         line++;
623         if (state == START_IMPL) state = IN_IMPL;
624         if (state == END_IMPL) state = IN_SOURCE;
625 	fmtbuf[0] = '\0';
626 	strcat (fmtbuf, sscanfmt (sizeof(s_comment)));
627 	strcat (fmtbuf, sscanfmt (sizeof(s_dbl_hash)));
628 	strcat (fmtbuf, sscanfmt (sizeof(s_implementation)));
629 	strcat (fmtbuf, sscanfmt (sizeof(s_preserve)));
630 	strcat (fmtbuf, sscanfmt (sizeof(s_marker)));
631 	strcat (fmtbuf, sscanfmt (sizeof(s_class)));
632 	strcat (fmtbuf, sscanfmt (sizeof(s_name)));
633         count = sscanf(s, fmtbuf,
634                        s_comment, s_dbl_hash, s_implementation, s_preserve, s_marker, s_class, s_name);
635         if (count == 7 &&
636             (strncmp(s_comment, cmt_start, sizeof(s_comment)) == 0) &&
637             (strncmp(s_dbl_hash, "##", sizeof(s_dbl_hash)) == 0) &&
638             (strncmp(s_implementation, IMPLEMENTATION, sizeof(s_implementation)) == 0))
639         {
640             if (strncmp(s_marker, "start", sizeof(s_marker)) == 0)
641             {
642                 if (state != IN_SOURCE)
643                 {
644                     STATE_WARNING("found a nested implementation comment")
645                 }
646                 preserve = strcmp(s_preserve, "preserve") ? 0 : 1;
647                 state = START_IMPL;
648                 d2ci = d2c_impl_find_or_add(s_name);
649                 es = d2ci->impl;
650             }
651             else if (strncmp(s_marker, "end", sizeof(s_marker)) == 0)
652             {
653                 if (state != IN_IMPL)
654                 {
655                     STATE_WARNING("found an end implemenataion comment without matching start")
656                 }
657                 if (d2ci && strcmp(d2ci->name, s_name) != 0)
658                 {
659                     STATE_WARNING("end implementation comment does not match start implementation comment")
660                 }
661                 state = END_IMPL;
662                 d2ci = NULL;
663                 es = NULL;
664             }
665             else
666             {
667                 STATE_WARNING("unrecognized state marker")
668             }
669         }
670 
671         if (state == IN_IMPL && preserve)
672         {
673             append_endless_string(es, s);
674             d2ci->in_source= 1;
675         }
676     }
677     if (state != IN_SOURCE && state != END_IMPL)
678         STATE_WARNING("found start implementation comment without end comment")
679 }
680 
681 /* This function takes a UML Operation and mangles it for implementation comments.
682    Because it uses an internal buffer to store and return, repeated calls to this
683    function will overwrite previous values.
684 */
d2c_operation_mangle_name(umloperation * ope)685 char *d2c_operation_mangle_name(umloperation *ope)
686 {
687     static char d2c_mangle_name[LARGE_BUFFER];
688     umlattrlist params = ope->parameters;
689     char *p;
690 
691     sprintf(d2c_mangle_name, "%s@%s@@", ope->attr.name, ope->attr.type);
692     while (params != NULL)
693     {
694         strcat(d2c_mangle_name, "@");
695         strcat(d2c_mangle_name, params->key.type);
696         params = params->next;
697     }
698 
699     /* Convert whitespace to underbars */
700     for (p = d2c_mangle_name; *p != '\0'; p++)
701     {
702         if (*p == ' ' || *p == '\t') *p = '_';
703     }
704     return d2c_mangle_name;
705 }
706 
d2c_backup(char * filename)707 int d2c_backup(char *filename)
708 {
709     /* This is not necessarily portable. (requires ability to just
710      * tag-on four more characters - not DOS-friendly)
711      * But I'll admit to being a bit out-of-the loop here.
712      */
713     char *backup_filename = my_malloc(strlen(filename) + 4);
714     strcpy(backup_filename, filename);
715     strcat(backup_filename, ".bak");
716 
717     if (generate_backup)
718     {
719         if (remove(backup_filename))
720         {
721             if (errno != ENOENT)
722             {
723                 fprintf(stderr, "Error %d while trying to delete file %s\n", errno, backup_filename);
724                 free(backup_filename);
725                 return -1;
726             }
727         }
728         if (rename(filename, backup_filename))
729         {
730             if (errno != ENOENT)
731             {
732                 fprintf(stderr, "Error %d while trying to rename %s to %s\n", errno, filename, backup_filename);
733                 free(backup_filename);
734                 return -1;
735             }
736         }
737     }
738     free(backup_filename);
739     return 0;
740 }
741 
742 /* Todo on auto-indentation:
743    1. Define meta-characters that are converted to braces
744 */
745 int indent_count = 4;
746 int indent_open_brace_on_newline = 1;
747 
748 
749 typedef struct
750 {
751     FILE *f;
752     int indentation;
753 } D2C_INDENT_STRUCT;
754 
755 D2C_INDENT_STRUCT d2c_files[32];
756 int d2c_num_files = 0;
757 
d2c_indent_offset(FILE * f)758 int d2c_indent_offset(FILE *f)
759 {
760     int i;
761     for (i = 0; i < d2c_num_files; i++)
762     {
763         if (d2c_files[i].f == f)
764         {
765             return i;
766         }
767     }
768     d2c_files[i].f = f;
769     d2c_files[i].indentation = 0;
770     d2c_num_files++;
771     return i;
772 }
773 
d2c_indent(FILE * f)774 void d2c_indent(FILE *f)
775 {
776     d2c_files[d2c_indent_offset(f)].indentation++;
777 }
778 
d2c_outdent(FILE * f)779 void d2c_outdent(FILE *f)
780 {
781     d2c_files[d2c_indent_offset(f)].indentation--;
782 }
783 
d2c_fprint_indent(FILE * f)784 int d2c_fprint_indent(FILE *f)
785 {
786     int i;
787     int indentation;
788 
789     indentation = d2c_files[d2c_indent_offset(f)].indentation;
790 
791     for (i = 0; i < indentation * indent_count; i++)
792         fputc(' ', f);
793     return i;
794 }
795 
796 char d2c_io_lchar = 0;
797 
_d2c_fputc(int c,FILE * f)798 int _d2c_fputc(int c, FILE *f)
799 {
800     int indent_cnt = 0;
801     int rc;
802 
803     if (d2c_io_lchar == '\n' && c != '\n')
804         indent_cnt = d2c_fprint_indent(f);
805     d2c_io_lchar = c;
806     rc = fputc(c, f);
807     if (rc == EOF)
808         return rc;
809     else
810         return indent_cnt + 1;
811 }
812 
_d2c_fputs(const char * s,FILE * f)813 int _d2c_fputs(const char *s, FILE *f)
814 {
815     const char *buf = s;
816     /* int len = 0; */
817     while (*buf != '\0')
818     {
819         if (fputc(*buf, f) == EOF)
820             return EOF;
821         /* len++; */
822         buf++;
823     }
824     return 1;
825 }
826 
827 
828 char d2c_fprintf_buf[HUGE_BUFFER * 2];
_d2c_fprintf(FILE * f,char * fmt,...)829 int _d2c_fprintf(FILE *f, char *fmt, ...)
830 {
831     va_list argptr;
832     int cnt;
833     int extern_cnt;
834     int i;
835 
836     va_start(argptr, fmt);
837     cnt = vsprintf(d2c_fprintf_buf, fmt, argptr);
838     va_end(argptr);
839 
840     extern_cnt = cnt;
841     if (cnt != EOF)
842     {
843         for (i = 0; i < cnt; i++)
844         {
845             extern_cnt += _d2c_fputc(d2c_fprintf_buf[i], f);
846         }
847     }
848     return extern_cnt;
849 }
850 
d2c_directprintf(FILE * f,char * fmt,...)851 int d2c_directprintf(FILE *f, char *fmt, ...)
852 {
853     va_list argptr;
854 
855     d2c_indentate(f);
856     va_start(argptr, fmt);
857     vfprintf(f, fmt, argptr);
858     va_end(argptr);
859     return 0;
860 }
861 
d2c_open_brace(FILE * f,char * suffix)862 void d2c_open_brace(FILE *f, char *suffix)
863 {
864     if (indent_open_brace_on_newline)
865     {
866         d2c_fputc('\n', f);
867     }
868     else
869     {
870         d2c_fputc(' ', f);
871     }
872     d2c_fprintf(f, "{%s\n", suffix);
873     d2c_indent(f);
874 }
875 
d2c_close_brace(FILE * f,char * suffix)876 void d2c_close_brace(FILE *f, char *suffix)
877 {
878     d2c_outdent(f);
879     d2c_fprintf(f, "}%s\n", suffix);
880 }
881 
882 param_list *d2c_parameters = NULL;
883 
param_list_destroy()884 void param_list_destroy()
885 {
886     param_list *p = d2c_parameters;
887     while (p != NULL)
888     {
889         free(p->name);
890         free(p->value);
891         d2c_parameters = p;
892         p = p->next;
893         free(d2c_parameters);
894     }
895     d2c_parameters = NULL;
896 }
897 
d2c_parameter_add(char * name,char * value)898 param_list * d2c_parameter_add(char *name, char *value)
899 {
900     param_list *entry = my_malloc (sizeof(d2c_parameters));
901     entry->name = strdup(name);
902     entry->value = value ? strdup(value) : NULL;
903     entry->next = d2c_parameters;
904     d2c_parameters = entry;
905 
906     return entry;
907 }
908 
d2c_parameter_set(char * name,char * value)909 param_list * d2c_parameter_set(char *name, char *value)
910 {
911     param_list *entry = d2c_parameter_find(name);
912     if (entry == NULL)
913         entry=d2c_parameter_add(name, value);
914     else
915     {
916         free(entry->value);
917         entry->value = value ? strdup(value) : NULL;
918     }
919 
920     return entry;
921 }
922 
d2c_parameter_value(char * name)923 char * d2c_parameter_value(char *name)
924 {
925     param_list *entry = d2c_parameter_find(name);
926     if (entry != NULL)
927         return entry->value;
928     return NULL;
929 }
930 
d2c_parameter_find(char * name)931 param_list *d2c_parameter_find(char *name)
932 {
933     param_list *p = d2c_parameters;
934     while (p != NULL)
935     {
936         if (strcmp(p->name, name) == 0)
937             return p;
938         p = p->next;
939     }
940     return NULL;
941 }
942 
943 
d2c_indentate(FILE * f)944 void d2c_indentate( FILE *f)
945 {
946     int i;
947     for ( i = 0; i < d2c_indentposition; i++) {
948         fputs( d2c_indentstring, f);
949     }
950 }
951 
952 
953 /*
954  * increment the tab position
955  * tab position is used in d2c_fprintf and alike
956  */
d2c_shift_code()957 void d2c_shift_code()
958 {
959     d2c_indentposition ++;
960 }
961 
962 
963 /*
964  * increment the tab position
965  * tab position is used in d2c_fprintf and alike
966  */
d2c_unshift_code()967 void d2c_unshift_code()
968 {
969     if( d2c_indentposition > 0 )
970         d2c_indentposition --;
971 }
972 
973 
974 
975 
976 /*
977 * find a diaoid token in a string
978 * the diaoid must be formatted as @diaoid <oid> where oid is a string without space
979 * @param the NULL terminated string buffer to look in
980 * @param (out) a pointer located on the first oid charater - NULL is allowed if you dont need this pointer
981 * @return the diaoid found or NULL if none is found
982 */
find_diaoid(const char * buf,char ** newpos)983 char *find_diaoid( const char *buf, char **newpos  )
984 {
985     static const char *oidtag = "@diaoid";
986     char *cp, *ep; // current pos, diaoid ending position
987     char *oidp=NULL;
988     debug( DBG_CORE, "find_diaoid()" );
989     if( buf == NULL ) {
990         return NULL;
991     }
992     cp = strstr( buf, oidtag );
993     if( cp == NULL )
994         return NULL;
995     cp += strlen(oidtag)+1;
996     /* get the oid */
997     ep = strpbrk( cp, " \t\n\r" );
998     if( ep == NULL ) {
999         oidp = strdup(cp);
1000     } else {
1001         oidp= (char*) strndup( cp, (size_t) ( ep-cp));
1002     }
1003     /* caller want the new position : we set it */
1004     if( newpos != NULL ) {
1005         (*newpos) = cp;
1006     }
1007     return oidp;
1008 }
1009 
1010 
1011