#--------------------------------------------------------------------
#   makemake.tcl
#   ============
#   Tcl procs to convert Nebula package definitions into Makefiles
#   and Visual Studio workspace files.
#
#   Nebula package files define 'modules' and 'targets'. A module
#   is a collection of source files that belong together.
#   A target is a collection of modules, and specifies how the
#   modules should be compiled into a binary. This can be a
#   generic dll, a class package dll, or an executable.
#
#   (C) 2000 A.Weissflog
#
#   17-May-00   floh    added support for header files
#--------------------------------------------------------------------

source "$farwest_home/bin/makedepend.tcl"
source "$farwest_home/bin/nsh.tcl"

#--------------------------------------------------------------------
#   structs
#   =======
#   mod(i,name)         - name of module
#   mod(i,dir)          - directory where source files reside
#   mod(i,files)        - list of source files for module 'name'
#   mod(i,headers)      - list of header files for module 'name'
#   mod(i,version)      - version file for module 'name'
#   mod(i,objs)         - object file names for win32 (generated)
#   mod(i,srcs)         - source file names for win32 (generated)
#   mod(i,hdrs)         - header file names
#   mod(i,deps,src)     - dependencies for 'src'
#
#   tar(i,name)         - name of target
#   tar(i,platform)     - one of 'all|win32|unix'
#   tar(i,type)         - one of 'dll|package|exe'
#   tar(i,mods)         - module list for target 'name'
#   tar(i,depends)      - list of other targets, which this target depends on
#   tar(i,libs_win32)   - win32 specific link libs
#   tar(i,libs_unix)    - unix specific link libs
#   tar(i,rsrc_win32)   - win32 specific resource files
#   tar(i,copyright)    - target copyright string
#
#   'plat' may be one of 'win32', 'unix'
#   'tartype' may be one of 'release', 'debug', 'profile', 'noassert'
#--------------------------------------------------------------------

global mod
global tar
global num_mods
global num_tars

set num_mods 0
set num_tars 0

set platform [get_platform]

#--------------------------------------------------------------------
#   procs
#   =====
#   beginmodule $mod_name
#       setdir $subdir
#       setfiles   $file $file $file...
#       setheaders $file $file $file...
#       setver $file
#   endmodule
#   begintarget $name
#       setmods $module $module $module...
#       setdepend $target $target...
#       setlibs_win32 $lib $lib...
#       setlibs_unix  $lib $lib...
#   endtarget
#--------------------------------------------------------------------

#====================================================================
#   UTILITY PROCEDURES
#====================================================================

#--------------------------------------------------------------------
#   cvs
#   Minimal tcl shell around cvs.
#--------------------------------------------------------------------
proc cvs { cmd dir pattern } {
    global platform
    
    set err "ok"
    set cwd [pwd]
    cd $dir
    set files [glob -nocomplain $pattern]

    if {$files != ""} {
        set sh "sh"
        set sh_arg "-c"
        if {($platform=="win2k") || ($platform=="winnt")} {
            # replace slashes by backslash in 'dir'
            set dir [string map {/ \\} $dir]
            set sh "cmd.exe"
            set sh_arg "/c"
            set sh_delim "&&"
        } elseif {$platform=="win9x"} {
            set dir [string map {/ \\} $dir]
            set sh "command.com"
            set sh_arg "/c"
            set sh_delim "&&"
        } elseif {$platform=="unix"} {
            set sh "sh"
            set sh_arg "-c"
            set sh_delim ";"
        }
        after 500
        switch $cmd {
            addascii { catch { exec $sh $sh_arg "cd $dir $sh_delim cvs add $files"  } err }
            commit   { catch { exec $sh $sh_arg "cd $dir $sh_delim cvs commit -m bla $files" } err }
            edit     { catch { exec $sh $sh_arg "cd $dir $sh_delim cvs edit $files" } err }
        }
        puts "-> cvs $cmd $files = $err"
    } else {
        puts "-> ignoring cvs on empty list"
    }
    cd $cwd
}

#--------------------------------------------------------------------
#   make_cvs_edit
#   Puts all affected files into 'cvs edit' state.
#   11-Mar-00   floh    created
#   20-Mar-00   floh    no longer affect .toc files
#--------------------------------------------------------------------
proc make_cvs_edit { } {
    global farwest_home
    set cwd [pwd]
    cvs edit $farwest_home/code/src/packages *.cc
    cvs edit $farwest_home/code/src          *.mak
    cvs edit $farwest_home/code/vstudio      *.dsp
    cvs edit $farwest_home/code/vstudio      *.dsw
    cd $cwd
}

