xref: /AOO41X/main/soltools/mkdepend/main.c (revision c04e8dea6dace76db38280a41258735c125f5e20)
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     abort();
144     fatalerr ("got signal %d\n", sig);
145 }
146 
147 #if defined(USG) || (defined(i386) && defined(SYSV)) || defined(WIN32) || defined(OS2) || defined(Lynx_22)
148 #define USGISH
149 #endif
150 
151 #ifndef USGISH
152 #ifndef _POSIX_SOURCE
153 #define sigaction sigvec
154 #define sa_handler sv_handler
155 #define sa_mask sv_mask
156 #define sa_flags sv_flags
157 #endif
158 struct sigaction sig_act;
159 #endif /* USGISH */
160 
161 boolean native_win_slashes = FALSE;
162 
main(argc,argv)163 int main(argc, argv)
164     int argc;
165     char    **argv;
166 {
167     register char   **fp = filelist;
168     register char   **incp = includedirs;
169     register char   *p;
170     register struct inclist *ip;
171     char    *makefile = NULL;
172     struct filepointer  *filecontent;
173     struct pair *psymp = predefs;
174     char *endmarker = NULL;
175     char *defincdir = NULL;
176     struct IncludesCollection* incCollection;
177 
178     ProgramName = argv[0];
179 
180     while (psymp->p_name)
181     {
182         hash_define(psymp->p_name, psymp->p_value, &maininclist);
183         psymp++;
184     }
185     if (argc == 2 && argv[1][0] == '@') {
186         struct stat ast;
187         int afd;
188         char *args;
189         char **nargv;
190         int nargc;
191         char quotechar = '\0';
192 
193         nargc = 1;
194         if ((afd = open(argv[1]+1, O_RDONLY)) < 0)
195         fatalerr("cannot open \"%s\"\n", argv[1]+1);
196         fstat(afd, &ast);
197         args = (char *)malloc(ast.st_size + 1);
198         if ((ast.st_size = read(afd, args, (size_t) ast.st_size)) < 0)
199         fatalerr("failed to read %s\n", argv[1]+1);
200         args[ast.st_size] = '\0';
201         close(afd);
202         for (p = args; *p; p++) {
203         if (quotechar) {
204             if (quotechar == '\\' ||
205             (*p == quotechar && p[-1] != '\\'))
206             quotechar = '\0';
207             continue;
208         }
209         switch (*p) {
210         case '\\':
211         case '"':
212         case '\'':
213             quotechar = *p;
214             break;
215         case ' ':
216         case '\n':
217             *p = '\0';
218             if (p > args && p[-1])
219             nargc++;
220             break;
221         }
222         }
223         if (p[-1])
224         nargc++;
225         nargv = (char **)malloc(nargc * sizeof(char *));
226         nargv[0] = argv[0];
227         argc = 1;
228         for (p = args; argc < nargc; p += strlen(p) + 1)
229         if (*p) nargv[argc++] = p;
230         argv = nargv;
231     }
232     for(argc--, argv++; argc; argc--, argv++) {
233             /* if looking for endmarker then check before parsing */
234         if (endmarker && strcmp (endmarker, *argv) == 0) {
235             endmarker = NULL;
236             continue;
237         }
238         if (**argv != '-') {
239             /* treat +thing as an option for C++ */
240             if (endmarker && **argv == '+')
241                 continue;
242             *fp++ = argv[0];
243             continue;
244         }
245         switch(argv[0][1]) {
246         case '-':
247             endmarker = &argv[0][2];
248             if (endmarker[0] == '\0') endmarker = "--";
249             break;
250         case 'D':
251             if (argv[0][2] == '\0') {
252                 argv++;
253                 argc--;
254             }
255             for (p=argv[0] + 2; *p ; p++)
256                 if (*p == '=') {
257                     *p = ' ';
258                     break;
259                 }
260             define(argv[0] + 2, &maininclist);
261             break;
262         case 'I':
263             if (incp >= includedirs + MAXDIRS)
264                 fatalerr("Too many -I flags.\n");
265             *incp++ = argv[0]+2;
266             if (**(incp-1) == '\0') {
267                 *(incp-1) = *(++argv);
268                 argc--;
269             }
270             break;
271         case 'Y':
272             defincdir = argv[0]+2;
273             break;
274         /* do not use if endmarker processing */
275         case 'a':
276             if (endmarker) break;
277             append = TRUE;
278             break;
279         case 'w':
280             if (endmarker) break;
281             if (argv[0][2] == '\0') {
282                 argv++;
283                 argc--;
284                 width = atoi(argv[0]);
285             } else
286                 width = atoi(argv[0]+2);
287             break;
288         case 'n':
289             // Use "-n" switch to generate dependencies with windows-native slash style
290             native_win_slashes = TRUE;
291             break;
292         case 'o':
293             if (endmarker) break;
294             if (argv[0][2] == '\0') {
295                 argv++;
296                 argc--;
297                 objsuffix = argv[0];
298             } else
299                 objsuffix = argv[0]+2;
300             break;
301         case 'p':
302             if (endmarker) break;
303             if (argv[0][2] == '\0') {
304                 argv++;
305                 argc--;
306                 objprefix = argv[0];
307             } else
308                 objprefix = argv[0]+2;
309             break;
310         case 'v':
311             if (endmarker) break;
312             verbose = TRUE;
313 #ifdef DEBUG
314             if (argv[0][2])
315                 _debugmask = atoi(argv[0]+2);
316 #endif
317             break;
318         case 's':
319             if (endmarker) break;
320             startat = argv[0]+2;
321             if (*startat == '\0') {
322                 startat = *(++argv);
323                 argc--;
324             }
325             if (*startat != '#')
326                 fatalerr("-s flag's value should start %s\n",
327                     "with '#'.");
328             break;
329         case 'f':
330             if (endmarker) break;
331             makefile = argv[0]+2;
332             if (*makefile == '\0') {
333                 makefile = *(++argv);
334                 argc--;
335             }
336             break;
337 
338         case 'm':
339             warn_multiple = TRUE;
340             break;
341 
342         /* Ignore -O, -g so we can just pass ${CFLAGS} to
343            makedepend
344          */
345         case 'O':
346         case 'g':
347             break;
348         default:
349             if (endmarker) break;
350     /*      fatalerr("unknown opt = %s\n", argv[0]); */
351             warning("ignoring option %s\n", argv[0]);
352         }
353     }
354 
355     convert_slashes(objprefix);
356     objprefix = append_slash(objprefix);
357 
358     if (!defincdir) {
359 #ifdef PREINCDIR
360         if (incp >= includedirs + MAXDIRS)
361         fatalerr("Too many -I flags.\n");
362         *incp++ = PREINCDIR;
363 #endif
364         if (incp >= includedirs + MAXDIRS)
365         fatalerr("Too many -I flags.\n");
366         *incp++ = INCLUDEDIR;
367 #ifdef POSTINCDIR
368         if (incp >= includedirs + MAXDIRS)
369         fatalerr("Too many -I flags.\n");
370         *incp++ = POSTINCDIR;
371 #endif
372     } else if (*defincdir) {
373         if (incp >= includedirs + MAXDIRS)
374         fatalerr("Too many -I flags.\n");
375         *incp++ = defincdir;
376     }
377 
378     redirect(startat, makefile);
379 
380     /*
381      * catch signals.
382      */
383 #ifdef USGISH
384 /*  should really reset SIGINT to SIG_IGN if it was.  */
385 #ifdef SIGHUP
386     signal (SIGHUP, catch);
387 #endif
388     signal (SIGINT, catch);
389 #ifdef SIGQUIT
390     signal (SIGQUIT, catch);
391 #endif
392     signal (SIGILL, catch);
393 #ifdef SIGBUS
394     signal (SIGBUS, catch);
395 #endif
396     signal (SIGSEGV, catch);
397 #ifdef SIGSYS
398     signal (SIGSYS, catch);
399 #endif
400     signal (SIGFPE, catch);
401 #else
402     sig_act.sa_handler = catch;
403 #ifdef _POSIX_SOURCE
404     sigemptyset(&sig_act.sa_mask);
405     sigaddset(&sig_act.sa_mask, SIGINT);
406     sigaddset(&sig_act.sa_mask, SIGQUIT);
407 #ifdef SIGBUS
408     sigaddset(&sig_act.sa_mask, SIGBUS);
409 #endif
410     sigaddset(&sig_act.sa_mask, SIGILL);
411     sigaddset(&sig_act.sa_mask, SIGSEGV);
412     sigaddset(&sig_act.sa_mask, SIGHUP);
413     sigaddset(&sig_act.sa_mask, SIGPIPE);
414 #ifdef SIGSYS
415     sigaddset(&sig_act.sa_mask, SIGSYS);
416 #endif
417 #else
418     sig_act.sa_mask = ((1<<(SIGINT -1))
419                |(1<<(SIGQUIT-1))
420 #ifdef SIGBUS
421                |(1<<(SIGBUS-1))
422 #endif
423                |(1<<(SIGILL-1))
424                |(1<<(SIGSEGV-1))
425                |(1<<(SIGHUP-1))
426                |(1<<(SIGPIPE-1))
427 #ifdef SIGSYS
428                |(1<<(SIGSYS-1))
429 #endif
430                );
431 #endif /* _POSIX_SOURCE */
432     sig_act.sa_flags = 0;
433     sigaction(SIGHUP, &sig_act, (struct sigaction *)0);
434     sigaction(SIGINT, &sig_act, (struct sigaction *)0);
435     sigaction(SIGQUIT, &sig_act, (struct sigaction *)0);
436     sigaction(SIGILL, &sig_act, (struct sigaction *)0);
437 #ifdef SIGBUS
438     sigaction(SIGBUS, &sig_act, (struct sigaction *)0);
439 #endif
440     sigaction(SIGSEGV, &sig_act, (struct sigaction *)0);
441 #ifdef SIGSYS
442     sigaction(SIGSYS, &sig_act, (struct sigaction *)0);
443 #endif
444 #endif /* USGISH */
445 
446     /*
447      * now peruse through the list of files.
448      */
449     incCollection = create_IncludesCollection();
450 
451     for(fp=filelist; *fp; fp++) {
452         struct symhash *includes;
453         filecontent = getfile(*fp);
454         ip = newinclude(*fp, (char *)NULL);
455 
456         includes = hash_copy( maininclist );
457         find_includes(filecontent, ip, ip, 0, FALSE, incCollection, includes);
458         hash_free( includes );
459 
460         freefile(filecontent);
461         recursive_pr_include(ip, ip->i_file, base_name(*fp));
462         inc_clean();
463     }
464     if (printed)
465         printf("\n");
466 
467     delete_IncludesCollection(incCollection);
468 
469     exit(0);
470 }
471 
getfile(file)472 struct filepointer *getfile(file)
473     char    *file;
474 {
475     register int    fd;
476     struct filepointer  *content;
477     struct stat st;
478     off_t       size_backup;
479     ssize_t     bytes_read;
480     size_t      malloc_size;
481 
482     content = (struct filepointer *)malloc(sizeof(struct filepointer));
483     if ((fd = open(file, O_RDONLY)) < 0) {
484         warning("makedepend:  Cannot open file \"%s\"\n", file);
485         content->f_p = content->f_base = content->f_end = (char *)malloc(1);
486         *content->f_p = '\0';
487         return(content);
488     }
489     fstat(fd, &st);
490 
491     size_backup = st.st_size;
492     malloc_size = size_backup;
493     /* Since off_t is larger than size_t, need to test for
494      * truncation.
495      */
496     if ( (off_t)malloc_size != size_backup )
497     {
498         close( fd );
499         warning("makedepend:  File \"%s\" size larger than can fit in size_t.  Cannot allocate memory for contents.\n", file);
500         content->f_p = content->f_base = content->f_end = (char *)malloc(1);
501         *content->f_p = '\0';
502         return(content);
503     }
504 
505     content->f_base = (char *)malloc(malloc_size+1);
506     if (content->f_base == NULL)
507         fatalerr("makedepend:  Cannot allocate memory to process file \"%s\"\n", file);
508     if ((bytes_read = read(fd, content->f_base, malloc_size)) < 0)
509         if ( st.st_mode & S_IFREG )
510             fatalerr("makedepend:  Failed to read file \"%s\"\n", file);
511 
512     close(fd);
513     content->f_len = bytes_read+1;
514     content->f_p = content->f_base;
515     content->f_end = content->f_base + bytes_read;
516     *content->f_end = '\0';
517     content->f_line = 0;
518     return(content);
519 }
520 
freefile(fp)521 void freefile(fp)
522     struct filepointer  *fp;
523 {
524     free(fp->f_base);
525     free(fp);
526 }
527 
copy(str)528 char *copy(str)
529     register char   *str;
530 {
531     register char   *p = (char *)malloc(strlen(str) + 1);
532 
533     strcpy(p, str);
534     return(p);
535 }
536 
match(str,list)537 int match(str, list)
538     register char   *str, **list;
539 {
540     register int    i;
541 
542     for (i=0; *list; i++, list++)
543         if (strcmp(str, *list) == 0)
544             return(i);
545     return(-1);
546 }
547 
548 /*
549  * Get the next line.  We only return lines beginning with '#' since that
550  * is all this program is ever interested in.
551  */
get_line(filep)552 char *get_line(filep)
553     register struct filepointer *filep;
554 {
555     register char   *p, /* walking pointer */
556             *eof,   /* end of file pointer */
557             *bol;   /* beginning of line pointer */
558     register int    lineno; /* line number */
559 
560     p = filep->f_p;
561     eof = filep->f_end;
562     if (p >= eof)
563         return((char *)NULL);
564     lineno = filep->f_line;
565 
566     for(bol = p--; ++p < eof; ) {
567         if (*p == '/' && *(p+1) == '*') { /* consume comments */
568             *p++ = ' ', *p++ = ' ';
569             while (*p) {
570                 if (*p == '*' && *(p+1) == '/') {
571                     *p++ = ' ', *p = ' ';
572                     break;
573                 }
574                 else if (*p == '\n')
575                     lineno++;
576                 *p++ = ' ';
577             }
578             continue;
579         }
580         else if (*p == '/' && *(p+1) == '/') { /* consume comments */
581             *p++ = ' ', *p++ = ' ';
582             while (*p && *p != '\n')
583                 *p++ = ' ';
584             if ( *p == '\n' )
585                 p--;
586             lineno++;
587             continue;
588         }
589         else if (*p == '\\') {
590             if (*(p+1) == '\n') {
591                 *p = ' ';
592                 *(p+1) = ' ';
593                 lineno++;
594             }
595         }
596         else if (*p == '\n') {
597             lineno++;
598             if (*bol == '#') {
599                 register char *cp;
600 
601                 *p++ = '\0';
602                 /* punt lines with just # (yacc generated) */
603                 for (cp = bol+1;
604                      *cp && (*cp == ' ' || *cp == '\t'); cp++);
605                 if (*cp) goto done;
606             }
607             bol = p+1;
608         }
609     }
610     if (*bol != '#')
611         bol = NULL;
612 done:
613     filep->f_p = p;
614     filep->f_line = lineno;
615     return(bol);
616 }
617 
618 /*
619  * Strip the file name down to what we want to see in the Makefile.
620  * It will have objprefix and objsuffix around it.
621  */
base_name(file)622 char *base_name(file)
623     register char   *file;
624 {
625     register char   *p;
626 
627     file = copy(file);
628     for(p=file+strlen(file); p>file && *p != '.'; p--) ;
629 
630     if (*p == '.')
631         *p = '\0';
632 
633     while (p > file) {
634         if ( *p == '/' ||  *p == '\\') {
635             file = p + 1;
636             break;
637         };
638         p--;
639     };
640     return(file);
641 }
642 
643 #if defined(USG) && !defined(CRAY) && !defined(SVR4)
rename(from,to)644 int rename (from, to)
645     char *from, *to;
646 {
647     (void) unlink (to);
648     if (link (from, to) == 0) {
649     unlink (from);
650     return 0;
651     } else {
652     return -1;
653     }
654 }
655 #endif /* USGISH */
656 
redirect(line,makefile)657 void redirect(line, makefile)
658     char    *line,
659         *makefile;
660 {
661     struct stat st;
662     FILE    *fdin, *fdout;
663     char    backup[ OURBUFSIZ ],
664         buf[ OURBUFSIZ ];
665     boolean found = FALSE;
666     int len;
667 
668     /*
669      * if makefile is "-" then let it pour onto stdout.
670      */
671     if (makefile && *makefile == '-' && *(makefile+1) == '\0')
672         return;
673 
674     /*
675      * use a default makefile is not specified.
676      */
677     if (!makefile) {
678         if (stat("Makefile", &st) == 0)
679             makefile = "Makefile";
680         else if (stat("makefile", &st) == 0)
681             makefile = "makefile";
682         else
683             fatalerr("[mM]akefile is not present\n");
684     }
685     else
686         stat(makefile, &st);
687     if ((fdin = fopen(makefile, "r")) == NULL)
688         fatalerr("cannot open \"%s\"\n", makefile);
689     sprintf(backup, "%s.bak", makefile);
690     unlink(backup);
691 #if defined(WIN32) || defined(OS2)
692     fclose(fdin);
693 #endif
694     if (rename(makefile, backup) < 0)
695         fatalerr("cannot rename %s to %s\n", makefile, backup);
696 #if defined(WIN32) || defined(OS2)
697     if ((fdin = fopen(backup, "r")) == NULL)
698         fatalerr("cannot open \"%s\"\n", backup);
699 #endif
700     if ((fdout = freopen(makefile, "w", stdout)) == NULL)
701         fatalerr("cannot open \"%s\"\n", backup);
702     len = strlen(line);
703     while (!found && fgets(buf, OURBUFSIZ, fdin)) {
704         if (*buf == '#' && strncmp(line, buf, len) == 0)
705             found = TRUE;
706         fputs(buf, fdout);
707     }
708     if (!found) {
709         if (verbose)
710         warning("Adding new delimiting line \"%s\" and dependencies...\n",
711             line);
712         puts(line); /* same as fputs(fdout); but with newline */
713     } else if (append) {
714         while (fgets(buf, OURBUFSIZ, fdin)) {
715         fputs(buf, fdout);
716         }
717     }
718     fflush(fdout);
719 #if defined(USGISH) || defined(_SEQUENT_) || defined(USE_CHMOD)
720     chmod(makefile, st.st_mode);
721 #else
722     fchmod(fileno(fdout), st.st_mode);
723 #endif /* USGISH */
724     fclose(fdin);
725 }
726 
fatalerr(char * msg,...)727 void fatalerr(char *msg, ...)
728 {
729     va_list args;
730     fprintf(stderr, "%s: error:  ", ProgramName);
731     va_start(args, msg);
732     vfprintf(stderr, msg, args);
733     va_end(args);
734     exit (1);
735 }
736 
warning(char * msg,...)737 void warning(char *msg, ...)
738 {
739 #ifdef DEBUG_MKDEPEND
740     va_list args;
741     fprintf(stderr, "%s: warning:  ", ProgramName);
742     va_start(args, msg);
743     vfprintf(stderr, msg, args);
744     va_end(args);
745 #else
746     (void)msg;
747 #endif /* DEBUG_MKDEPEND */
748 }
749 
warning1(char * msg,...)750 void warning1(char *msg, ...)
751 {
752 #ifdef DEBUG_MKDEPEND
753     va_list args;
754     va_start(args, msg);
755     vfprintf(stderr, msg, args);
756     va_end(args);
757 #else
758     (void)msg;
759 #endif /* DEBUG_MKDEPEND */
760 }
761 
convert_slashes(path)762 void convert_slashes(path)
763     char* path;
764 {
765 #if defined (WNT) || defined(OS2)
766     /*
767      * Convert backslashes to slashes
768      */
769     char *ptr;
770     if (native_win_slashes) {
771         for (ptr = (char*)path; *ptr; ++ptr)
772             if (*ptr == '/')
773                 *ptr = '\\';
774     } else {
775         for (ptr = (char*)path; *ptr; ++ptr)
776             if (*ptr == '\\')
777                 *ptr = '/';
778     };
779 #else
780     (void)path;
781 #endif
782 }
783 
append_slash(path)784 char* append_slash(path)
785     char* path;
786 {
787     char *new_string;
788     if ((path[strlen(path) - 1] == '/') || (path[strlen(path) - 1] == '\\')) {
789         new_string = path;
790     } else {
791         new_string = (char*)malloc(sizeof(char) * (strlen(path) + 2));
792         strcpy(new_string, path);
793         if (native_win_slashes)
794             strcat(new_string, "\\");
795         else
796             strcat(new_string, "/");
797     };
798     return new_string;
799 }
800 
801