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