#--------------------------------------------------------------------
#   make_cvs_add
#   Add any new files.
#   11-Mar-00   floh    created
#   20-Mar-00   floh    + no longer affect .toc files
#                       + no longer commit changes, just add
#--------------------------------------------------------------------
proc make_cvs_add { } {
    global farwest_home
    set cwd [pwd]
    cvs addascii $farwest_home/code/src/packages *.cc
    cvs addascii $farwest_home/code/src          *.mak
    cvs addascii $farwest_home/code/vstudio      *.dsp
    cvs addascii $farwest_home/code/vstudio      *.dsw
    cd $cwd
}

#--------------------------------------------------------------------
#   addtolist $var $list
#   04-Mar-00   floh    created
#--------------------------------------------------------------------
proc addtolist {var list} {
    upvar $var v
    for {set i 0} {$i < [llength $list]} {incr i} {
        append v [lindex $list $i] " "
    }
}

#--------------------------------------------------------------------
#   findmodbyname $name
#   Find module index by name.
#   04-Mar-00   floh    created
#--------------------------------------------------------------------
proc findmodbyname {name} {
    global mod
    global num_mods
    for {set i 0} {$i < $num_mods} {incr i} {
        if {$name == $mod($i,name)} {
            return $i
        }
    }
    puts "ERROR: module '$name' not defined!"
    exit
}

#--------------------------------------------------------------------
#   findtargetbyname $name
#   Find target index by name.
#   04-Mar-00   floh    created
#--------------------------------------------------------------------
proc findtargetbyname {name} {
    global tar
    global num_tars
    for {set i 0} {$i < $num_tars} {incr i} {
        if {$name == $tar($i,name)} {
            return $i
        }
    }
    puts "ERROR: target '$name' not defined!"
    exit
}

#--------------------------------------------------------------------
#   gen_filelists $module
#   Generate source and object file name lists for a given module.
#   04-Mar-00   floh    created
#   11-Mar-00   floh    + generate dependencies for files
#   20-Mar-00   floh    + global variable 'global_gendeps' used to
#                         turn dependency-generation on/off
#   17-May-00   floh    + support for header files
#--------------------------------------------------------------------
proc gen_filelists {module} {
    global mod
    global num_mods
    global global_gendeps
    set i [findmodbyname $module]

    set num_files [llength $mod($i,files)]

    # generate object file lists
    set mod($i,objs) ""
    for {set j 0} {$j < $num_files} {incr j} {
        lappend mod($i,objs) "$mod($i,dir)/[lindex $mod($i,files) $j]\$(OBJ)"
    }

    # generate source file lists and dependencies
    set mod($i,srcs) ""   
    for {set j 0} {$j < $num_files} {incr j} {
        set cur_src "$mod($i,dir)/[lindex $mod($i,files) $j].cc"
        lappend mod($i,srcs) $cur_src
        if {$global_gendeps} {
            puts "-> dependencies for $cur_src"
            set tmp_dep_list [get_depends $cur_src ""]
            set dep_list ""
            for {set k 0} {$k < [llength $tmp_dep_list]} {incr k} {
                append dep_list "../inc/[lindex $tmp_dep_list $k]" " "
            }
            set mod($i,deps,$cur_src) $dep_list
        }
    }

    # append header files to 'hdrs'
    set mod($i,hdrs) ""
    set num_headers [llength $mod($i,headers)]
    for {set j 0} {$j < $num_headers} {incr j} {
        set cur_hdr "$mod($i,dir)/[lindex $mod($i,headers) $j].h"
        lappend mod($i,hdrs) $cur_hdr
    }
}

#====================================================================
#   .PAK FILE PARSING PROCEDURES
#====================================================================

#--------------------------------------------------------------------
#   beginmodule $name
#   Start definition of a module.
#   04-Mar-00   floh    created
#--------------------------------------------------------------------
proc beginmodule {name} {
    global num_mods
    global mod
    set mod($num_mods,name)         $name
    set mod($num_mods,dir)          ""
    set mod($num_mods,files)        ""
    set mod($num_mods,headers)      ""
    set mod($num_mods,version)      ""
}

#--------------------------------------------------------------------
#   setdir $subdir
#   Specify path where module files live.
#   04-Mar-00   floh    created
#--------------------------------------------------------------------
proc setdir {subdir} {
    global mod
    global num_mods
    set mod($num_mods,dir) $subdir
}

#--------------------------------------------------------------------
#   setfiles $files
#   04-Mar-00   floh    created
#--------------------------------------------------------------------
proc setfiles {file_list} {
    global mod
    global num_mods
    addtolist mod($num_mods,files) $file_list
}

#--------------------------------------------------------------------
#   setheaders $files
#   17-May-00   floh    created
#--------------------------------------------------------------------
proc setheaders {file_list} {
    global mod
    global num_mods
    addtolist mod($num_mods,headers) $file_list
}

