#!/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 rerun "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 # Try to disable write permissions on the generate file, to prevent # accidentally editing the generated file rather than source files. # if {$output_file ne ""} { catch {file attributes $output_file -readonly 1} catch {file attributes $output_file -permissions -w} catch {exec chmod -w $output_file} }