drh | 903b230 | 2017-10-13 18:58:55 +0000 | [diff] [blame] | 1 | #!/usr/bin/tclsh |
| 2 | # |
| 3 | # Use this script to build C-language source code for a program that uses |
| 4 | # tclsqlite.c together with custom TCL scripts and/or C extensions for |
| 5 | # either SQLite or TCL. |
| 6 | # |
| 7 | # Usage example: |
| 8 | # |
| 9 | # tclsh mktclsqliteprog.tcl demoapp.c.in >demoapp.c |
| 10 | # |
| 11 | # The demoapp.c.in file contains a mixture of C code, TCL script, and |
| 12 | # processing directives used by mktclsqliteprog.tcl to build the final C-code |
| 13 | # output file. Most lines of demoapp.c.in are copied straight through into |
| 14 | # the output. The following control directives are recognized: |
| 15 | # |
| 16 | # BEGIN_STRING |
| 17 | # |
| 18 | # This marks the beginning of large string literal - usually a TCL |
| 19 | # script of some kind. Subsequent lines of text through the first |
| 20 | # line that begins with END_STRING are converted into a C-language |
| 21 | # string literal. |
| 22 | # |
| 23 | # INCLUDE path |
| 24 | # |
| 25 | # The path argument is the name of a file to be inserted in place of |
| 26 | # the INCLUDE line. The path can begin with $ROOT to signify the |
| 27 | # root of the SQLite source tree, or $HOME to signify the directory |
| 28 | # that contains the demoapp.c.in input script itself. If the path does |
| 29 | # not begin with either $ROOT or $HOME, then it is interpreted relative |
| 30 | # to the current working directory. |
| 31 | # |
| 32 | # If the INCLUDE occurs in the middle of BEGIN_STRING...END_STRING |
| 33 | # then all of the text in the input file is converted into C-language |
| 34 | # string literals. |
| 35 | # |
| 36 | # None of the control directives described above will nest. Only the |
| 37 | # top-level input file ("demoapp.c.in" in the example) is interpreted. |
| 38 | # referenced files are copied verbatim. |
| 39 | # |
| 40 | if {[llength $argv]!=1} { |
| 41 | puts stderr "Usage: $argv0 TEMPLATE >OUTPUT" |
| 42 | exit 1 |
| 43 | } |
| 44 | set infile [lindex $argv 0] |
| 45 | set ROOT [file normalize [file dir $argv0]/..] |
| 46 | set HOME [file normalize [file dir $infile]] |
| 47 | set in [open $infile rb] |
| 48 | puts [subst {/* DO NOT EDIT |
| 49 | ** |
| 50 | ** This file was generated by \"$argv0 $infile\". |
| 51 | ** To make changes, edit $infile then rerun the generator |
| 52 | ** command. |
| 53 | */}] |
| 54 | set instr 0 |
| 55 | while {1} { |
| 56 | set line [gets $in] |
| 57 | if {[eof $in]} break |
| 58 | if {[regexp {^INCLUDE (.*)} $line all path]} { |
| 59 | regsub {^\$ROOT\y} $path $ROOT path |
| 60 | regsub {^\$HOME\y} $path $HOME path |
| 61 | set in2 [open $path rb] |
| 62 | puts "/* INCLUDE $path */" |
| 63 | if {$instr} { |
| 64 | while {1} { |
| 65 | set line [gets $in2] |
| 66 | if {[eof $in2]} break |
| 67 | set x [string map "\\\\ \\\\\\\\ \\\" \\\\\"" $line] |
| 68 | puts "\"$x\\n\"" |
| 69 | } |
| 70 | } else { |
| 71 | puts [read $in2] |
| 72 | } |
| 73 | puts "/* END $path */" |
| 74 | close $in2 |
| 75 | continue |
| 76 | } |
| 77 | if {[regexp {^BEGIN_STRING} $line]} { |
| 78 | set instr 1 |
| 79 | puts "/* BEGIN_STRING */" |
| 80 | continue |
| 81 | } |
| 82 | if {[regexp {^END_STRING} $line]} { |
| 83 | set instr 0 |
| 84 | puts "/* END_STRING */" |
| 85 | continue |
| 86 | } |
| 87 | if {$instr} { |
| 88 | set x [string map "\\\\ \\\\\\\\ \\\" \\\\\"" $line] |
| 89 | puts "\"$x\\n\"" |
| 90 | } else { |
| 91 | puts $line |
| 92 | } |
| 93 | } |