#--------------------------------------------------------------------
#   setversion $version_file
#   04-Mar-00   floh    created
#--------------------------------------------------------------------
proc setversion {version_file} {
    global mod
    global num_mods
    set mod($num_mods,version) $version_file
}

#--------------------------------------------------------------------
#   endmodule
#   04-Mar-00   floh    created
#--------------------------------------------------------------------
proc endmodule { } {
    global mod
    global num_mods

    # generate file lists for module
    set name $mod($num_mods,name)
    incr num_mods
    gen_filelists $name
}

#--------------------------------------------------------------------
#   dumpmodules
#   Print data of all defined modules.
#   04-Mar-00   floh    created
#--------------------------------------------------------------------
proc dumpmodules { } {
    global mod
    global num_mods
    puts "\n\n======================================================="
    puts " MODULES"
    puts " "
    for {set i 0} {$i < $num_mods} {incr i} {
        puts "-------------------------------------------------------"
        puts " module:      $mod($i,name)"
        puts " dir:         $mod($i,dir)"
        puts " files:       $mod($i,files)"
        puts " headers:     $mod($i,headers)"
        puts " version: $mod($i,version)"
    }
}

#--------------------------------------------------------------------
#   begintarget $name
#   04-Mar-00   floh    created
#--------------------------------------------------------------------
proc begintarget {name} {
    global num_tars
    global tar
    set tar($num_tars,name)         $name
    set tar($num_tars,platform)     "all"
    set tar($num_tars,type)         ""
    set tar($num_tars,mods)         ""
    set tar($num_tars,depends)      ""
    set tar($num_tars,libs_win32)   ""
    set tar($num_tars,libs_unix)    ""
    set tar($num_tars,rsrc_win32)   ""
    set tar($num_tars,copyright)    "(C) 2000 A.Weissflog"
}

#--------------------------------------------------------------------
#   setplatform $platform
#   09-Mar-00   floh    created
#--------------------------------------------------------------------
proc setplatform {platform} {
    global num_tars
    global tar
    set tar($num_tars,platform) $platform
}

#--------------------------------------------------------------------
#   settype $type
#   04-Mar-00   floh    created
#--------------------------------------------------------------------
proc settype {type} {
    global num_tars
    global tar
    set tar($num_tars,type) $type
}

#--------------------------------------------------------------------
#   setmods $modules
#   04-Mar-00   floh    created
#--------------------------------------------------------------------
proc setmods {mod_list} {
    global num_tars
    global tar
    set tar($num_tars,mods) ""
    for {set i 0} {$i < [llength $mod_list]} {incr i} {
        lappend tar($num_tars,mods) [lindex $mod_list $i] 
    }
}

#--------------------------------------------------------------------
#   setdepends $depends
#   04-Mar-00   floh    created
#--------------------------------------------------------------------
proc setdepends {depends} {
    global num_tars
    global tar
    set tar($num_tars,depends) $depends
}

#--------------------------------------------------------------------
#   setlibs_win32 $libs
#   04-Mar-00   floh    created
#--------------------------------------------------------------------
proc setlibs_win32 {libs} {
    global num_tars
    global tar
    addtolist tar($num_tars,libs_win32) $libs
}

#--------------------------------------------------------------------
#   setlibs_unix $libs
#   04-Mar-00   floh    created
#--------------------------------------------------------------------
proc setlibs_unix {libs} {
    global num_tars
    global tar
    addtolist tar($num_tars,libs_unix) $libs
}

#--------------------------------------------------------------------
#   setrsrc_win32 $libs
#   04-Mar-00   floh    created
#--------------------------------------------------------------------
proc setrsrc_win32 {file_list} {
    global num_tars
    global tar
    addtolist tar($num_tars,rsrc_win32) $file_list
}

#--------------------------------------------------------------------
#   endtarget
#   04-Mar-00   floh    created
#--------------------------------------------------------------------
proc endtarget { } {
    global num_tars
    incr num_tars
}

#--------------------------------------------------------------------
#   dumptargets
#   Print data of all defined targets.
#   04-Mar-00   floh    created
#--------------------------------------------------------------------
proc dumptargets { } {
    global tar
    global num_tars
    puts "\n\n======================================================="
    puts " TARGETS"
    puts " "
    for {set i 0} {$i < $num_tars} {incr i} {
        puts "-------------------------------------------------------"
        puts " target:      $tar($i,name)"
        puts " type:        $tar($i,type)"
        puts " mods:        $tar($i,mods)"
        puts " depends:     $tar($i,depends)"
        puts " libs_win32:  $tar($i,libs_win32)"
        puts " libs_unix:   $tar($i,libs_unix)"
        puts " rsrc_win32:  $tar($i,rsrc_win32)"
        puts " copyright:   $tar($i,copyright)"
    }
}

#====================================================================
#   PACKAGE HELPER FUNCTIONS
#====================================================================

