Lines of
lib/xvfs/xvfs.tcl
from check-in e90770a5a7
that are changed by the sequence of edits moving toward
check-in 32b55a907b:
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" {
e90770a5a7 2019-05-02 74: set data "NULL"
75: set type "XVFS_FILE_TYPE_DIR"
e90770a5a7 2019-05-02 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,"
e90770a5a7 2019-05-02 87: puts "\t\t.data = (unsigned char *) $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} {
104: puts "static struct xvfs_file_data xvfs_${fsName}_data\[\] = \{"
105: }
106:
107: # XXX:TODO: Include hidden files ?
108: foreach file [glob -nocomplain -tails -directory $workingDirectory *] {
109: if {$file in {. ..}} {
110: continue
111: }
112:
113: set inputFile [file join $workingDirectory $file]
114: set outputFile [file join $outputDirectory $file]
115:
116: unset -nocomplain fileInfo
117: catch {
118: file lstat $inputFile fileInfo
119: }
120: if {![info exists fileInfo]} {
121: puts stderr "warning: Unable to access $inputFile, skipping"
122: }
123:
124: if {$fileInfo(type) eq "directory"} {
125: lappend subDirectories $outputFile
126: }
127:
128: processFile $fsName $inputFile $outputFile [array get fileInfo]
129: lappend outputFiles $outputFile
130: }
131:
132: foreach subDirectory $subDirectories {
133: lappend outputFiles {*}[processDirectory $fsName $directory $subDirectory]
134: }
135:
136: if {$isTopLevel} {
137: puts "\};"
e90770a5a7 2019-05-02 138:
e90770a5a7 2019-05-02 139: if {0} {
e90770a5a7 2019-05-02 140: puts ""
e90770a5a7 2019-05-02 141: puts "static <type> xvfs_${fsName}_nameToIndex\[\] = \{"
e90770a5a7 2019-05-02 142: foreach outputFile $outputFiles {
e90770a5a7 2019-05-02 143: puts "\t\"$outputFile\","
e90770a5a7 2019-05-02 144: }
e90770a5a7 2019-05-02 145: puts "\};"
e90770a5a7 2019-05-02 146: }
147: }
148:
149: return $outputFiles
150: }
151:
152: proc ::xvfs::main {argv} {
153: # Main entry point
154: ## 1. Parse arguments
155: if {[llength $argv] % 2 != 0} {
156: lappend argv ""
157: }
158:
159: foreach {arg val} $argv {
160: switch -exact -- $arg {
161: "--help" {
162: printHelp stdout
163: exit 0
164: }
165: "--directory" {
166: set rootDirectory $val
167: }
168: "--name" {
169: set fsName $val
170: }
171: default {
172: printHelp stderr [list "Invalid option: $arg $val"]
173: exit 1
174: }
175: }
176: }
177:
178: ## 2. Validate arguments
179: set errors [list]
180: if {![info exists rootDirectory]} {
181: lappend errors "--directory must be specified"
182: }
183: if {![info exists fsName]} {
184: lappend errors "--name must be specified"
185: }
186:
187: if {[llength $errors] != 0} {
188: printHelp stderr $errors
189: exit 1
190: }
191:
192: ## 3. Start processing directory and producing initial output
e90770a5a7 2019-05-02 193: processDirectory $fsName $rootDirectory
194:
195: set ::xvfs::fsName $fsName
196: set ::xvfs::rootDirectory $rootDirectory
197: }
198:
199: package provide xvfs 1