| #!/usr/bin/tclsh |
| # |
| # Run this script to generate the "shell.c" source file from |
| # constituent parts. |
| # |
| # No arguments are required. This script determines the location |
| # of its input files relative to the location of the script itself. |
| # This script should be tool/mkshellc.tcl. If the directory holding |
| # the script is $DIR, then the component parts are located in $DIR/../src |
| # and $DIR/../ext/misc. |
| # |
| set ::topdir [file dir [file dir [file normal $argv0]]] |
| set ::out stdout |
| fconfigure stdout -translation binary |
| |
| if {$argc == 0} { |
| set inSources [list shell.c.in] |
| puts $::out {/* DO NOT EDIT! |
| ** This file is automatically generated by the script in the canonical |
| ** SQLite source tree at tool/mkshellc.tcl. That script combines source |
| ** code from various constituent source files of SQLite into this single |
| ** "shell.c" file used to implement the SQLite command-line shell. |
| ** |
| ** Most of the code found below comes from the "src/shell.c.in" file in |
| ** the canonical SQLite source tree. That main file contains "INCLUDE" |
| ** lines that specify other files in the canonical source tree that are |
| ** inserted to getnerate this complete program source file. |
| ** |
| ** The code from multiple files is combined into this single "shell.c" |
| ** source file to help make the command-line program easier to compile. |
| ** |
| ** To modify this program, get a copy of the canonical SQLite source tree, |
| ** edit "src/shell.c.in" and/or some of the other files that are included |
| ** by "src/shell.c.in", then rerun the tool/mkshellc.tcl script. |
| */} |
| } else { |
| set inSources $argv |
| } |
| |
| array set ::filesInput {} |
| |
| proc omit_redundant_typedefs {line} { |
| global typedef_seen |
| if {[regexp {^typedef .*\y([a-zA-Z0-9_]+);} $line all typename]} { |
| if {[info exists typedef_seen($typename)]} { |
| return "/* [string map {/* // */ //} $line] */" |
| } |
| set typedef_seen($typename) 1 |
| } |
| return $line |
| } |
| |
| # For INCLUDED files, suppress redundant #include directives and |
| # eliminate a Windows-specific attribute not needed for the shell. |
| proc misc_sieve {line} { |
| if {[regexp {^# *include "([^"]+)"} $line _ finc]} { |
| set finc [regsub {".*$} $finc ""] |
| # Project headers #include'd at top level (by shell.c.in), or |
| # files already the object of INCLUDE, need not be #include'd. |
| if {[regexp {^sqlite} $finc] || [info exists ::filesInput($finc)]} { |
| return "/* $line */" |
| } |
| } |
| return [string map [list __declspec(dllexport) {}] $line] |
| } |
| |
| # Read, process and emit the named file, and track recursion level. |
| proc include_file {fname rlevel} { |
| if {[info exists ::filesInput($fname)]} return ;# Block revisits. |
| set in [open $::topdir/src/$fname] |
| fconfigure $in -translation binary |
| set ::filesInput($fname) 1 |
| if {$rlevel > 0} { |
| puts $::out "/************************* Begin $fname ******************/" |
| } |
| set iLine 0 |
| # puts $::out "#line 1 \"$fname\"" |
| while {![eof $in]} { |
| set lx [omit_redundant_typedefs [gets $in]] |
| incr iLine |
| if {[regexp {^INCLUDE( |\()} $lx _ sep]} { |
| if {$sep eq " "} { |
| set ifn [lindex $lx 1] |
| } elseif {![regexp {^INCLUDE\( *([^ ]+) *\)} $lx _ ifn]} { |
| puts stderr "Bad INCLUDE at $iLine in $fname" |
| exit 1 |
| } |
| include_file $ifn [expr $rlevel + 1] |
| # puts $::out "#line [expr $iLine+1] \"$fname\"" |
| } else { |
| if {$rlevel > 0} { |
| puts $::out [misc_sieve $lx] |
| } elseif {$lx ne "" || ![eof $in]} { |
| puts $::out $lx |
| } |
| } |
| } |
| close $in |
| if {$rlevel > 0} { |
| puts $::out "/************************* End $fname ********************/" |
| } |
| } |
| |
| foreach {source} $inSources { |
| include_file $source 0 |
| } |
| close $::out |