#--------------------------------------------------------------------
#   gentocfile_win32
#   gentocfile_linux
#   Generate TOC files for a package target under bin/win32 and
#   bin/linux.
#   06-Mar-00   floh    created
#   20-Mar-00   floh    + slit into separate win32/linux procs
#                       + added date and time to heade
#--------------------------------------------------------------------
proc gentocfile_win32 {tarname} {
    global tar
    global farwest_home
    set i [findtargetbyname $tarname]

    puts "-> generating $farwest_home/bin/win32/$tarname.toc"
    set cid [open $farwest_home/bin/win32/$tarname.toc w]
    puts $cid "#--------------------------------------------------------------------"
    puts $cid "# /bin/win32/$tarname.toc"
    puts $cid "# MACHINE GENERATED, DON'T EDIT!"
    puts $cid "# [clock format [clock seconds]]"
    puts $cid "#--------------------------------------------------------------------"
    puts $cid "\$$tarname"
    for {set j 0} {$j < [llength $tar($i,mods)]} {incr j} {
        puts $cid "%[lindex $tar($i,mods) $j]"
    }
    close $cid
}
proc gentocfile_linux {tarname} {
    global tar
    global farwest_home
    set i [findtargetbyname $tarname]

    puts "-> generating $farwest_home/bin/linux/$tarname.toc"
    set cid [open $farwest_home/bin/linux/$tarname.toc w]
    puts $cid "#--------------------------------------------------------------------"
    puts $cid "# /bin/linux/$tarname.toc"
    puts $cid "# MACHINE GENERATED, DON'T EDIT!"
    puts $cid "# [clock format [clock seconds]]"
    puts $cid "#--------------------------------------------------------------------"
    puts $cid "\$$tarname"
    for {set j 0} {$j < [llength $tar($i,mods)]} {incr j} {
        puts $cid "%[lindex $tar($i,mods) $j]"
    }
    close $cid
}

#--------------------------------------------------------------------
#   genpacksrc
#   Generate package.cc file for a package target.
#   06-Mar-00   floh    created
#--------------------------------------------------------------------
proc genpacksrc {tarname} {
    global tar
    set i [findtargetbyname $tarname]

    puts "-> generating packages/$tarname.cc"
    set cid [open "packages/$tarname.cc" w]
    puts $cid "//----------------------------------------------------------"
    puts $cid "// $tarname.cc"
    puts $cid "// MACHINE GENERATED, DON'T EDIT!"
    puts $cid "//----------------------------------------------------------"
    puts $cid {#include "kernel/ntypes.h"}
    puts $cid {#include "kernel/nkernelserver.h"}
    for {set j 0} {$j < [llength $tar($i,mods)]} {incr j} {
        set initproc "n_init_[lindex $tar($i,mods) $j]"
        set finiproc "n_fini_[lindex $tar($i,mods) $j]"
        set newproc  "n_new_[lindex $tar($i,mods) $j]"
        set versproc "n_version_[lindex $tar($i,mods) $j]"
        puts $cid "extern \"C\" bool $initproc (nClass *, nKernelServer *);"
        puts $cid "extern \"C\" void $finiproc (void);"
        puts $cid "extern \"C\" void *$newproc (void);"
        puts $cid "extern \"C\" char *$versproc (void);"
    }
    puts $cid "extern \"C\" void N_EXPORT n_addmodules(nKernelServer *);"
    puts $cid "extern \"C\" void N_EXPORT n_remmodules(nKernelServer *);"
    puts $cid "void N_EXPORT n_addmodules(nKernelServer *ks)"
    puts $cid "\{"
    for {set j 0} {$j < [llength $tar($i,mods)]} {incr j} {
        set name [lindex $tar($i,mods) $j]
        set initproc "n_init_[lindex $tar($i,mods) $j]"
        set finiproc "n_fini_[lindex $tar($i,mods) $j]"
        set newproc  "n_new_[lindex $tar($i,mods) $j]"
        set versproc "n_version_[lindex $tar($i,mods) $j]"
        puts $cid "    ks->AddModule(\"$name\",$initproc,$finiproc,$newproc,$versproc);"
    }
    puts $cid "\}"
    puts $cid "void N_EXPORT n_remmodules(nKernelServer *)"
    puts $cid "\{"
    puts $cid "\}"
    puts $cid "//----------------------------------------------------------"
    puts $cid "// EOF"
    puts $cid "//----------------------------------------------------------"
    close $cid
}

#====================================================================
#   Include generator functions for GNU Make and Visual Studio
#   Workspace files.
#====================================================================
source $farwest_home/bin/makeunix.tcl
source $farwest_home/bin/makedsw.tcl

#--------------------------------------------------------------------
#   EOF
#--------------------------------------------------------------------

