8dfe2a5ad19cdde1cf7eaaeb502d02059c55f229
[keystone-rtos/ibl.git] / src / make / makedep / makedep.gawk
1 #*****************************************************************************
2 #* FILE PURPOSE:Scan C files for include references
3 #*
4 #******************************************************************************
5 #* FILE NAME:   makedep.awk
6 #*
7 #* DESCRIPTION:
8 #*
9 #* NOTE:        Written for Thompson Automation TAWK compiler
10 #*
11 #* NOTE:            Processes #includes even in false conditional compilation
12 #*
13 #* (C) Copyright 1999, Telogy Networks, Inc.
14 #******************************************************************************
16 local progname              = "makedep"
17 local version_string        = "V1.01"
18 local version_date          = "Aug 17, 2001"
20 #*******************************************************************************
21 # Types & Constants
22 #*******************************************************************************
23 local true = 1
24 local false = 0
26 local c_re_include          =  /^[ \t]*#[ \t]*include[ \t]+/
27 local s_re_include          =  /^[ \t]*\.(include|copy)[ \t]+/
28 local re_include            = c_re_include
30 #*******************************************************************************
31 # Command Line Options
32 #*******************************************************************************
33 local quiet                 = false
34 local no_warn               = false
35 local bracket_includes      = true
36 local quote_includes        = true
37 local abs_paths             = true
38 local recurse               = true
39 local depend_not_found      = false
40 local stdout_format         = false
41 local indent_string         = "    "
42 local objext                = "obj"
43 local outfile_spec          = ""
45 local outfile               = ""
46 local infile                = ""
47 local infile_basename
49 local err_file
51 local orig_argc
54 local paths[]
55 local depends[]             # actually [][]
56 local processed_files[]
58 #*******************************************************************************
59 # Syntax
60 #*******************************************************************************
61 local comment_start         = "# "
62 local comment_stop          = ""
63 local eol_continue          = "\\"
65 #*******************************************************************************
66 # File Processing
67 #*******************************************************************************
68 local file_error            = false
70 #*******************************************************************************
71 # Program Debug & Control
72 #*******************************************************************************
73 local trace_file            = "trace.out"
74 local trace_classes[]
75 local exit_code             = -1
76 local banner_done           = false
78 #*******************************************************************************
79 # Top Level Functions
80 #*******************************************************************************
81 BEGIN \
82 {
83     local i
84     local j
85     local option
86     local arg
87     local sub_option
88     local input_found = false
89     local any_gen = false
91     trace_classes[ "includes" ] = 0
92     trace_classes[ "flow" ]     = 0
93     trace_classes[ "file" ]     = 0
94     trace_classes[ "fileops" ]  = 0     # 1 = inhibit file delete rename, etc
97     paths[0] = 1
98     paths[1] = ""       # place holder for "current place" directory
100     trace( "flow", "BEGIN" )
102     err_file = stdout
104     for ( i=1; i < ARGC; i++)
105     {
106         if (ARGV[i] ~ /^-/)
107         {
108             option = substr(ARGV[i], 2, 1)
109             arg    = substr(ARGV[i], 3)
111             if (option == "I")
112             {
113                 if (arg == "")
114                 {
115                     # don't process this argument as a file
116                     ARGV[i] = ""
118                     i++
119                     arg = ARGV[i]
120                 }
121                 paths[0]++
122                 paths[paths[0]] = arg
123             }
124             else if (option == "a")
125             {
126                 re_include = s_re_include
127             }
128             else if (option == "e")
129             {
130                 if (arg == "")
131                 {
132                     # don't process this argument as a file
133                     ARGV[i] = ""
135                     i++
136                     arg = ARGV[i]
137                 }
138                 objext = arg    
139             }
140             else if (option == "f")
141             {
142                 depend_not_found = true
143             }
144             else if (option == "p")
145             {
146                 stdout_format = true
147             }
148             else if (option == "o")
149             {
150                 if (arg == "")
151                 {
152                     # don't process this argument as a file
153                     ARGV[i] = ""
155                     i++
156                     arg = ARGV[i]
157                 }
158                 outfile_spec = arg      
159             }
160             else if (option == "r")
161             {
162                 recurse = false
163             }
164             else if (option == "s")
165             {
166                 bracket_includes = false
167             }
168             else if (option == "q")
169             {
170                 quiet = true
171             }
172             else if (option == "w")
173             {
174                 no_warn = true
175             }
176             else if (option == "d")
177             {
178                 process_trace_option(arg)
179             }
180             else if (option == "h" || option == "?")
181             {
182                 help()
183             }
184             else
185             {
186                 fatal_error("bad option:" ARGV[i])
187             }
189             # don't process this argument as a file
190             ARGV[i] = ""
191         }
192         else
193         {
194             input_found = true
195             ARGV[i] = to_abs_path(ARGV[i])
196         }
197     }
199     if (!quiet)
200     {
201         banner()
202     }
204     if (stdout_format)
205     {
206         if (outfile_spec != "")
207         {
208             fatal_error("can't specify both -p and -o")
209         }
211         err_file = stderr
212         outfile  = stdout
213     }
215     if (outfile_spec == "")
216     {
217         outfile_spec = "./$.d"
218     }
220     if (!input_found)
221     {
222         fatal_error("nothing to do, use " progname "-h for help");
223     }
225     # we add more arguments as we go so remember the number of original args
226     orig_argc = ARGC
229 match( $0, re_include ) != 0 \
231     local num_depends
232     local filename
233     local abs_filename
234     local this_dir
236     trace("includes", "#include line:" $0)
238     # find directory of current file
239     this_dir = file_path(FILENAME)
240     if (this_dir == "")
241     {
242         this_dir = "./"
243     }
245     # assume that the file name is the second arg
246     filename = $2
248     # is this a bracket include?
249     if (filename ~ /^</)
250     {
251         # yes, should we process it?
252         if (!bracket_includes)
253         {
254             # no
255             next
256         }
257         paths[1] = ""
258     }
259     else
260     {
261         # no, must be a quote include, should we process it?
262         if (!quote_includes)
263         {
264             # no
265             next
266         }
267         paths[1] = this_dir
268     }
270     # strip off the quotes or brackets
271         if (filename ~ /^[<"]/)
272         {
273        filename = substr(filename, 2, length(filename)-2)
274         }
276     abs_filename = find_file(filename, paths);
277     if (abs_filename == "")
278     {
279         warn("include file not found", filename)
280         abs_filename = filename
281     }
282     else
283     {
284         if (recurse && !(abs_filename in processed_files))
285         {
286             trace("flow", "queueing file " abs_filename)
287             ARGV[ARGC] = abs_filename
288             processed_files[abs_filename] = 1
289             ARGC++
290             depends[abs_filename][0] = 0
291         }
292     }
294     num_depends                     = depends[FILENAME][0]+1
295     depends[FILENAME][num_depends]  = abs_filename
296     depends[FILENAME][0]            = num_depends
298     next
301 # all other lines do nothing
303     next
306 END \
308     local arg
310     trace( "flow", "END" )
312     if (exit_code >= 0)
313     {
314         exit(exit_code)
315     }
317     for (arg=1; arg < orig_argc; arg++)
318     {
319         delete processed_files
320         infile = ARGV[arg]
322         if (infile != "" && !stdout_format)
323         {
324             file_done()
326             infile_basename = basename(infile)
327             infile_basename = strip_ext(infile_basename)
328             outfile = outfile_spec
329             gsubs("$", infile_basename, outfile, 0)
331             gen_header()
332             file_error = false
333         }
335         process_depends(infile, 1)
336     }
339 #*******************************************************************************
340 # Command Line Functions
341 #*******************************************************************************
342 function process_trace_option(arg)
344     local i
345     local setting
347     if ( arg ~ /^\+/ )
348     {
349         setting = 1
350     }
351     else if ( arg ~ /^-/ )
352     {
353         setting = 0
354     }
355     else
356     {
357         fatal_error("bad debug option:" ARGV[i])
358     }
360     arg = substr(arg,2)
361     if (arg == "")
362     {
363         for (i in trace_classes)
364         {
365             trace_classes[i] = setting
366         }
367     }
368     else if (arg in trace_classes)
369     {
370         trace_classes[arg] = setting
371     }
372     else
373     {
374         banner()
375         print "Valid Trace Classes are:"
376         for (i in trace_classes)
377         {
378             print "\t" i
379         }
380         fatal_error("unknown trace class " arg)
381     }
384 function banner()
386     if (banner_done)
387     {
388         return
389     }
391     banner_done = true
392     print toupper(progname) " " version_string ": C include dependency generator/lister" >err_file
393     print "Last updated " version_date >err_file
396 function help()
398     banner()
399     print "usage " progname " <options> <file>"
400     print "where options is 0 or more of the following:"
401     print "(default values are listed in paren's)"
402     print "    -Idir                add an include path"
403     print "    -a                   use asm format includes"
404     print "    -eext                set obj extension to ext"
405     print "    -s                   don't process standard include files ie. <>"
406     print "    -r                   don't recurse to find dependencies of found include file"
407     print "    -o                   specify output file (./$.d)"
408     print "    -p                   pipe output to stdout w/o extra formating"
409     print "    -q                   quiet mode (no banner)"
410     print "    -w                   suppress warnings"
411     print "    -d(+|-)[trace class] this program's diagnostics (see source)"
412     print "    -h or -?             this help"
413     exit_code = 10
414     exit
417 #*******************************************************************************
418 # File Functions
419 #*******************************************************************************
420 function file_done()
422     close( outfile )
423     if ( file_error )
424     {
425         delete_file( outfile )
426     }
429 function file_time( name )
431     return ctime(filetime(name))
434 function file_exists( name )
436     return ( filemode(name) != "" )
439 function rename_file( old_name, new_name )
441     trace( "file", "rename " old_name " to " new_name )
442     if ( !traceif( "fileops" ) )
443     {
444         delete_file( new_name )
445         if ( !file_exists( old_name ) )
446         {
447             print "File does not exist: " old_name
448         }
449         else
450         {
451             rename(old_name,new_name)
452         }
453     }
456 function delete_file( name )
458     trace( "file", "delete " name )
459     if ( !traceif( "fileops" ) && file_exists( name ) )
460     {
461         rmfile(name)
462     }
465 # return filename without extension
466 function strip_ext( filename )
468     local new_name
470     # match the extension ( last dot and file component after it )
471     if ( match( filename, /\.[^ \t/\\.]*$/ ) != 0 )
472     {
473         # has an extension, return everything up to but not including it
474         new_name = substr( filename, 1, RSTART-1 )
475     }
476     else
477     {
478         # does not have an extension, return it all
479         new_name = filename
480     }
482     trace( "file", "strip_ext of " filename " gives " new_name )
483     return new_name
486 # return extension
487 function file_ext( filename )
489     local new_name
491     # match the extension ( last dot and file component after it )
492     if ( match( filename, /\.[^ \t/\\.]*$/ ) != 0 )
493     {
494         # has an extension, return it
495         new_name = substr( filename, RSTART )
496     }
497     else
498     {
499         # does not have an extension, return it all
500         new_name = ""
501     }
503     trace( "file", "filename_ext of " filename " gives " new_name )
504     return new_name
507 # return filename.ext w/o leading paths
508 function basename( filename )
510     local new_name
511     
512     new_name = filename
514     # turn all backslashes to forward slashes
515     gsubs("\\", "/", new_name)
517     # match the basename (everything after the last slash)
518     if ( match( new_name, /\/[^/]*$/ ) != 0 )
519     {
520         # match found, return it
521         new_name = substr(new_name, RSTART+1)
522     }
523     else
524     {
525         # no slashes found, strip off any drive spec
526         # for this purpose a drive spec is everything before the first colon
527         if ( match( new_name, /:[^:]*$/ ) != 0 )
528         {
529             # match found, return it
530             new_name = substr(new_name, RSTART+1)
531         }
532     }
534     trace( "file", "basename of " filename " gives " new_name )
535     return new_name
538 # return drive & directories of filename
539 function file_path( filename )
541     local new_name
542     
543     new_name = filename
545     # turn all backslashes to forward slashes
546     gsubs("\\", "/", new_name)
548     # match the basename (everything after the last slash)
549     if ( match( new_name, /\/[^/]*$/ ) != 0 )
550     {
551         # match found, return it
552         new_name = substr(new_name, 1, RSTART-1)
553     }
554     else
555     {
556         # no slashes found, strip off any drive spec
557         # for this purpose a drive spec is everything before the first colon
558         if ( match( new_name, /:[^:]*$/ ) != 0 )
559         {
560             # match found, return it
561             new_name = substr(new_name, 1, RSTART-1)
562         }
563         else
564         {
565             # no drive & no directories
566             new_name = ""
567         }
568     }
570     trace( "file", "basename of " filename " gives " new_name )
571     return new_name
574 function to_abs_path(filename)
576     # not implemented yet
577     return filename
580 function find_file(filename, path_array)
582     local i
583     local test_file
584     local num_paths
586     num_paths = path_array[0]
588     for (i=1; i <= num_paths; i++)
589     {
590         test_file = path_array[i]
592         if (test_file != "")
593         {
594             if (!(test_file ~ /\/$/))
595             {
596                 test_file = test_file "/"
597             }
598             test_file = test_file filename
599             test_file = to_abs_path(test_file)
601             if (file_exists(test_file))
602             {
603                 return test_file
604             }
605         }
606     }
608     return ""
611 #*******************************************************************************
612 # Output Processing
613 #*******************************************************************************
614 function process_depends(filename, level)
616     local i
617     local j
618     local abs_file
619     local num_depends
621     num_depends = depends[filename][0]
623     for (i=1; i <= num_depends; i++)
624     {
625         abs_file = depends[filename][i]
627         for (j=0; j < level; j++)
628         {
629             printf("%s", indent_string) >outfile
630         }
632         if (abs_file in processed_files)
633         {
634 #            printf("%s %-40s already included %s %s\n", \
635 #                comment_start, abs_file, comment_stop, eol_continue) >outfile
636         }
637         else
638         {
639             processed_files[abs_file] = 1
641             if (abs_file in depends)
642             {
643                 printf("%-40s %s\n", abs_file, eol_continue) >outfile
644 #                printf("%-40s %s %s %s %s\n", \
645 #                    abs_file, comment_start, file_time(abs_file), \
646 #                    comment_stop, eol_continue)   >outfile
647                 process_depends(abs_file, level+1)
648             }
649             else
650             {
651                 if (depend_not_found)
652                 {
653                                     printf("%-40s %s\n", abs_file, eol_continue) >outfile
654 #                    printf("%-40s %s not found %s %s\n", \
655 #                        abs_file, comment_start, comment_stop, eol_continue) >outfile
656                 }
657                 else
658                 {
659 #                    printf("%s %-40s not found %s %s\n", \
660 #                        comment_start, abs_file, comment_stop, eol_continue) >outfile
661                 }
662             }
663         }
664     }
667 function gen_header()
669     # print header
671     local   infile_ext
672     local   outfile_ext
674     infile_ext      = file_ext(infile)
675     outfile_ext     = file_ext(outfile)
677     print comment_start "Dependency file for " infile comment_stop >outfile
678     print comment_start "Generated on " ctime() comment_stop >outfile 
679     print comment_start "From " infile " dated " ctime(filetime(infile)) comment_stop >outfile
680     print comment_start "This file was generated by " progname ", do not edit!!" comment_stop >outfile
681     print "" >outfile
682     print infile_basename "." objext, ":", infile, infile_basename outfile_ext, eol_continue >outfile
685 #*******************************************************************************
686 # Support Functions
687 #*******************************************************************************
688 function error( desc )
690     print "Error: " desc " in " FILENAME " line " FNR >err_file
691     file_error = true
694 function warn( desc, arg )
696     local err
698     if (no_warn)
699     {
700         return
701     }
703     if (arg != "")
704     {
705         arg = sprintf("for item %s ", arg)
706     }
708     printf("Warning: %s%s in %s line %d\n", arg, desc, FILENAME, FNR) >err_file
711 function fatal_error( desc )
713     print "Error: " desc >err_file
715     exit_code = 3
716     exit
719 function trace( class, msg )
721     if ( traceif( class ) )
722     {
723         print msg >trace_file
724     }
727 function traceif( class )
729     if ( !(class in trace_classes) )
730     {
731         print "trace class", class, "missing" >trace_file
732         return true
733     }
734     return ( trace_classes[class] != 0 )