1# Copyright (C) 1999-2000 Jean-Claude Wippler <jcw@equi4.com>
2#
3# MetaKit file show utility
4
5proc dumpView {db view {prop ""}} {
6    array set fields {}
7    set desc {}
8    set work {}
9
10        # a property list of the form "-file" causes reading from file
11    if {[regexp {^-(.*)} $prop - file]} {
12        if {$file == ""} { set fd stdin } else { set fd [open $file] }
13        set prop {}
14        while {[gets $fd line] >= 0} {
15            lappend prop $line
16        }
17        if {$file != ""} { close $fd }
18    }
19
20        # set up datatypes, build property list if none given
21    foreach name [mk::view info $db.$view] {
22        if {![regexp {^(.*):(.)} $name - name type]} {
23            set type S
24        }
25        switch $type {
26            M       { set format {fn:(%db)} }
27            V       { set format {s:[#%d]} }
28            default { set format f }
29        }
30        set fields($name) $format
31       	lappend desc $name
32    }
33
34    	# expand all fields if there is an empty entry
35    set n [lsearch -exact $prop ""]
36    if {$prop == "" || $n >= 0} {
37    	set prop [eval lreplace [list $prop] $n $n $desc]
38    }
39
40        # split off commands and formatting details into a work list
41    foreach name $prop {
42        if {![regexp {^([^/]*)/(.*)} $name - name actions]} {
43            set actions ""
44        }
45        if {$actions == "" && [info exists fields($name)]} {
46            set actions $fields($name)
47        }
48        if {![regexp {^([^:]*):(.*)} $actions - actions format]} {
49            set format ""
50        }
51        lappend work $name [split $actions ""] $format
52    }
53
54        # go through each row in the view
55    mk::loop c $db.$view {
56        set r {}
57        foreach {s a f} $work {
58            set gmt 0
59            foreach x $a {
60                switch -- $x {
61
62                    f { set s [mk::get $c $s] }
63                    n { set s [string length $s] }
64                    s { set s [mk::view size $c.$s] }
65
66                    g { set gmt [expr {1-$gmt}] }
67                    d { set s [clock format $s -format {%Y/%m/%d} -gmt $gmt] }
68                    t { set s [clock format $s -format {%H:%M:%S} -gmt $gmt] }
69
70                    k { set s [expr {($s+1023)/1024}] }
71                    x { binary scan $s H* s }
72                    h { set s [join [hexDump $s] \n] }
73
74                    z { package require Trf; set s [zip -mode d $s] }
75                    b { package require Trf; set s [bz2 -mode d $s] }
76
77                    l { puts $r; set r {} }
78
79                    i { set s [mk::cursor pos c] }
80					p { set s $desc }
81					v { set s $view }
82                }
83            }
84            if {$f != ""} {
85                set s [format $f $s]
86            }
87            lappend r $s
88        }
89        if {[llength $r] > 0} {
90            puts [join $r "  "]
91        }
92    }
93}
94
95proc hexDump {s} {
96	set r {}
97	set n [string length $s]
98	for {set i 0} {$i < $n} {incr i 16} {
99		set t [string range $s $i [expr {$i + 15}]]
100		regsub -all {[^ -~]} $t {.} u
101		binary scan $t H* t
102		lappend r [format {%8d:  %-32s  %-16s} $i $t $u]
103	}
104	return $r
105}
106
107set USAGE "  Usage: mkshow file view ?prop ...?
108
109    file    is the name of the MetaKit datafile
110    view    is a view or subview description (e.g. 'view/123.subview')
111    prop    lists of properties (all if omitted, from file if '-file')
112
113  The properties may not contain a ':X' type specifier, but they may
114  contain a list of action specifiers (i.e. 'prop/abc...').  Each is
115  applied to the result so far.  An optional ':...' introduces a format.
116  An empty argument is expanded to the list of all fields in the view.
117
118  Examples:
119    mkshow file view                 -- one line per row, all properties
120    mkshow file view /i:%5d: \"\"      -- prefix each line with the row #
121    mkshow file view :blah \"\" /l     -- dump each row as a Tcl command
122    mkshow file view name:%-12s      -- just the name, left, fixed width
123    mkshow file view name/fz:%.100s  -- unzip, then show first 100 chars
124    mkshow file view date/fd date/ft -- show field as date and as time
125
126  For a description of all actions specifiers, type 'mkshow -actions'.
127"
128
129set ACTIONS "  Action codes available in mkshow:
130
131    f   fetch the property value (this is usually the first action)
132    n   returns size of the property value (default for :B and :M)
133    s   returns the number of rows in the subview
134
135    g   set gmt mode for following 'd' and 't' actions
136    d   converts int seconds to a YYYY/MM/DD value
137    t   converts int seconds to a HH:MM:SS value
138
139    k   convert int value to 'kilo' (i.e. '(N+1023)/1024')
140    x   convert string value to hexadecimal form
141    h	convert string value to a pretty-printed hex dump
142
143    z   uncompress string value using Trf's zip
144    b   uncompress string value using Trf's bz2
145
146    i   returns the row number (used without property, i.e. '/i:%5d:')
147    p	returns list of all properties (used without property: '/p')
148    v	returns the input view path (used without property: '/v')
149
150    l   generate output in Tcl list format (must be last arg: '/l')
151    :   the remainder of this argument specifies a format string
152"
153
154if {[llength $argv] < 2} {
155	switch -glob -- [lindex $argv 0] {
156		-a*		{ puts stderr $ACTIONS }
157		default { puts stderr $USAGE }
158    }
159    exit 1
160}
161
162set file [lindex $argv 0]
163set view [lindex $argv 1]
164set prop [lrange $argv 2 end]
165
166mk::file open db $file -readonly
167
168dumpView db $view $prop
169