sum.tcl
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 package require Tcl 8.2;
00019
00020 catch {package require tcllibc};
00021
00022
00023 namespace ::crc {
00024 variable sum_version 1.1.0
00025 namespace export sum
00026
00027 variable uid
00028 if {![info exists uid]} {
00029 uid = 0
00030 }
00031 }
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 ret ::crc::SumSysV (type s , optional seed =0) {
00042 set t $seed
00043 binary scan $s c* r
00044 foreach n $r {
00045 incr t [expr {$n & 0xFF}]
00046 }
00047 return [expr {$t % 0xFFFF}]
00048 }
00049
00050
00051
00052
00053
00054
00055 ret ::crc::SumBsd (type s , optional seed =0) {
00056 set t $seed
00057 binary scan $s c* r
00058 foreach n $r {
00059 set t [expr {($t & 1) ? (($t >> 1) + 0x8000) : ($t >> 1)}]
00060 set t [expr {($t + ($n & 0xFF)) & 0xFFFF}]
00061 }
00062 return $t
00063 }
00064
00065
00066
00067 if {[package provide critcl] != {}} {
00068 namespace ::crc {
00069 critcl::ccommand SumSysV_c {dummy interp objc objv} {
00070 int r = TCL_OK;
00071 unsigned int t = 0;
00072
00073 if (objc < 2 || objc > 3) {
00074 Tcl_WrongNumArgs(interp, 1, objv, "data ?seed?");
00075 return TCL_ERROR;
00076 }
00077
00078 if (objc == 3)
00079 r = Tcl_GetIntFromObj(interp, objv[2], (int *)&t);
00080
00081 if (r == TCL_OK) {
00082 int cn, size;
00083 unsigned char *data;
00084
00085 data = Tcl_GetByteArrayFromObj(objv[1], &size);
00086 for (cn = 0; cn < size; cn++)
00087 t += data[cn];
00088 }
00089
00090 Tcl_SetIntObj(Tcl_GetObjResult(interp), t & 0xFFFF);
00091 return r;
00092 }
00093
00094 critcl::ccommand SumBsd_c {dummy interp objc objv} {
00095 int r = TCL_OK;
00096 unsigned int t = 0;
00097
00098 if (objc < 2 || objc > 3) {
00099 Tcl_WrongNumArgs(interp, 1, objv, "data ?seed?");
00100 return TCL_ERROR;
00101 }
00102
00103 if (objc == 3)
00104 r = Tcl_GetIntFromObj(interp, objv[2], (int *)&t);
00105
00106 if (r == TCL_OK) {
00107 int cn, size;
00108 unsigned char *data;
00109
00110 data = Tcl_GetByteArrayFromObj(objv[1], &size);
00111 for (cn = 0; cn < size; cn++) {
00112 t = (t & 1) ? ((t >> 1) + 0x8000) : (t >> 1);
00113 t = (t + data[cn]) & 0xFFFF;
00114 }
00115 }
00116
00117 Tcl_SetIntObj(Tcl_GetObjResult(interp), t & 0xFFFF);
00118 return r;
00119 }
00120 }
00121 }
00122
00123
00124
00125
00126 if {[info command ::crc::SumBsd_c] == {}} {
00127 interp alias {} ::crc::sum-bsd {} ::crc::SumBsd
00128 } else {
00129 interp alias {} ::crc::sum-bsd {} ::crc::SumBsd_c
00130 }
00131
00132 if {[info command ::crc::SumSysV_c] == {}} {
00133 interp alias {} ::crc::sum-sysv {} ::crc::SumSysV
00134 } else {
00135 interp alias {} ::crc::sum-sysv {} ::crc::SumSysV_c
00136 }
00137
00138
00139
00140
00141
00142 ret ::crc::Pop (type varname , optional nth =0) {
00143 upvar $varname args
00144 set r [lindex $args $nth]
00145 set args [lreplace $args $nth $nth]
00146 return $r
00147 }
00148
00149
00150
00151
00152
00153 ret ::crc::SumTimeout (type token) {
00154 # FRINK: nocheck
00155 variable $token
00156 upvar 0 $token state
00157 set state(error) "operation timed out"
00158 set state(reading) 0
00159 }
00160
00161
00162
00163
00164 ret ::crc::SumChunk (type token , type channel) {
00165 # FRINK: nocheck
00166 variable $token
00167 upvar 0 $token state
00168
00169 if {[eof $channel]} {
00170 fileevent $channel readable {}
00171 set state(reading) 0
00172 }
00173
00174 after cancel $state(after)
00175 set state(after) [after $state(timeout) \
00176 [list [namespace origin SumTimeout] $token]]
00177 set state(result) [$state(algorithm) \
00178 [read $channel $state(chunksize)] \
00179 $state(result)]
00180 }
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194 ret ::crc::sum (type args) {
00195 array set opts [list -filename {} -channel {} -chunksize 4096 \
00196 -timeout 30000 -bsd 1 -sysv 0 -format %u \
00197 algorithm [namespace origin sum-bsd]]
00198 while {[string match -* [set option [lindex $args 0]]]} {
00199 switch -glob -- $option {
00200 -bsd { set opts(-bsd) 1 ; set opts(-sysv) 0 }
00201 -sysv { set opts(-bsd) 0 ; set opts(-sysv) 1 }
00202 -file* { set opts(-filename) [Pop args 1] }
00203 -for* { set opts(-format) [Pop args 1] }
00204 -chan* { set opts(-channel) [Pop args 1] }
00205 -chunk* { set opts(-chunksize) [Pop args 1] }
00206 -time* { set opts(-timeout) [Pop args 1] }
00207 -- { Pop args ; break }
00208 default {
00209 set err [join [lsort [array names opts -*]] ", "]
00210 return -code error "bad option $option:\
00211 must be one of $err"
00212 }
00213 }
00214 Pop args
00215 }
00216
00217 # Set the correct sum algorithm
00218 if {$opts(-sysv)} {
00219 set opts(algorithm) [namespace origin sum-sysv]
00220 }
00221
00222 # If a file was given - open it for binary reading.
00223 if {$opts(-filename) != {}} {
00224 set opts(-channel) [open $opts(-filename) r]
00225 fconfigure $opts(-channel) -translation binary
00226 }
00227
00228 if {$opts(-channel) == {}} {
00229
00230 if {[llength $args] != 1} {
00231 return -code error "wrong # args: should be \
00232 \"sum ?-bsd|-sysv? ?-format string? ?-chunksize size? \
00233 ?-timeout ms? -file name | -channel chan | data\""
00234 }
00235 set r [$opts(algorithm) [lindex $args 0]]
00236
00237 } else {
00238
00239 # Create a unique token for the event handling
00240 variable uid
00241 set token [namespace current]::[incr uid]
00242 upvar #0 $token tok
00243 array set tok [list reading 1 result 0 timeout $opts(-timeout) \
00244 chunksize $opts(-chunksize) \
00245 algorithm $opts(algorithm)]
00246 set tok(after) [after $tok(timeout) \
00247 [list [namespace origin SumTimeout] $token]]
00248
00249 fileevent $opts(-channel) readable \
00250 [list [namespace origin SumChunk] $token $opts(-channel)]
00251 vwait [subst $token](reading)
00252
00253 # If we opened the channel we must close it too.
00254 if {$opts(-filename) != {}} {
00255 close $opts(-channel)
00256 }
00257
00258 # Extract the result or error message if there was a problem.
00259 set r $tok(result)
00260 if {[info exists tok(error)]} {
00261 return -code error $tok(error)
00262 }
00263
00264 unset tok
00265 }
00266
00267 return [format $opts(-format) $r]
00268 }
00269
00270
00271
00272 package provide sum $::crc::sum_version
00273
00274
00275
00276
00277
00278
00279