| #!/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 {[lindex $argv 0]!=""} { |
| set output_file [lindex $argv 0] |
| file delete -force $output_file |
| set out [open $output_file wb] |
| } else { |
| set output_file {} |
| } |
| |
| ############################## FIRST PASS ################################ |
| # Read through the shell.c.in source file to gather information. Do not |
| # yet generate any code |
| # |
| set in [open $topdir/src/shell.c.in] |
| fconfigure $in -translation binary |
| set allSource(src/shell.c.in) 1 |
| set inUsage 0 |
| set dotcmd {} |
| while {1} { |
| set lx [gets $in] |
| if {[eof $in]} break; |
| if {[regexp {^INCLUDE } $lx]} { |
| set cfile [lindex $lx 1] |
| if {[string match ../* $cfile]} { |
| set xfile [string range $cfile 3 end] |
| } else { |
| set xfile "src/$cfile" |
| } |
| set allSource($xfile) 1 |
| } elseif {[regexp {^\*\* USAGE:\s+([^\s]+)} $lx all dotcmd]} { |
| set inUsage 1 |
| set details [string trim [string range $lx 2 end]] |
| } elseif {$inUsage} { |
| if {![regexp {^\*\*} $lx] || [regexp { DOT-COMMAND: } $lx]} { |
| set inUsage 0 |
| set Usage($dotcmd) [string trim $details] |
| } else { |
| append details \n |
| append details [string range [string trimright $lx] 3 end] |
| } |
| } |
| } |
| |
| # Generate dot-command usage text based on the data accumulated in |
| # the Usage() array. |
| # |
| proc generate_usage {out} { |
| global Usage |
| puts $out "/**************************************************************" |
| puts $out "** \"Usage\" help text automatically generated from comments */" |
| puts $out "static const struct \173" |
| puts $out " const char *zCmd; /* Name of the dot-command */" |
| puts $out " const char *zUsage; /* Documentation */" |
| puts $out "\175 aUsage\[\] = \173" |
| foreach dotcmd [array names Usage] { |
| puts $out " \173 \"$dotcmd\"," |
| foreach line [split $Usage($dotcmd) \n] { |
| set x [string map [list \\ \\\\ \" \\\"] $line] |
| puts $out "\"$x\\n\"" |
| } |
| puts $out " \175," |
| } |
| puts $out "\175;" |
| } |
| # generate_usage stderr |
| |
| ###### SECOND PASS ####### |
| # Make a second pass through shell.c.in to generate the the final |
| # output, based on data gathered during the first pass. |
| # |
| |
| puts $out {/* |
| ** This is the amalgamated source code to the "sqlite3" or "sqlite3.exe" |
| ** command-line shell (CLI) for SQLite. This file is automatically |
| ** generated by the tool/mkshellc.tcl script from the following sources: |
| **} |
| foreach fn [lsort [array names allSource]] { |
| puts $out "** $fn" |
| } |
| puts $out {** |
| ** To modify this program, get a copy of the canonical SQLite source tree, |
| ** edit the src/shell.c.in file and/or some of the other files that are |
| ** listed above, then rerun the command "make shell.c". |
| */} |
| seek $in 0 start |
| puts $out "/************************* Begin src/shell.c.in ******************/" |
| proc omit_redundant_typedefs {line} { |
| global typedef_seen |
| if {[regexp {^typedef .* ([a-zA-Z0-9_]+);} $line all typename]} { |
| # --------------------\y jimtcl does not support \y |
| if {[info exists typedef_seen($typename)]} { |
| return "/* [string map {/* // */ //} $line] */" |
| } |
| set typedef_seen($typename) 1 |
| } |
| return $line |
| } |
| set iLine 0 |
| while {1} { |
| set lx [omit_redundant_typedefs [gets $in]] |
| if {[eof $in]} break; |
| incr iLine |
| if {[regexp {^INCLUDE } $lx]} { |
| set cfile [lindex $lx 1] |
| if {[string match ../* $cfile]} { |
| set xfile [string range $cfile 3 end] |
| } else { |
| set xfile "src/$cfile" |
| } |
| puts $out "/************************* Begin $xfile ******************/" |
| # puts $out "#line 1 \"$xfile\"" |
| set in2 [open $topdir/$xfile] |
| fconfigure $in2 -translation binary |
| while {![eof $in2]} { |
| set lx [omit_redundant_typedefs [gets $in2]] |
| if {[regexp {^# *include "sqlite} $lx]} { |
| set lx "/* $lx */" |
| } |
| if {[regexp {^# *include "windirent.h"} $lx]} { |
| set lx "/* $lx */" |
| } |
| set lx [string map [list __declspec(dllexport) {}] $lx] |
| puts $out $lx |
| } |
| close $in2 |
| puts $out "/************************* End $xfile ********************/" |
| # puts $out "#line [expr $iLine+1] \"shell.c.in\"" |
| } elseif {[regexp {^INSERT-USAGE-TEXT-HERE} $lx]} { |
| generate_usage $out |
| } else { |
| puts $out $lx |
| } |
| } |
| puts $out "/************************* End src/shell.c.in ******************/" |
| close $in |
| close $out |