| 1 | #///////////////////////////////////////////////////////////////////////////// |
|---|
| 2 | # FILE : bfstring.tcl |
|---|
| 3 | # PURPOSE : This file contains some utility functions for strings manipulation |
|---|
| 4 | # or generation. |
|---|
| 5 | #///////////////////////////////////////////////////////////////////////////// |
|---|
| 6 | |
|---|
| 7 | |
|---|
| 8 | #///////////////////////////////////////////////////////////////////////////// |
|---|
| 9 | proc ListToStr { list {sep {, }} {ant {}} {sig {}} } { |
|---|
| 10 | # |
|---|
| 11 | # PURPOSE: Obtiene un string concatenando los elementos de una lista |
|---|
| 12 | # separándolos entre ellos por <sep>, anteponiendo <ant> y posponiendo |
|---|
| 13 | # <sig> a cada uno de ellos. |
|---|
| 14 | # |
|---|
| 15 | # RETURN: The string created. |
|---|
| 16 | # |
|---|
| 17 | #///////////////////////////////////////////////////////////////////////////// |
|---|
| 18 | set result {} |
|---|
| 19 | set coma {} |
|---|
| 20 | foreach it $list { |
|---|
| 21 | append result $coma $ant $it $sig |
|---|
| 22 | set coma $sep |
|---|
| 23 | } |
|---|
| 24 | return $result |
|---|
| 25 | } |
|---|
| 26 | |
|---|
| 27 | |
|---|
| 28 | #///////////////////////////////////////////////////////////////////////////// |
|---|
| 29 | proc ListToStrStruct {list structure} { |
|---|
| 30 | # |
|---|
| 31 | # PURPOSE: Obtiene un string concatenando los elementos de una lista |
|---|
| 32 | # separándolos sucesivamente según se establezca en el parámetro |
|---|
| 33 | # structure. |
|---|
| 34 | # |
|---|
| 35 | # PARAMETERS: |
|---|
| 36 | # list -> lista con los elementos a concatenar |
|---|
| 37 | # structure -> lista de listas de la forma {n sep ini end} donde: |
|---|
| 38 | # n -> indice cada cuantos elementos separa con sep, ini y end |
|---|
| 39 | # sep -> separador |
|---|
| 40 | # ini -> string a concatenar al principio de cada grupo de elementos |
|---|
| 41 | # end -> string a concatenar al final de cada grupo de elementos |
|---|
| 42 | # |
|---|
| 43 | #///////////////////////////////////////////////////////////////////////////// |
|---|
| 44 | set structureLevel [lindex $structure 0] |
|---|
| 45 | foreach {n sep ini end} $structureLevel { |
|---|
| 46 | set result $ini |
|---|
| 47 | if {[llength $structure] > 1} { |
|---|
| 48 | set newStructure [lrange $structure 1 end] |
|---|
| 49 | set newList [lrange $list 0 [expr $n-1]] |
|---|
| 50 | append result [ListToStrStruct $newList $newStructure] |
|---|
| 51 | for {set i $n} {$i < [llength $list]} {incr i $n} { |
|---|
| 52 | append result $end $sep $ini |
|---|
| 53 | set newList [lrange $list $i [expr $i+$n-1]] |
|---|
| 54 | append result [ListToStrStruct $newList $newStructure] |
|---|
| 55 | } |
|---|
| 56 | } else { |
|---|
| 57 | append result [lindex $list 0] |
|---|
| 58 | for {set i 1} {$i < [llength $list]} {incr i} { |
|---|
| 59 | if {([expr $i % $n ]==0)} { |
|---|
| 60 | append result $end $sep $ini |
|---|
| 61 | } else { |
|---|
| 62 | append result " " |
|---|
| 63 | } |
|---|
| 64 | append result [lindex $list $i] |
|---|
| 65 | } |
|---|
| 66 | } |
|---|
| 67 | append result $end |
|---|
| 68 | } |
|---|
| 69 | return $result |
|---|
| 70 | } |
|---|
| 71 | |
|---|
| 72 | |
|---|
| 73 | #///////////////////////////////////////////////////////////////////////////// |
|---|
| 74 | proc DateTol {date} { |
|---|
| 75 | # |
|---|
| 76 | # PURPOSE: Creates a date string in tol format. e.j. y2002m11d23 |
|---|
| 77 | # |
|---|
| 78 | # PARAMETERS: |
|---|
| 79 | # date: list with at least 3 elements (year month day) |
|---|
| 80 | # |
|---|
| 81 | #///////////////////////////////////////////////////////////////////////////// |
|---|
| 82 | set newDate [FormatDate $date] |
|---|
| 83 | set y [lindex $newDate 0] |
|---|
| 84 | set m [lindex $newDate 1] |
|---|
| 85 | set d [lindex $newDate 2] |
|---|
| 86 | |
|---|
| 87 | return "y${y}m${m}d${d}" |
|---|
| 88 | } |
|---|
| 89 | |
|---|
| 90 | #///////////////////////////////////////////////////////////////////////////// |
|---|
| 91 | proc FormatDate {date} { |
|---|
| 92 | # |
|---|
| 93 | # PURPOSE: Returns a date (list) formated as YYYY MM DD |
|---|
| 94 | # |
|---|
| 95 | # PARAMETERS: |
|---|
| 96 | # date: list with at least 3 elements (year month day) |
|---|
| 97 | # |
|---|
| 98 | #///////////////////////////////////////////////////////////////////////////// |
|---|
| 99 | set year [lindex $date 0] |
|---|
| 100 | set month [lindex $date 1] |
|---|
| 101 | set day [lindex $date 2] |
|---|
| 102 | |
|---|
| 103 | if {[string range $month 0 0] eq 0} { |
|---|
| 104 | set month [string range $month 1 1] |
|---|
| 105 | } |
|---|
| 106 | if {[string range $day 0 0] eq 0} { |
|---|
| 107 | set day [string range $day 1 1] |
|---|
| 108 | } |
|---|
| 109 | return [list $year [format "%02d" $month] [format "%02d" $day]] |
|---|
| 110 | } |
|---|
| 111 | |
|---|
| 112 | #///////////////////////////////////////////////////////////////////////////// |
|---|
| 113 | proc StringMapToWidget {txt} { |
|---|
| 114 | # |
|---|
| 115 | # PURPOSE: Converts and string into a valid name for a widget |
|---|
| 116 | # |
|---|
| 117 | # PARAMETERS: |
|---|
| 118 | # txt: Text origin |
|---|
| 119 | # |
|---|
| 120 | # RETURN: the modified text |
|---|
| 121 | # |
|---|
| 122 | #///////////////////////////////////////////////////////////////////////////// |
|---|
| 123 | string map {" " "" "*" "" "$" ""} [string tolower $txt] |
|---|
| 124 | } |
|---|
| 125 | |
|---|
| 126 | |
|---|
| 127 | #///////////////////////////////////////////////////////////////////////////// |
|---|
| 128 | proc StringReplace {txt old new} { |
|---|
| 129 | # |
|---|
| 130 | # PURPOSE: It replaces in a text the characters indicated by a new text |
|---|
| 131 | # |
|---|
| 132 | # PARAMETERS: |
|---|
| 133 | # txt: Text origin |
|---|
| 134 | # old: Text to replace |
|---|
| 135 | # new: Text to insert |
|---|
| 136 | # |
|---|
| 137 | # RETURN: the modified text |
|---|
| 138 | # |
|---|
| 139 | #///////////////////////////////////////////////////////////////////////////// |
|---|
| 140 | set pos [string first $old $txt] |
|---|
| 141 | while {[expr $pos != -1]} { |
|---|
| 142 | set txt [string replace $txt $pos [expr $pos + [string length $old] - 1] $new] |
|---|
| 143 | incr pos [string length $new] |
|---|
| 144 | set pos [string first $old $txt $pos] |
|---|
| 145 | } |
|---|
| 146 | return $txt |
|---|
| 147 | } |
|---|
| 148 | |
|---|
| 149 | #///////////////////////////////////////////////////////////////////////////// |
|---|
| 150 | proc CheckDateTime { datetime } { |
|---|
| 151 | # |
|---|
| 152 | # PURPOSE: Check if a string has the following formats: |
|---|
| 153 | # yyyy/mm/dd |
|---|
| 154 | # yyyy-mm-dd |
|---|
| 155 | # yyyymmdd |
|---|
| 156 | # HH:MM:SS |
|---|
| 157 | # yyyy/mm/dd:HH:MM:SS |
|---|
| 158 | # yyyy-mm-dd:HH:MM:SS |
|---|
| 159 | # yyyymmdd:HH:MM:SS |
|---|
| 160 | # |
|---|
| 161 | # PARAMETERS: |
|---|
| 162 | # datetime: Text to check |
|---|
| 163 | # |
|---|
| 164 | # RETURN: 1 if parameter is a valid datetime |
|---|
| 165 | # 0 if parameter is not a valid datetime |
|---|
| 166 | # |
|---|
| 167 | #///////////////////////////////////////////////////////////////////////////// |
|---|
| 168 | return [regexp \ |
|---|
| 169 | {((^([0-9]{4})([/-]?)(0[1-9]|1[0-2])([/-]?)(0[1-9]|[12][0-9]|3[01])$)|(^([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$)|(^([0-9]{4})([/-]?)(0[1-9]|1[0-2])([/-]?)(0[1-9]|[12][0-9]|3[01]):([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$))} \ |
|---|
| 170 | $datetime] |
|---|
| 171 | } |
|---|
| 172 | |
|---|
| 173 | #///////////////////////////////////////////////////////////////////////////// |
|---|
| 174 | proc DateToIso8601 { datetime format } { |
|---|
| 175 | # |
|---|
| 176 | # PURPOSE: Get a valid date with / without format from a datetime |
|---|
| 177 | # |
|---|
| 178 | # PARAMETERS: |
|---|
| 179 | # datetime: Text to check |
|---|
| 180 | # format : format to apply |
|---|
| 181 | # |
|---|
| 182 | # RETURN: datetime |
|---|
| 183 | # |
|---|
| 184 | #///////////////////////////////////////////////////////////////////////////// |
|---|
| 185 | regsub {[:h]} $datetime "T" dateT |
|---|
| 186 | |
|---|
| 187 | regsub -all {[/\.ymdis]} $datetime "" iso8601 |
|---|
| 188 | |
|---|
| 189 | set mask 00000101T00:00:00 |
|---|
| 190 | set addmask [string range $mask [string length $iso8601] end] |
|---|
| 191 | |
|---|
| 192 | set res [join "$iso8601 $addmask" ""] |
|---|
| 193 | |
|---|
| 194 | if {$format == ""} { |
|---|
| 195 | return $res |
|---|
| 196 | } else { |
|---|
| 197 | return [clock format [clock scan $res] -format $format] |
|---|
| 198 | } |
|---|
| 199 | |
|---|
| 200 | return $res |
|---|
| 201 | |
|---|
| 202 | } |
|---|
| 203 | |
|---|
| 204 | |
|---|
| 205 | #///////////////////////////////////////////////////////////////////////////// |
|---|
| 206 | proc Ver2Num { version } { |
|---|
| 207 | # |
|---|
| 208 | # PURPUSE: Convert a text that represents a version (separated numbers by '.') |
|---|
| 209 | # to number to be able to make comparisons between versions |
|---|
| 210 | #///////////////////////////////////////////////////////////////////////////// |
|---|
| 211 | set result [Ver2NumGen $version . 4] |
|---|
| 212 | return $result |
|---|
| 213 | } |
|---|
| 214 | |
|---|
| 215 | #///////////////////////////////////////////////////////////////////////////// |
|---|
| 216 | proc Ver2NumGen { version sepVer padVer } { |
|---|
| 217 | # |
|---|
| 218 | # PURPUSE: It turns a chain that represents a version (separated numbers by a |
|---|
| 219 | # separator) number to be able to make comparisons between versions. |
|---|
| 220 | # The maximum number of digitos of the elements of the version can be |
|---|
| 221 | # indicated |
|---|
| 222 | # PARAMETERS: |
|---|
| 223 | # version -> Version in format x.y... |
|---|
| 224 | # sepVer -> Separator of elements within the version |
|---|
| 225 | # padVer -> Maximum number of digitos for a part of version |
|---|
| 226 | #///////////////////////////////////////////////////////////////////////////// |
|---|
| 227 | set setNum [split $version $sepVer] |
|---|
| 228 | set lstNum "" |
|---|
| 229 | foreach item $setNum { |
|---|
| 230 | set itemExt "[string repeat 0 $padVer]$item" |
|---|
| 231 | lappend lstNum \ |
|---|
| 232 | [string range $itemExt [expr [string length $itemExt] - $padVer] \ |
|---|
| 233 | [string length $itemExt]] |
|---|
| 234 | } |
|---|
| 235 | set num [string trimleft [join $lstNum {}] 0] |
|---|
| 236 | if {[string is double $num]} { |
|---|
| 237 | return $num |
|---|
| 238 | } else { |
|---|
| 239 | return 0 |
|---|
| 240 | } |
|---|
| 241 | } |
|---|
| 242 | |
|---|
| 243 | |
|---|
| 244 | #///////////////////////////////////////////////////////////////////////////// |
|---|
| 245 | proc ObtainRelativePath {path referencePath} { |
|---|
| 246 | # |
|---|
| 247 | # PURPOSE: Express an absolute path in relative terms to a referencePath. |
|---|
| 248 | # |
|---|
| 249 | # PARAMETERS: |
|---|
| 250 | # path -> Absolute input path which is to be expressed in relative terms |
|---|
| 251 | # referencePath -> Absolute path to which the expression to be computed |
|---|
| 252 | # refers to |
|---|
| 253 | # |
|---|
| 254 | # If any of the input paths is not absolute an internal fatal error is |
|---|
| 255 | # produced |
|---|
| 256 | # |
|---|
| 257 | # RETURN: |
|---|
| 258 | # It returns a relative path to referencePath if path and |
|---|
| 259 | # referencePath are in the same unit, otherwise it returns path. |
|---|
| 260 | # |
|---|
| 261 | #///////////////////////////////////////////////////////////////////////////// |
|---|
| 262 | # Check if two input paths are absolute ones |
|---|
| 263 | if {[file pathtype $path] != "absolute"} { |
|---|
| 264 | error "$path is not an absolute path" |
|---|
| 265 | } |
|---|
| 266 | if {[file pathtype $referencePath] != "absolute"} { |
|---|
| 267 | error "$referencePath is not an absolute path" |
|---|
| 268 | } |
|---|
| 269 | |
|---|
| 270 | # Check whether the unit is the same for both paths or not |
|---|
| 271 | if {[lindex [file split $path] 0] != \ |
|---|
| 272 | [lindex [file split $referencePath] 0]} { |
|---|
| 273 | # Just return the input path in negative case |
|---|
| 274 | return $path |
|---|
| 275 | } else { |
|---|
| 276 | # Compute the relative way from one to the other |
|---|
| 277 | set sPath [file split $path] |
|---|
| 278 | set sReferencePath [file split $referencePath] |
|---|
| 279 | |
|---|
| 280 | set index 0 |
|---|
| 281 | foreach level $sPath { |
|---|
| 282 | if {[lindex $sPath $index] != [lindex $sReferencePath $index]} { |
|---|
| 283 | break |
|---|
| 284 | } else { |
|---|
| 285 | incr index |
|---|
| 286 | if {$index >= [llength $sReferencePath]} { |
|---|
| 287 | break |
|---|
| 288 | } |
|---|
| 289 | } |
|---|
| 290 | } |
|---|
| 291 | set levelsToClimb [expr [llength $sReferencePath] - $index] |
|---|
| 292 | |
|---|
| 293 | set computedPath {} |
|---|
| 294 | |
|---|
| 295 | if {$levelsToClimb > 0} { |
|---|
| 296 | for {set i 0} {$i < $levelsToClimb} {incr i} { |
|---|
| 297 | lappend computedPath ".." |
|---|
| 298 | } |
|---|
| 299 | } |
|---|
| 300 | |
|---|
| 301 | for {set i $index} {$i < [llength $sPath]} {incr i} { |
|---|
| 302 | lappend computedPath [lindex $sPath $i] |
|---|
| 303 | } |
|---|
| 304 | |
|---|
| 305 | return [eval file join $computedPath] |
|---|
| 306 | } |
|---|
| 307 | } |
|---|