Lines of
lib/xvfs/xvfs.tcl
from check-in 47dcf5fc27
that are changed by the sequence of edits moving toward
check-in 303b2de493:
1: #! /usr/bin/env tclsh
2:
3: namespace eval ::xvfs {}
4:
5: # Functions
6: proc ::xvfs::printHelp {channel {errors ""}} {
7: if {[llength $errors] != 0} {
8: foreach error $errors {
9: puts $channel "error: $error"
10: }
11: puts $channel ""
12: }
13: puts $channel "Usage: dir2c \[--help\] --directory <rootDirectory> --name <fsName>"
14: flush $channel
15: }
16:
17: proc ::xvfs::sanitizeCString {string} {
18: set output [join [lmap char [split $string ""] {
19: if {![regexp {[A-Za-z0-9./-]} $char]} {
20: binary scan $char H* char
21: set char "\\[format %03o 0x$char]"
22: }
23:
24: set char
25: }] ""]
26:
27: return $output
28: }
29:
30: proc ::xvfs::binaryToCHex {binary {prefix ""} {width 10}} {
31: binary scan $binary H* binary
32: set output [list]
33:
34: set width [expr {$width * 2}]
35: set stopAt [expr {$width - 1}]
36:
37: while {$binary ne ""} {
38: set row [string range $binary 0 $stopAt]
39: set binary [string range $binary $width end]
40:
41: set rowOutput [list]
42: while {$row ne ""} {
43: set value [string range $row 0 1]
44: set row [string range $row 2 end]
45:
46: lappend rowOutput "\\x$value"
47: }
48: set rowOutput [join $rowOutput {}]
49: set rowOutput "${prefix}\"${rowOutput}\""
50: lappend output $rowOutput
51: }
52:
53: if {[llength $output] == 0} {
54: return "${prefix}\"\""
55: }
56:
57: set output [join $output "\n"]
58: }
59:
60: proc ::xvfs::processFile {fsName inputFile outputFile fileInfoDict} {
61: array set fileInfo $fileInfoDict
62:
63: switch -exact -- $fileInfo(type) {
64: "file" {
65: set type "XVFS_FILE_TYPE_REG"
66: set fd [open $inputFile]
67: fconfigure $fd -encoding binary -translation binary -blocking true
68: set data [read $fd]
69: set size [string length $data]
70: set data [string trimleft [binaryToCHex $data "\t\t\t"]]
71: close $fd
72: }
73: "directory" {
74: set data "NULL"
75: set type "XVFS_FILE_TYPE_DIR"
76: set size "0"
77: }
78: default {
79: return -code error "Unable to process $inputFile, unknown type: $fileInfo(type)"
80: }
81: }
82:
83: puts "\t\{"
84: puts "\t\t.name = \"[sanitizeCString $outputFile]\","
85: puts "\t\t.type = $type,"
86: puts "\t\t.size = $size,"
87: puts "\t\t.data = $data"
88: puts "\t\},"
89: }
90:
91: proc ::xvfs::processDirectory {fsName directory {subDirectory ""}} {
92: set subDirectories [list]
93: set outputFiles [list]
94: set workingDirectory [file join $directory $subDirectory]
95: set outputDirectory $subDirectory
96:
97: if {$subDirectory eq ""} {
98: set isTopLevel true
99: } else {
100: set isTopLevel false
101: }
102:
103: if {$isTopLevel} {
47dcf5fc27 2019-05-01 104: puts {
47dcf5fc27 2019-05-01 105: /*
47dcf5fc27 2019-05-01 106: * XXX:TODO: Move this header information
47dcf5fc27 2019-05-01 107: */
47dcf5fc27 2019-05-01 108: #include <unistd.h>
47dcf5fc27 2019-05-01 109: #include <tcl.h>
47dcf5fc27 2019-05-01 110:
47dcf5fc27 2019-05-01 111: typedef enum {
47dcf5fc27 2019-05-01 112: XVFS_FILE_TYPE_REG,
47dcf5fc27 2019-05-01 113: XVFS_FILE_TYPE_DIR
47dcf5fc27 2019-05-01 114: } xvfs_file_type_t;
47dcf5fc27 2019-05-01 115:
47dcf5fc27 2019-05-01 116: typedef Tcl_WideInt xvfs_size_t;
47dcf5fc27 2019-05-01 117:
47dcf5fc27 2019-05-01 118: struct xvfs_file_data {
47dcf5fc27 2019-05-01 119: const char *name;
47dcf5fc27 2019-05-01 120: xvfs_file_type_t type;
47dcf5fc27 2019-05-01 121: xvfs_size_t size;
47dcf5fc27 2019-05-01 122: const unsigned char *data;
47dcf5fc27 2019-05-01 123: };}
124: puts "static struct xvfs_file_data xvfs_${fsName}_data\[\] = \{"
125: }
126:
127: # XXX:TODO: Include hidden files ?
128: foreach file [glob -nocomplain -tails -directory $workingDirectory *] {
129: if {$file in {. ..}} {
130: continue
131: }
132:
133: set inputFile [file join $workingDirectory $file]
134: set outputFile [file join $outputDirectory $file]
135:
136: unset -nocomplain fileInfo
137: catch {
138: file lstat $inputFile fileInfo
139: }
140: if {![info exists fileInfo]} {
141: puts stderr "warning: Unable to access $inputFile, skipping"
142: }
143:
144: if {$fileInfo(type) eq "directory"} {
145: lappend subDirectories $outputFile
146: }
147:
148: processFile $fsName $inputFile $outputFile [array get fileInfo]
149: lappend outputFiles $outputFile
150: }
151:
152: foreach subDirectory $subDirectories {
153: lappend outputFiles {*}[processDirectory $fsName $directory $subDirectory]
154: }
155:
156: if {$isTopLevel} {
157: puts "\};"
158:
159: if {0} {
160: puts ""
161: puts "static <type> xvfs_${fsName}_nameToIndex\[\] = \{"
162: foreach outputFile $outputFiles {
163: puts "\t\"$outputFile\","
164: }
165: puts "\};"
166: }
167: }
168:
169: return $outputFiles
170: }
171:
172: proc ::xvfs::main {argv} {
173: # Main entry point
174: ## 1. Parse arguments
175: if {[llength $argv] % 2 != 0} {
176: lappend argv ""
177: }
178:
179: foreach {arg val} $argv {
180: switch -exact -- $arg {
181: "--help" {
182: printHelp stdout
183: exit 0
184: }
185: "--directory" {
186: set rootDirectory $val
187: }
188: "--name" {
189: set fsName $val
190: }
191: default {
192: printHelp stderr [list "Invalid option: $arg $val"]
193: exit 1
194: }
195: }
196: }
197:
198: ## 2. Validate arguments
199: set errors [list]
200: if {![info exists rootDirectory]} {
201: lappend errors "--directory must be specified"
202: }
203: if {![info exists fsName]} {
204: lappend errors "--name must be specified"
205: }
206:
207: if {[llength $errors] != 0} {
208: printHelp stderr $errors
209: exit 1
210: }
211:
212: ## 3. Start processing directory and producing initial output
213: processDirectory $fsName $rootDirectory
214:
215: set ::xvfs::fsName $fsName
216: set ::xvfs::rootDirectory $rootDirectory
217: }
218:
219: package provide xvfs 1