xref: /AOO41X/main/soltools/mkdepend/main.c (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /* $XConsortium: main.c,v 1.84 94/11/30 16:10:44 kaleb Exp $ */
2 /* $XFree86: xc/config/makedepend/main.c,v 3.4 1995/07/15 14:53:49 dawes Exp $ */
3 /*
4 
5 Copyright (c) 1993, 1994  X Consortium
6 
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
13 
14 The above copyright notice and this permission notice shall be included in
15 all copies or substantial portions of the Software.
16 
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
20 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 
24 Except as contained in this notice, the name of the X Consortium shall not be
25 used in advertising or otherwise to promote the sale, use or other dealings
26 in this Software without prior written authorization from the X Consortium.
27 
28 */
29 
30 #if defined(FREEBSD) || defined(MACOSX)
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #endif
34 
35 #ifdef _MSC_VER     /* Define ssize_t */
36 
37 #if !defined(_W64)
38 #if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
39 #define _W64 __w64
40 #else
41 #define _W64
42 #endif
43 #endif
44 
45 #ifdef  _WIN64
46 typedef __int64    ssize_t;
47 #else
48 typedef _W64 int   ssize_t;
49 #endif
50 
51 #endif
52 
53 #include "def.h"
54 #include <string.h>
55 #ifdef hpux
56 #define sigvec sigvector
57 #endif /* hpux */
58 
59 #ifdef X_POSIX_C_SOURCE
60 #define _POSIX_C_SOURCE X_POSIX_C_SOURCE
61 #include <signal.h>
62 #undef _POSIX_C_SOURCE
63 #else
64 #if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE)
65 #include <signal.h>
66 #else
67 #define _POSIX_SOURCE
68 #include <signal.h>
69 #undef _POSIX_SOURCE
70 #endif
71 #endif
72 
73 #include <stdarg.h>
74 
75 #ifdef MINIX
76 #define USE_CHMOD   1
77 #endif
78 
79 #ifdef DEBUG
80 int _debugmask;
81 #endif
82 
83 char *ProgramName;
84 
85 #define OBJSUFFIX ".obj"
86 #define INCLUDEDIR "."
87 
88 char    *directives[] = {
89     "if",
90     "ifdef",
91     "ifndef",
92     "else",
93     "endif",
94     "define",
95     "undef",
96     "include",
97     "line",
98     "pragma",
99     "error",
100     "ident",
101     "sccs",
102     "elif",
103     "eject",
104     NULL
105 };
106 
107 #define MAKEDEPEND
108 #include "imakemdep.h"  /* from config sources */
109 #undef MAKEDEPEND
110 
111 /*******   function declarations ********/
112 /*******   added by -Wall project *******/
113 void redirect(char * line, char * makefile );
114 
115 struct  inclist inclist[ MAXFILES ],
116         *inclistp = inclist;
117 
118 struct symhash *maininclist = NULL;
119 
120 char    *filelist[ MAXFILES ];
121 char    *includedirs[ MAXDIRS + 1 ];
122 char    *notdotdot[ MAXDIRS ];
123 char    *objprefix = "";
124 char    *objsuffix = OBJSUFFIX;
125 char    *startat = "# DO NOT DELETE";
126 int width = 78;
127 boolean append = FALSE;
128 boolean printed = FALSE;
129 boolean verbose = FALSE;
130 boolean show_where_not = FALSE;
131 boolean warn_multiple = FALSE;  /* Warn on multiple includes of same file */
132 
133 static
134 #ifdef SIGNALRETURNSINT
135 int
136 #else
137 void
138 #endif
catch(sig)139 catch (sig)
140     int sig;
141 {
142     fflush (stdout);
143     fatalerr ("got signal %d\n", sig);
144 }
145 
146 #if defined(USG) || (defined(i386) && defined(SYSV)) || defined(WIN32) || defined(OS2) || defined(Lynx_22)
147 #define USGISH
148 #endif
149 
150 #ifndef USGISH
151 #ifndef _POSIX_SOURCE
152 #define sigaction sigvec
153 #define sa_handler sv_handler
154 #define sa_mask sv_mask
155 #define sa_flags sv_flags
156 #endif
157 struct sigaction sig_act;
158 #endif /* USGISH */
159 
160 boolean native_win_slashes = FALSE;
161 
main(argc,argv)162 int main(argc, argv)
163     int argc;
164     char    **argv;
165 {
166     register char   **fp = filelist;
167     register char   **incp = includedirs;
168     register char   *p;
169     register struct inclist *ip;
170     char    *makefile = NULL;
171     struct filepointer  *filecontent;
172     struct pair *psymp = predefs;
173     char *endmarker = NULL;
174     char *defincdir = NULL;
175     struct IncludesCollection* incCollection;
176 
177     ProgramName = argv[0];
178 
179     while (psymp->p_name)
180     {
181         hash_define(psymp->p_name, psymp->p_value, &maininclist);
182         psymp++;
183     }
184     if (argc == 2 && argv[1][0] == '@') {
185         struct stat ast;
186         int afd;
187         char *args;
188         char **nargv;
189         int nargc;
190         char quotechar = '\0';
191 
192         nargc = 1;
193         if ((afd = open(argv[1]+1, O_RDONLY)) < 0)
194         fatalerr("cannot open \"%s\"\n", argv[1]+1);
195         fstat(afd, &ast);
196         args = (char *)malloc(ast.st_size + 1);
197         if ((ast.st_size = read(afd, args, (size_t) ast.st_size)) < 0)
198         fatalerr("failed to read %s\n", argv[1]+1);
199         args[ast.st_size] = '\0';
200         close(afd);
201         for (p = args; *p; p++) {
202         if (quotechar) {
203             if (quotechar == '\\' ||
204             (*p == quotechar && p[-1] != '\\'))
205             quotechar = '\0';
206             continue;
207         }
208         switch (*p) {
209         case '\\':
210         case '"':
211         case '\'':
212             quotechar = *p;
213             break;
214         case ' ':
215         case '\n':
216             *p = '\0';
217             if (p > args && p[-1])
218             nargc++;
219             break;
220         }
221         }
222         if (p[-1])
223         nargc++;
224         nargv = (char **)malloc(nargc * sizeof(char *));
225         nargv[0] = argv[0];
226         argc = 1;
227         for (p = args; argc < nargc; p += strlen(p) + 1)
228         if (*p) nargv[argc++] = p;
229         argv = nargv;
230     }
231     for(argc--, argv++; argc; argc--, argv++) {
232             /* if looking for endmarker then check before parsing */
233         if (endmarker && strcmp (endmarker, *argv) == 0) {
234             endmarker = NULL;
235             continue;
236         }
237         if (**argv != '-') {
238             /* treat +thing as an option for C++ */
239             if (endmarker && **argv == '+')
240                 continue;
241             *fp++ = argv[0];
242             continue;
243         }
244         switch(argv[0][1]) {
245         case '-':
246             endmarker = &argv[0][2];
247             if (endmarker[0] == '\0') endmarker = "--";
248             break;
249         case 'D':
250             if (argv[0][2] == '\0') {
251                 argv++;
252                 argc--;
253             }
254             for (p=argv[0] + 2; *p ; p++)
255                 if (*p == '=') {
256                     *p = ' ';
257                     break;
258                 }
259             define(argv[0] + 2, &maininclist);
260             break;
261         case 'I':
262             if (incp >= includedirs + MAXDIRS)
263                 fatalerr("Too many -I flags.\n");
264             *incp++ = argv[0]+2;
265             if (**(incp-1) == '\0') {
266                 *(incp-1) = *(++argv);
267                 argc--;
268             }
269             break;
270         case 'Y':
271             defincdir = argv[0]+2;
272             break;
273         /* do not use if endmarker processing */
274         case 'a':
275             if (endmarker) break;
276             append = TRUE;
277             break;
278         case 'w':
279             if (endmarker) break;
280             if (argv[0][2] == '\0') {
281                 argv++;
282                 argc--;
283                 width = atoi(argv[0]);
284             } else
285                 width = atoi(argv[0]+2);
286             break;
287         case 'n':
288             // Use "-n" switch to generate dependencies with windows-native slash style
289             native_win_slashes = TRUE;
290             break;
291         case 'o':
292             if (endmarker) break;
293             if (argv[0][2] == '\0') {
294                 argv++;
295                 argc--;
296                 objsuffix = argv[0];
297             } else
298                 objsuffix = argv[0]+2;
299             break;
300         case 'p':
301             if (endmarker) break;
302             if (argv[0][2] == '\0') {
303                 argv++;
304                 argc--;
305                 objprefix = argv[0];
306             } else
307                 objprefix = argv[0]+2;
308             break;
309         case 'v':
310             if (endmarker) break;
311             verbose = TRUE;
312 #ifdef DEBUG
313             if (argv[0][2])
314                 _debugmask = atoi(argv[0]+2);
315 #endif
316             break;
317         case 's':
318             if (endmarker) break;
319             startat = argv[0]+2;
320             if (*startat == '\0') {
321                 startat = *(++argv);
322                 argc--;
323             }
324             if (*startat != '#')
325                 fatalerr("-s flag's value should start %s\n",
326                     "with '#'.");
327             break;
328         case 'f':
329             if (endmarker) break;
330             makefile = argv[0]+2;
331             if (*makefile == '\0') {
332                 makefile = *(++argv);
333                 argc--;
334             }
335             break;
336 
337         case 'm':
338             warn_multiple = TRUE;
339             break;
340 
341         /* Ignore -O, -g so we can just pass ${CFLAGS} to
342            makedepend
343          */
344         case 'O':
345         case 'g':
346             break;
347         default:
348             if (endmarker) break;
349     /*      fatalerr("unknown opt = %s\n", argv[0]); */
350             warning("ignoring option %s\n", argv[0]);
351         }
352     }
353 
354     convert_slashes(objprefix);
355     objprefix = append_slash(objprefix);
356 
357     if (!defincdir) {
358 #ifdef PREINCDIR
359         if (incp >= includedirs + MAXDIRS)
360         fatalerr("Too many -I flags.\n");
361         *incp++ = PREINCDIR;
362 #endif
363         if (incp >= includedirs + MAXDIRS)
364         fatalerr("Too many -I flags.\n");
365         *incp++ = INCLUDEDIR;
366 #ifdef POSTINCDIR
367         if (incp >= includedirs + MAXDIRS)
368         fatalerr("Too many -I flags.\n");
369         *incp++ = POSTINCDIR;
370 #endif
371     } else if (*defincdir) {
372         if (incp >= includedirs + MAXDIRS)
373         fatalerr("Too many -I flags.\n");
374         *incp++ = defincdir;
375     }
376 
377     redirect(startat, makefile);
378 
379     /*
380      * catch signals.
381      */
382 #ifdef USGISH
383 /*  should really reset SIGINT to SIG_IGN if it was.  */
384 #ifdef SIGHUP
385     signal (SIGHUP, catch);
386 #endif
387     signal (SIGINT, catch);
388 #ifdef SIGQUIT
389     signal (SIGQUIT, catch);
390 #endif
391     signal (SIGILL, catch);
392 #ifdef SIGBUS
393     signal (SIGBUS, catch);
394 #endif
395     signal (SIGSEGV, catch);
396 #ifdef SIGSYS
397     signal (SIGSYS, catch);
398 #endif
399     signal (SIGFPE, catch);
400 #else
401     sig_act.sa_handler = catch;
402 #ifdef _POSIX_SOURCE
403     sigemptyset(&sig_act.sa_mask);
404     sigaddset(&sig_act.sa_mask, SIGINT);
405     sigaddset(&sig_act.sa_mask, SIGQUIT);
406 #ifdef SIGBUS
407     sigaddset(&sig_act.sa_mask, SIGBUS);
408 #endif
409     sigaddset(&sig_act.sa_mask, SIGILL);
410     sigaddset(&sig_act.sa_mask, SIGSEGV);
411     sigaddset(&sig_act.sa_mask, SIGHUP);
412     sigaddset(&sig_act.sa_mask, SIGPIPE);
413 #ifdef SIGSYS
414     sigaddset(&sig_act.sa_mask, SIGSYS);
415 #endif
416 #else
417     sig_act.sa_mask = ((1<<(SIGINT -1))
418                |(1<<(SIGQUIT-1))
419 #ifdef SIGBUS
420                |(1<<(SIGBUS-1))
421 #endif
422                |(1<<(SIGILL-1))
423                |(1<<(SIGSEGV-1))
424                |(1<<(SIGHUP-1))
425                |(1<<(SIGPIPE-1))
426 #ifdef SIGSYS
427                |(1<<(SIGSYS-1))
428 #endif
429                );
430 #endif /* _POSIX_SOURCE */
431     sig_act.sa_flags = 0;
432     sigaction(SIGHUP, &sig_act, (struct sigaction *)0);
433     sigaction(SIGINT, &sig_act, (struct sigaction *)0);
434     sigaction(SIGQUIT, &sig_act, (struct sigaction *)0);
435     sigaction(SIGILL, &sig_act, (struct sigaction *)0);
436 #ifdef SIGBUS
437     sigaction(SIGBUS, &sig_act, (struct sigaction *)0);
438 #endif
439     sigaction(SIGSEGV, &sig_act, (struct sigaction *)0);
440 #ifdef SIGSYS
441     sigaction(SIGSYS, &sig_act, (struct sigaction *)0);
442 #endif
443 #endif /* USGISH */
444 
445     /*
446      * now peruse through the list of files.
447      */
448     incCollection = create_IncludesCollection();
449 
450     for(fp=filelist; *fp; fp++) {
451         struct symhash *includes;
452         filecontent = getfile(*fp);
453         ip = newinclude(*fp, (char *)NULL);
454 
455         includes = hash_copy( maininclist );
456         find_includes(filecontent, ip, ip, 0, FALSE, incCollection, includes);
457         hash_free( includes );
458 
459         freefile(filecontent);
460         recursive_pr_include(ip, ip->i_file, base_name(*fp));
461         inc_clean();
462     }
463     if (printed)
464         printf("\n");
465 
466     delete_IncludesCollection(incCollection);
467 
468     exit(0);
469 }
470 
getfile(file)471 struct filepointer *getfile(file)
472     char    *file;
473 {
474     register int    fd;
475     struct filepointer  *content;
476     struct stat st;
477     off_t       size_backup;
478     ssize_t     bytes_read;
479     size_t      malloc_size;
480 
481     content = (struct filepointer *)malloc(sizeof(struct filepointer));
482     if ((fd = open(file, O_RDONLY)) < 0) {
483         warning("makedepend:  Cannot open file \"%s\"\n", file);
484         content->f_p = content->f_base = content->f_end = (char *)malloc(1);
485         *content->f_p = '\0';
486         return(content);
487     }
488     fstat(fd, &st);
489 
490     size_backup = st.st_size;
491     malloc_size = size_backup;
492     /* Since off_t is larger than size_t, need to test for
493      * truncation.
494      */
495     if ( (off_t)malloc_size != size_backup )
496     {
497         close( fd );
498         warning("makedepend:  File \"%s\" size larger than can fit in size_t.  Cannot allocate memory for contents.\n", file);
499         content->f_p = content->f_base = content->f_end = (char *)malloc(1);
500         *content->f_p = '\0';
501         return(content);
502     }
503 
504     content->f_base = (char *)malloc(malloc_size+1);
505     if (content->f_base == NULL)
506         fatalerr("makedepend:  Cannot allocate memory to process file \"%s\"\n", file);
507     if ((bytes_read = read(fd, content->f_base, malloc_size)) < 0)
508         if ( st.st_mode & S_IFREG )
509             fatalerr("makedepend:  Failed to read file \"%s\"\n", file);
510 
511     close(fd);
512     content->f_len = bytes_read+1;
513     content->f_p = content->f_base;
514     content->f_end = content->f_base + bytes_read;
515     *content->f_end = '\0';
516     content->f_line = 0;
517     return(content);
518 }
519 
freefile(fp)520 void freefile(fp)
521     struct filepointer  *fp;
522 {
523     free(fp->f_base);
524     free(fp);
525 }
526 
copy(str)527 char *copy(str)
528     register char   *str;
529 {
530     register char   *p = (char *)malloc(strlen(str) + 1);
531 
532     strcpy(p, str);
533     return(p);
534 }
535 
match(str,list)536 int match(str, list)
537     register char   *str, **list;
538 {
539     register int    i;
540 
541     for (i=0; *list; i++, list++)
542         if (strcmp(str, *list) == 0)
543             return(i);
544     return(-1);
545 }
546 
547 /*
548  * Get the next line.  We only return lines beginning with '#' since that
549  * is all this program is ever interested in.
550  */
get_line(filep)551 char *get_line(filep)
552     register struct filepointer *filep;
553 {
554     register char   *p, /* walking pointer */
555             *eof,   /* end of file pointer */
556             *bol;   /* beginning of line pointer */
557     register int    lineno; /* line number */
558 
559     p = filep->f_p;
560     eof = filep->f_end;
561     if (p >= eof)
562         return((char *)NULL);
563     lineno = filep->f_line;
564 
565     for(bol = p--; ++p < eof; ) {
566         if (*p == '/' && *(p+1) == '*') { /* consume comments */
567             *p++ = ' ', *p++ = ' ';
568             while (*p) {
569                 if (*p == '*' && *(p+1) == '/') {
570                     *p++ = ' ', *p = ' ';
571                     break;
572                 }
573                 else if (*p == '\n')
574                     lineno++;
575                 *p++ = ' ';
576             }
577             continue;
578         }
579         else if (*p == '/' && *(p+1) == '/') { /* consume comments */
580             *p++ = ' ', *p++ = ' ';
581             while (*p && *p != '\n')
582                 *p++ = ' ';
583             if ( *p == '\n' )
584                 p--;
585             lineno++;
586             continue;
587         }
588         else if (*p == '\\') {
589             if (*(p+1) == '\n') {
590                 *p = ' ';
591                 *(p+1) = ' ';
592                 lineno++;
593             }
594         }
595         else if (*p == '\n') {
596             lineno++;
597             if (*bol == '#') {
598                 register char *cp;
599 
600                 *p++ = '\0';
601                 /* punt lines with just # (yacc generated) */
602                 for (cp = bol+1;
603                      *cp && (*cp == ' ' || *cp == '\t'); cp++);
604                 if (*cp) goto done;
605             }
606             bol = p+1;
607         }
608     }
609     if (*bol != '#')
610         bol = NULL;
611 done:
612     filep->f_p = p;
613     filep->f_line = lineno;
614     return(bol);
615 }
616 
617 /*
618  * Strip the file name down to what we want to see in the Makefile.
619  * It will have objprefix and objsuffix around it.
620  */
base_name(file)621 char *base_name(file)
622     register char   *file;
623 {
624     register char   *p;
625 
626     file = copy(file);
627     for(p=file+strlen(file); p>file && *p != '.'; p--) ;
628 
629     if (*p == '.')
630         *p = '\0';
631 
632     while (p > file) {
633         if ( *p == '/' ||  *p == '\\') {
634             file = p + 1;
635             break;
636         };
637         p--;
638     };
639     return(file);
640 }
641 
642 #if defined(USG) && !defined(CRAY) && !defined(SVR4)
rename(from,to)643 int rename (from, to)
644     char *from, *to;
645 {
646     (void) unlink (to);
647     if (link (from, to) == 0) {
648     unlink (from);
649     return 0;
650     } else {
651     return -1;
652     }
653 }
654 #endif /* USGISH */
655 
redirect(line,makefile)656 void redirect(line, makefile)
657     char    *line,
658         *makefile;
659 {
660     struct stat st;
661     FILE    *fdin, *fdout;
662     char    backup[ BUFSIZ ],
663         buf[ BUFSIZ ];
664     boolean found = FALSE;
665     int len;
666 
667     /*
668      * if makefile is "-" then let it pour onto stdout.
669      */
670     if (makefile && *makefile == '-' && *(makefile+1) == '\0')
671         return;
672 
673     /*
674      * use a default makefile is not specified.
675      */
676     if (!makefile) {
677         if (stat("Makefile", &st) == 0)
678             makefile = "Makefile";
679         else if (stat("makefile", &st) == 0)
680             makefile = "makefile";
681         else
682             fatalerr("[mM]akefile is not present\n");
683     }
684     else
685         stat(makefile, &st);
686     if ((fdin = fopen(makefile, "r")) == NULL)
687         fatalerr("cannot open \"%s\"\n", makefile);
688     sprintf(backup, "%s.bak", makefile);
689     unlink(backup);
690 #if defined(WIN32) || defined(OS2)
691     fclose(fdin);
692 #endif
693     if (rename(makefile, backup) < 0)
694         fatalerr("cannot rename %s to %s\n", makefile, backup);
695 #if defined(WIN32) || defined(OS2)
696     if ((fdin = fopen(backup, "r")) == NULL)
697         fatalerr("cannot open \"%s\"\n", backup);
698 #endif
699     if ((fdout = freopen(makefile, "w", stdout)) == NULL)
700         fatalerr("cannot open \"%s\"\n", backup);
701     len = strlen(line);
702     while (!found && fgets(buf, BUFSIZ, fdin)) {
703         if (*buf == '#' && strncmp(line, buf, len) == 0)
704             found = TRUE;
705         fputs(buf, fdout);
706     }
707     if (!found) {
708         if (verbose)
709         warning("Adding new delimiting line \"%s\" and dependencies...\n",
710             line);
711         puts(line); /* same as fputs(fdout); but with newline */
712     } else if (append) {
713         while (fgets(buf, BUFSIZ, fdin)) {
714         fputs(buf, fdout);
715         }
716     }
717     fflush(fdout);
718 #if defined(USGISH) || defined(_SEQUENT_) || defined(USE_CHMOD)
719     chmod(makefile, st.st_mode);
720 #else
721     fchmod(fileno(fdout), st.st_mode);
722 #endif /* USGISH */
723     fclose(fdin);
724 }
725 
fatalerr(char * msg,...)726 void fatalerr(char *msg, ...)
727 {
728     va_list args;
729     fprintf(stderr, "%s: error:  ", ProgramName);
730     va_start(args, msg);
731     vfprintf(stderr, msg, args);
732     va_end(args);
733     exit (1);
734 }
735 
warning(char * msg,...)736 void warning(char *msg, ...)
737 {
738 #ifdef DEBUG_MKDEPEND
739     va_list args;
740     fprintf(stderr, "%s: warning:  ", ProgramName);
741     va_start(args, msg);
742     vfprintf(stderr, msg, args);
743     va_end(args);
744 #else
745     (void)msg;
746 #endif /* DEBUG_MKDEPEND */
747 }
748 
warning1(char * msg,...)749 void warning1(char *msg, ...)
750 {
751 #ifdef DEBUG_MKDEPEND
752     va_list args;
753     va_start(args, msg);
754     vfprintf(stderr, msg, args);
755     va_end(args);
756 #else
757     (void)msg;
758 #endif /* DEBUG_MKDEPEND */
759 }
760 
convert_slashes(path)761 void convert_slashes(path)
762     char* path;
763 {
764 #if defined (WNT) || defined(OS2)
765     /*
766      * Convert backslashes to slashes
767      */
768     char *ptr;
769     if (native_win_slashes) {
770         for (ptr = (char*)path; *ptr; ++ptr)
771             if (*ptr == '/')
772                 *ptr = '\\';
773     } else {
774         for (ptr = (char*)path; *ptr; ++ptr)
775             if (*ptr == '\\')
776                 *ptr = '/';
777     };
778 #else
779     (void)path;
780 #endif
781 }
782 
append_slash(path)783 char* append_slash(path)
784     char* path;
785 {
786     char *new_string;
787     if ((path[strlen(path) - 1] == '/') || (path[strlen(path) - 1] == '\\')) {
788         new_string = path;
789     } else {
790         new_string = (char*)malloc(sizeof(char) * (strlen(path) + 2));
791         strcpy(new_string, path);
792         if (native_win_slashes)
793             strcat(new_string, "\\");
794         else
795             strcat(new_string, "/");
796     };
797     return new_string;
798 }
799 
800