#!/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
