home *** CD-ROM | disk | FTP | other *** search
/ H4CK3R 5 / hacker05 / 05_HACK_05.ISO / programacao / freewrap / TCLLIBsampleApp.exe / sample / tcllib / tcllib1.0 / csv / csv.tcl next >
Encoding:
Text File  |  2001-08-17  |  7.1 KB  |  276 lines

  1. # csv.tcl --
  2. #
  3. #    Tcl implementations of CSV reader and writer
  4. #
  5. # Copyright (c) 2001 by Andreas Kupries <a.kupries@westend.com>
  6. #
  7. # See the file "license.terms" for information on usage and redistribution
  8. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  9. # RCS: @(#) $Id: csv.tcl,v 1.4 2001/08/02 16:38:06 andreas_kupries Exp $
  10.  
  11. package require Tcl 8.3
  12. package provide csv 0.1
  13.  
  14. namespace eval ::csv {
  15.     namespace export *
  16. }
  17.  
  18. # ::csv::join --
  19. #
  20. #    Takes a list of values and generates a string in CSV format.
  21. #
  22. # Arguments:
  23. #    values        A list of the values to join
  24. #    sepChar        The separator character, defaults to comma
  25. #
  26. # Results:
  27. #    A string containing the values in CSV format.
  28.  
  29. proc ::csv::join {values {sepChar ,}} {
  30.     set out ""
  31.     set sep {}
  32.     foreach val $values {
  33.     if {[string match "*\[\"$sepChar\]*" $val]} {
  34.         append out $sep\"[string map [list \" \"\"] $val]\" ; # "
  35.     } else {
  36.         append out $sep$val
  37.     }
  38.     set sep $sepChar
  39.     }
  40.     return $out
  41. }
  42.  
  43. # ::csv::joinlist --
  44. #
  45. #    Takes a list of lists of values and generates a string in CSV
  46. #    format. Each item in the list is made into a single CSV
  47. #    formatted record in the final string, the records being
  48. #    separated by newlines.
  49. #
  50. # Arguments:
  51. #    values        A list of the lists of the values to join
  52. #    sepChar        The separator character, defaults to comma
  53. #
  54. # Results:
  55. #    A string containing the values in CSV format, the records
  56. #    separated by newlines.
  57.  
  58. proc ::csv::joinlist {values {sepChar ,}} {
  59.     set out ""
  60.     foreach record $values {
  61.     append out "[join $record]\n"
  62.     }
  63.     return $out
  64. }
  65.  
  66. # ::csv::read2matrix --
  67. #
  68. #    A wrapper around "::csv::split2matrix" reading CSV formatted
  69. #    lines from the specified channel and adding it to the given
  70. #    matrix.
  71. #
  72. # Arguments:
  73. #    m        The matrix to add the read data too.
  74. #    chan        The channel to read from.
  75. #    sepChar        The separator character, defaults to comma
  76. #
  77. # Results:
  78. #    A list of the values in 'line'.
  79.  
  80. proc ::csv::read2matrix {chan m {sepChar ,}} {
  81.     while {![eof $chan]} {
  82.     if {[gets $chan line] < 0} {continue}
  83.     if {$line == {}} {continue}
  84.     split2matrix $m $line $sepChar
  85.     }
  86.     return
  87. }
  88.  
  89. # ::csv::read2queue --
  90. #
  91. #    A wrapper around "::csv::split2queue" reading CSV formatted
  92. #    lines from the specified channel and adding it to the given
  93. #    queue.
  94. #
  95. # Arguments:
  96. #    q        The queue to add the read data too.
  97. #    chan        The channel to read from.
  98. #    sepChar        The separator character, defaults to comma
  99. #
  100. # Results:
  101. #    A list of the values in 'line'.
  102.  
  103. proc ::csv::read2queue {chan q {sepChar ,}} {
  104.     while {![eof $chan]} {
  105.     if {[gets $chan line] < 0} {continue}
  106.     if {$line == {}} {continue}
  107.     split2queue $q $line $sepChar
  108.     }
  109.     return
  110. }
  111.  
  112. # ::csv::report --
  113. #
  114. #    A report command which can be used by the matrix methods
  115. #    "format-via" and "format2chan-via". For the latter this
  116. #    command delegates the work to "::csv::writematrix". "cmd" is
  117. #    expected to be either "printmatrix" or
  118. #    "printmatrix2channel". The channel argument, "chan", has to
  119. #    be present for the latter and must not be present for the first.
  120. #
  121. # Arguments:
  122. #    cmd        Either 'printmatrix' or 'printmatrix2channel'
  123. #    matrix        The matrix to format.
  124. #    args        0 (chan): The channel to write to
  125. #
  126. # Results:
  127. #    None for 'printmatrix2channel', else the CSV formatted string.
  128.  
  129. proc ::csv::report {cmd matrix args} {
  130.     switch -exact -- $cmd {
  131.     printmatrix {
  132.         if {[llength $args] > 0} {
  133.         return -code error "wrong # args: ::csv::report printmatrix matrix"
  134.         }
  135.         return [joinlist [$matrix get rect 0 0 end end]]
  136.     }
  137.     printmatrix2channel {
  138.         if {[llength $args] != 1} {
  139.         return -code error "wrong # args: ::csv::report printmatrix2channel matrix chan"
  140.         }
  141.         writematrix $matrix [lindex $args 0]
  142.         return ""
  143.     }
  144.     default {
  145.         return -code error "Unknown method $cmd"
  146.     }
  147.     }
  148. }
  149.  
  150. # ::csv::split --
  151. #
  152. #    Split a string according to the rules for CSV processing.
  153. #    This assumes that the string contains a single line of CSVs
  154. #
  155. # Arguments:
  156. #    line        The string to split
  157. #    sepChar        The separator character, defaults to comma
  158. #
  159. # Results:
  160. #    A list of the values in 'line'.
  161.  
  162. proc ::csv::split {line {sepChar ,}} {
  163.     regsub -all -- {(\A\"|\"\Z)} $line \0 line
  164.     set line [string map [list $sepChar\"\"\" $sepChar\0\" \
  165.         \"\"\"$sepChar \"\0$sepChar \
  166.         \"\" \" \" \0 ] $line]
  167.     set end 0
  168.     while {[regexp -indices -start $end -- {(\0)[^\0]*(\0)} $line -> start end]} {
  169.     set start [lindex $start 0]
  170.     set end   [lindex $end 0]
  171.     set range [string range $line $start $end]
  172.     set first [string first $sepChar $range]
  173.     if {$first >= 0} {
  174.         set line [string replace $line $start $end \
  175.             [string map [list $sepChar \1] $range]]
  176.     }
  177.     incr end
  178.     }
  179.     set line [string map [list $sepChar \0 \1 $sepChar \0 {} ] $line]
  180.     return [::split $line \0]
  181. }
  182.  
  183. # ::csv::split2matrix --
  184. #
  185. #    Split a string according to the rules for CSV processing.
  186. #    This assumes that the string contains a single line of CSVs.
  187. #    The resulting list of values is appended to the specified
  188. #    matrix, as a new row. The code assumes that the matrix provides
  189. #    the same interface as the queue provided by the 'struct'
  190. #    module of tcllib, "add row" in particular.
  191. #
  192. # Arguments:
  193. #    m        The matrix to write the resulting list to.
  194. #    line        The string to split
  195. #    sepChar        The separator character, defaults to comma
  196. #
  197. # Results:
  198. #    A list of the values in 'line', written to 'q'.
  199.  
  200. proc ::csv::split2matrix {m line {sepChar ,}} {
  201.     $m add row [split $line $sepChar]
  202.     return
  203. }
  204.  
  205. # ::csv::split2queue --
  206. #
  207. #    Split a string according to the rules for CSV processing.
  208. #    This assumes that the string contains a single line of CSVs.
  209. #    The resulting list of values is appended to the specified
  210. #    queue, as a single item. IOW each item in the queue represents
  211. #    a single CSV record. The code assumes that the queue provides
  212. #    the same interface as the queue provided by the 'struct'
  213. #    module of tcllib, "put" in particular.
  214. #
  215. # Arguments:
  216. #    q        The queue to write the resulting list to.
  217. #    line        The string to split
  218. #    sepChar        The separator character, defaults to comma
  219. #
  220. # Results:
  221. #    A list of the values in 'line', written to 'q'.
  222.  
  223. proc ::csv::split2queue {q line {sepChar ,}} {
  224.     $q put [split $line $sepChar]
  225.     return
  226. }
  227.  
  228. # ::csv::writematrix --
  229. #
  230. #    A wrapper around "::csv::join" taking the rows in a matrix and
  231. #    writing them as CSV formatted lines into the channel.
  232. #
  233. # Arguments:
  234. #    m        The matrix to take the data to write from.
  235. #    chan        The channel to write into.
  236. #    sepChar        The separator character, defaults to comma
  237. #
  238. # Results:
  239. #    None.
  240.  
  241. proc ::csv::writematrix {m chan {sepChar ,}} {
  242.     set n [$m rows]
  243.     for {set r 0} {$r < $n} {incr r} {
  244.     puts $chan [join [$m get row $r] $sepChar]
  245.     }
  246.  
  247.     # Memory intensive alternative:
  248.     # puts $chan [joinlist [m get rect 0 0 end end] $sepChar]
  249.     return
  250. }
  251.  
  252. # ::csv::writequeue --
  253. #
  254. #    A wrapper around "::csv::join" taking the rows in a queue and
  255. #    writing them as CSV formatted lines into the channel.
  256. #
  257. # Arguments:
  258. #    q        The queue to take the data to write from.
  259. #    chan        The channel to write into.
  260. #    sepChar        The separator character, defaults to comma
  261. #
  262. # Results:
  263. #    None.
  264.  
  265. proc ::csv::writequeue {q chan {sepChar ,}} {
  266.     while {[$q size] > 0} {
  267.     puts $chan [join [$q get] $sepChar]
  268.     }
  269.  
  270.     # Memory intensive alternative:
  271.     # puts $chan [joinlist [$q get [$q size]] $sepChar]
  272.     return
  273. }
  274.  
  275.