_utils.tcl 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. # Several utility procs for usage in other scripts
  2. # don't export anything, just use it from the namespace,
  3. # because these scripts aren't useful for console users
  4. # and should therefore not be exported to the global
  5. # namespace.
  6. #
  7. # These procs are not specific to anything special,
  8. # they could be useful in any script.
  9. #
  10. # Born to prevent duplication between scripts for common stuff.
  11. namespace eval utils {
  12. proc get_machine_display_name {{machineid ""}} {
  13. if {$machineid eq ""} {
  14. set machineid [machine]
  15. }
  16. if {$machineid eq ""} {
  17. return "<none>"
  18. }
  19. set config_name [${machineid}::machine_info config_name]
  20. return [get_machine_display_name_by_config_name $config_name]
  21. }
  22. proc get_machine_display_name_by_config_name {config_name} {
  23. return [get_display_name_by_config_name $config_name "machines"]
  24. }
  25. proc get_extension_display_name_by_config_name {config_name} {
  26. return [get_display_name_by_config_name $config_name "extensions"]
  27. }
  28. proc get_display_name_by_config_name {config_name type} {
  29. if {[catch {
  30. set names [openmsx_info $type $config_name]
  31. if {$type eq "machines"} {
  32. set keylist [list "manufacturer" "code"]
  33. } elseif {$type eq "extensions"} {
  34. set keylist [list "manufacturer" "code" "name"]
  35. } else {
  36. error "Unsupported type: $type"
  37. }
  38. set arglist [list]
  39. foreach key $keylist {
  40. if [dict exists $names $key] {
  41. set arg [dict get $names $key]
  42. if {$arg ne ""} {
  43. lappend arglist $arg
  44. }
  45. }
  46. }
  47. set result [join $arglist]
  48. # fallback if this didn't give useful results:
  49. if {$result eq ""} {
  50. set result $config_name
  51. }
  52. }]} {
  53. # hmm, XML file probably broken. Fallback:
  54. set result "$config_name (CORRUPT)"
  55. }
  56. return $result
  57. }
  58. proc get_machine_time {{machineid ""}} {
  59. if {$machineid eq ""} {
  60. set machineid [machine]
  61. }
  62. set err [catch {set mtime [${machineid}::machine_info time]}]
  63. if {$err} {
  64. return ""
  65. }
  66. return [format_time $mtime]
  67. }
  68. proc format_time {time} {
  69. format "%02d:%02d:%02d" [expr {int($time / 3600)}] [expr {int($time / 60) % 60}] [expr {int($time) % 60}]
  70. }
  71. proc format_time_subseconds {time} {
  72. format "%02d:%02d.%02d" [expr {int($time / 60)}] [expr {int($time) % 60}] [expr {int(fmod($time,1) * 100)}]
  73. }
  74. proc get_ordered_machine_list {} {
  75. lsort -dictionary [list_machines]
  76. }
  77. proc get_random_number {max} {
  78. expr {floor(rand() * $max)}
  79. }
  80. proc clip {min max val} {
  81. expr {($val < $min) ? $min : (($val > $max) ? $max : $val)}
  82. }
  83. # provides.... file completion. Currently has a small issue: it adds a space at
  84. # after a /, which you need to erase to continue completing
  85. proc file_completion {args} {
  86. set result [list]
  87. foreach i [glob -nocomplain -path [lindex $args end] *] {
  88. if {[file isdirectory $i]} {
  89. append i /
  90. }
  91. lappend result $i
  92. }
  93. return $result
  94. }
  95. # Replaces characters that are invalid in file names on the host OS or
  96. # file system by underscores.
  97. if {$::tcl_platform(platform) eq "windows"
  98. || [string match *-dingux* $::tcl_platform(osVersion)]} {
  99. # Dingux is Linux, but runs on VFAT.
  100. variable _filename_clean_disallowed {[\x00-\x1f\x7f/\\?*:|"<>+\[\]]}
  101. } else {
  102. # UNIX does allow 0x01-0x1f and 0x7f, but we consider them undesirable.
  103. variable _filename_clean_disallowed {[\x00-\x1f\x7f/]}
  104. }
  105. proc filename_clean {path} {
  106. variable _filename_clean_disallowed
  107. return [regsub -all $_filename_clean_disallowed $path _]
  108. }
  109. # Gets you a filename with numbers in it to avoid overwriting
  110. # an existing file with the same name. Especially useful for
  111. # cases with automatically generated filenames
  112. proc get_next_numbered_filename {directory prefix suffix} {
  113. set pattern "${prefix}\[0-9\]\[0-9\]\[0-9\]\[0-9\]${suffix}"
  114. set files [glob -directory $directory -tails -nocomplain $pattern]
  115. if {[llength $files] == 0} {
  116. set num "0001"
  117. } else {
  118. set name [lindex [lsort $files] end]
  119. scan [string range $name [string length $prefix] end] "%4d" n
  120. if {$n == 9999} {
  121. error "Can't create new filename"
  122. }
  123. set num [format "%04d" [expr {$n + 1}]]
  124. }
  125. file join $directory "${prefix}${num}${suffix}"
  126. }
  127. namespace export get_machine_display_name
  128. namespace export get_machine_display_name_by_config_name
  129. namespace export get_extension_display_name_by_config_name
  130. namespace export get_display_name_by_config_name
  131. namespace export get_machine_time
  132. namespace export format_time
  133. namespace export get_ordered_machine_list
  134. namespace export get_random_number
  135. namespace export clip
  136. namespace export file_completion
  137. namespace export filename_clean
  138. namespace export get_next_numbered_filename
  139. } ;# namespace utils
  140. # Don't import in global namespace, these are only useful in other scripts.