Diff

Differences From Artifact [ce5afd32b3]:

To Artifact [4a88bcbca8]:


     1      1   #! /usr/bin/env tclsh
     2      2   
     3      3   if {[llength $argv] != 2} {
     4         -	puts stderr "Usage: dir2c <hashkey> <startdir>"
            4  +	puts stderr "Usage: kitdll <hashkey> <startdir>"
     5      5   
     6      6   	exit 1
     7      7   }
     8      8   
     9      9   set hashkey [lindex $argv 0]
    10     10   set startdir [lindex $argv 1]
    11     11   
................................................................................
    21     21   	}
    22     22   	return $file
    23     23   }
    24     24   
    25     25   proc recursive_glob {dir} {
    26     26   	set children [glob -nocomplain -directory $dir *]
    27     27   
    28         -	set ret [list]
           28  +	set ret [list $dir]
    29     29   	foreach child $children {
    30     30   		unset -nocomplain childinfo
    31     31   		catch {
    32     32   			file stat $child childinfo
    33     33   		}
    34     34   
    35     35   		if {![info exists childinfo(type)]} {
................................................................................
    37     37   		}
    38     38   
    39     39   		if {$childinfo(type) == "directory"} {
    40     40   			foreach add [recursive_glob $child] {
    41     41   				lappend ret $add
    42     42   			}
    43     43   
    44         -			lappend ret $child
    45         -
    46     44   			continue
    47     45   		}
    48     46   
    49     47   		if {$childinfo(type) != "file"} {
    50     48   			continue
    51     49   		}
    52     50   
    53     51   		lappend ret $child
    54     52   	}
    55     53   
    56     54   	return $ret
    57     55   }
    58     56   
    59         -proc dir2c_hash {path} {
    60         -	set h 0
    61         -	set g 0
    62         -
    63         -	for {set idx 0} {$idx < [string length $path]} {incr idx} {
    64         -		binary scan [string index $path $idx] H* char
    65         -		set char "0x$char"
    66         -
    67         -		set h [expr {($h << 4) + $char}]
    68         -		set g [expr {$h & 0xf0000000}]
    69         -		if {$g != 0} {
    70         -			set h [expr {($h & 0xffffffff) ^ ($g >> 24)}]
    71         -		}
    72         -
    73         -		set h [expr {$h & ((~$g) & 0xffffffff)}]
    74         -	}
    75         -
    76         -	return $h
    77         -}
    78         -
           57  +# Convert a string into a C-style binary string
           58  +## XXX: This function needs to be optimized
    79     59   proc stringify {data} {
    80     60   	set ret "\""
    81     61   	for {set idx 0} {$idx < [string length $data]} {incr idx} {
    82     62   		binary scan [string index $data $idx] H* char
    83     63   
    84     64   		append ret "\\x${char}"
    85     65   
................................................................................
    91     71   	set ret [string trim $ret "\n\""]
    92     72   
    93     73   	set ret "\"$ret\""
    94     74   
    95     75   	return $ret
    96     76   }
    97     77   
           78  +# This function must be kept in-sync with the generated C function below
           79  +proc kitdll_hash {path} {
           80  +	set h 0
           81  +	set g 0
           82  +
           83  +	for {set idx 0} {$idx < [string length $path]} {incr idx} {
           84  +		binary scan [string index $path $idx] H* char
           85  +		set char "0x$char"
           86  +
           87  +		set h [expr {($h << 4) + $char}]
           88  +		set g [expr {$h & 0xf0000000}]
           89  +		if {$g != 0} {
           90  +			set h [expr {($h & 0xffffffff) ^ ($g >> 24)}]
           91  +		}
           92  +
           93  +		set h [expr {$h & ((~$g) & 0xffffffff)}]
           94  +	}
           95  +
           96  +	return $h
           97  +}
           98  +
           99  +# Generate list of files to include in output
    98    100   set files [recursive_glob $startdir]
    99    101   
   100         -set cpp_tag "DIR2C_[string toupper $hashkey]"
   101         -set code_tag "dir2c_[string tolower $hashkey]"
          102  +# Insert dummy entry cooresponding to C dummy entry
          103  +set files [linsert $files 0 "__DUMMY__"]
          104  +
          105  +# Produce C89 compatible header
          106  +set cpp_tag "KITDLL_[string toupper $hashkey]"
          107  +set code_tag "kitdll_[string tolower $hashkey]"
   102    108   
   103    109   puts "#ifndef $cpp_tag"
   104    110   puts "#  define $cpp_tag 1"
   105         -puts {#  include <unistd.h>
          111  +puts {
          112  +#  ifdef HAVE_STDC
          113  +#    ifndef HAVE_UNISTD_H
          114  +#      define HAVE_UNISTD_H 1
          115  +#    endif
          116  +#    ifndef HAVE_STRING_H
          117  +#      define HAVE_STRING_H 1
          118  +#    endif
          119  +#  endif
          120  +#  ifdef HAVE_UNISTD_H
          121  +#    include <unistd.h>
          122  +#  endif
          123  +#  ifdef HAVE_STRING_H
          124  +#    include <string.h>
          125  +#  endif
   106    126   
   107         -#  ifndef LOADED_DIR2C_COMMON
   108         -#    define LOADED_DIR2C_COMMON 1
          127  +#  ifndef LOADED_KITDLL_COMMON
          128  +#    define LOADED_KITDLL_COMMON 1
   109    129   
   110    130   typedef enum {
   111         -	DIR2C_FILETYPE_FILE,
   112         -	DIR2C_FILETYPE_DIR
   113         -} dir2c_filetype_t;
          131  +	KITDLL_FILETYPE_FILE,
          132  +	KITDLL_FILETYPE_DIR
          133  +} kitdll_filetype_t;
   114    134   
   115         -struct dir2c_data {
   116         -	const char            *name;
   117         -	unsigned long         index;
   118         -	unsigned long         size;
   119         -	dir2c_filetype_t      type;
   120         -	const unsigned char   *data;
          135  +struct kitdll_data {
          136  +	const char *             name;
          137  +	unsigned long            index;
          138  +	unsigned long            size;
          139  +	kitdll_filetype_t        type;
          140  +	const unsigned char *    data;
   121    141   };
   122    142   
   123         -static unsigned long dir2c_hash(const unsigned char *path) {
          143  +static unsigned long kitdll_hash(const unsigned char *path) {
   124    144   	unsigned long i, h = 0, g = 0;
   125    145   
   126    146   	for (i = 0; path[i]; i++) {
   127    147   		h = (h << 4) + path[i];
   128    148   		g = h & 0xf0000000;
   129    149   		if (g) {
   130    150   			h ^= (g >> 24);
................................................................................
   131    151   		}
   132    152   		h &= ((~g) & 0xffffffffLU);
   133    153   	}
   134    154           
   135    155           return(h);
   136    156   }
   137    157   
   138         -#  endif /* !LOADED_DIR2C_COMMON */}
          158  +#  endif /* !LOADED_KITDLL_COMMON */}
   139    159   puts ""
   140    160   
   141         -puts "static struct dir2c_data ${code_tag}_data\[\] = {"
          161  +puts "static struct kitdll_data ${code_tag}_data\[\] = {"
   142    162   puts "\t{"
   143    163   puts "\t\t.name  = NULL,"
   144    164   puts "\t\t.index = 0,"
   145    165   puts "\t\t.type  = 0,"
   146    166   puts "\t\t.size  = 0,"
   147    167   puts "\t\t.data  = NULL,"
   148    168   puts "\t},"
   149         -puts "\t{"
   150         -puts "\t\t.name  = \"\","
   151         -puts "\t\t.index = 1,"
   152         -puts "\t\t.type  = DIR2C_FILETYPE_DIR,"
   153         -puts "\t\t.size  = 0,"
   154         -puts "\t\t.data  = NULL,"
   155         -puts "\t},"
   156         -for {set idx 0} {$idx < [llength $files]} {incr idx} {
          169  +for {set idx 1} {$idx < [llength $files]} {incr idx} {
   157    170   	set file [lindex $files $idx]
   158    171   	set shortfile [shorten_file $startdir $file]
   159    172   
   160    173   	unset -nocomplain finfo type
   161    174   	file stat $file finfo
   162    175   
   163    176   	switch -- $finfo(type) {
   164    177   		"file" {
   165         -			set type "DIR2C_FILETYPE_FILE"
          178  +			set type "KITDLL_FILETYPE_FILE"
   166    179   			set size $finfo(size)
   167    180   
   168    181   			set fd [open $file]
   169    182   			fconfigure $fd -translation binary
   170    183   			set data [read $fd]
   171    184   			close $fd
   172    185   
   173         -			set data [stringify $data]
          186  +			set data "(unsigned char *) [stringify $data]"
   174    187   		}
   175    188   		"directory" {
   176         -			set type "DIR2C_FILETYPE_DIR"
          189  +			set type "KITDLL_FILETYPE_DIR"
   177    190   			set data "NULL"
   178    191   			set size 0
   179    192   		}
   180    193   	}
   181    194   
   182    195   	puts "\t{"
   183    196   	puts "\t\t.name  = \"$shortfile\","
   184         -	puts "\t\t.index = [expr $idx + 2],"
          197  +	puts "\t\t.index = $idx,"
   185    198   	puts "\t\t.type  = $type,"
   186    199   	puts "\t\t.size  = $size,"
   187    200   	puts "\t\t.data  = $data,"
   188    201   	puts "\t},"
   189    202   }
   190    203   puts "};"
   191    204   puts ""
   192    205   
   193    206   puts "static unsigned long ${code_tag}_lookup_index(const char *path) {"
   194         -puts "\tswitch (dir2c_hash(path)) {"
   195         -puts "\t\tcase [dir2c_hash {}]:"
   196         -puts "\t\t\treturn(1);"
          207  +puts "\tswitch (kitdll_hash((unsigned char *) path)) {"
   197    208   
   198         -set seenhashes [list]
   199         -for {set idx 0} {$idx < [llength $files]} {incr idx} {
          209  +for {set idx 1} {$idx < [llength $files]} {incr idx} {
   200    210   	set file [lindex $files $idx]
   201    211   	set shortfile [shorten_file $startdir $file]
   202         -	set hash [dir2c_hash $shortfile]
          212  +	set hash [kitdll_hash $shortfile]
   203    213   
   204         -	if {[lsearch -exact $seenhashes $hash] != -1} {
   205         -		puts stderr "ERROR: Duplicate hash seen: $file ($hash), aborting"
          214  +	lappend indexes_per_hash($hash) [list $shortfile $idx]
          215  +}
   206    216   
   207         -		exit 1
   208         -	}
   209         -
   210         -	lappend seenhashes $hash
   211         -
          217  +foreach {hash idx_list} [array get indexes_per_hash] {
   212    218   	puts "\t\tcase $hash:"
   213         -	puts "\t\t\treturn([expr $idx + 2]);"
          219  +
          220  +	if {[llength $idx_list] == 1} {
          221  +		set idx [lindex $idx_list 0 1]
          222  +
          223  +		puts "\t\t\treturn($idx);"
          224  +	} else {
          225  +		foreach idx_ent $idx_list {
          226  +			set shortfile [lindex $idx_ent 0]
          227  +			set idx [lindex $idx_ent 1]
          228  +
          229  +			puts "\t\t\tif (strcmp(path, \"$shortfile\") == 0) return($idx);"
          230  +		}
          231  +		puts "\t\t\tbreak;"
          232  +	}
   214    233   }
   215    234   
   216    235   puts "\t}"
   217    236   puts "\treturn(0);"
   218    237   puts "}"
   219    238   puts ""
   220    239   
   221         -puts "static struct dir2c_data *${code_tag}_getData(const char *path) {"
   222         -puts "\tunsigned long index;"
          240  +puts "static struct kitdll_data *${code_tag}_getData(const char *path, unsigned long index) {"
          241  +puts "\tif (path != NULL) {"
          242  +puts "\t\tindex = ${code_tag}_lookup_index(path);"
          243  +puts "\t}"
   223    244   puts ""
   224         -puts "\tindex = ${code_tag}_lookup_index(path);"
   225    245   puts "\tif (index == 0) {"
   226    246   puts "\t\treturn(NULL);"
   227    247   puts "\t}"
          248  +puts ""
          249  +puts "\tif (path != NULL) {"
          250  +puts "\t\tif (strcmp(path, ${code_tag}_data\[index\].name) != 0) {"
          251  +puts "\t\t\treturn(NULL);"
          252  +puts "\t\t}"
          253  +puts "\t}"
   228    254   puts ""
   229    255   puts "\treturn(&${code_tag}_data\[index\]);"
   230    256   puts "}"
   231    257   puts ""
          258  +
          259  +puts "static unsigned long ${code_tag}_getChildren(const char *path, unsigned long *outbuf, unsigned long outbuf_count) {"
          260  +puts "\tunsigned long index;"
          261  +puts "\tunsigned long num_children = 0;"
          262  +puts ""
          263  +puts "\tindex = ${code_tag}_lookup_index(path);"
          264  +puts "\tif (index == 0) {"
          265  +puts "\t\treturn(0);"
          266  +puts "\t}"
          267  +puts ""
          268  +puts "\tif (${code_tag}_data\[index\].type != KITDLL_FILETYPE_DIR) {"
          269  +puts "\t\treturn(0);"
          270  +puts "\t}"
          271  +puts ""
          272  +puts "\tif (strcmp(path, ${code_tag}_data\[index\].name) != 0) {"
          273  +puts "\t\treturn(0);"
          274  +puts "\t}"
          275  +puts ""
          276  +puts "\tswitch (index) {"
          277  +
          278  +unset -nocomplain children
          279  +array set children [list]
          280  +for {set idx 1} {$idx < [llength $files]} {incr idx} {
          281  +	set file [lindex $files $idx]
          282  +	set shortfile [shorten_file $startdir $file]
          283  +
          284  +	unset -nocomplain finfo type
          285  +	file stat $file finfo
          286  +
          287  +	if {$finfo(type) != "directory"} {
          288  +		continue;
          289  +	}
          290  +
          291  +	# Determine which children are under this directory
          292  +	## Convert the current pathname to a regular expression that matches exactly
          293  +	set file_regexp [string map [list "\\" "\\\\" "." "\\." "\{" "\\\{" "\}" "\\\}" "*" "\\*"] $file]
          294  +
          295  +	## Search for pathnames which start with exactly our name, followed by a slash
          296  +	## followed by no more slashes (direct descendants)
          297  +	set child_idx_list [lsearch -regexp -all $files "^${file_regexp}/\[^/\]*$"]
          298  +
          299  +	set children($idx) $child_idx_list
          300  +
          301  +	puts "\t\tcase $idx:"
          302  +	puts "\t\t\tnum_children = [llength $child_idx_list];"
          303  +	puts "\t\t\tbreak;"
          304  +	
          305  +}
          306  +
          307  +puts "\t}"
          308  +puts ""
          309  +puts "\tif (outbuf == NULL) {"
          310  +puts "\t\treturn(num_children);"
          311  +puts "\t}"
          312  +puts ""
          313  +puts "\tif (num_children > outbuf_count) {"
          314  +puts "\t\tnum_children = outbuf_count;"
          315  +puts "\t}"
          316  +puts ""
          317  +puts "\tif (num_children == 0) {"
          318  +puts "\t\treturn(num_children);"
          319  +puts "\t}"
          320  +puts ""
          321  +puts "\tif (outbuf_count > num_children) {"
          322  +puts "\t\toutbuf_count = num_children;"
          323  +puts "\t}"
          324  +puts ""
          325  +puts "\tswitch (index) {"
          326  +
          327  +foreach {idx child_idx_list} [array get children] {
          328  +	if {[llength $child_idx_list] == 0} {
          329  +		continue
          330  +	}
          331  +
          332  +	puts "\t\tcase $idx:"
          333  +	puts "\t\t\tswitch(outbuf_count) {"
          334  +
          335  +	for {set child_idx_idx [expr {[llength $child_idx_list] - 1}]} {$child_idx_idx >= 0} {incr child_idx_idx -1} {
          336  +		set child_idx [lindex $child_idx_list $child_idx_idx]
          337  +
          338  +		puts "\t\t\t\tcase [expr {$child_idx_idx + 1}]:"
          339  +		puts "\t\t\t\t\toutbuf\[$child_idx_idx\] = $child_idx;"
          340  +	}
          341  +
          342  +	puts "\t\t\t}"
          343  +
          344  +	puts "\t\t\tbreak;"
          345  +}
          346  +
          347  +puts "\t}"
          348  +puts ""
          349  +puts "\treturn(num_children);"
          350  +puts "}"
          351  +puts ""
   232    352   
   233    353   puts "#endif /* !$cpp_tag */"