Posted to tcl by msiism at Tue Jun 12 23:18:11 GMT 2018view raw

  1. #!/bin/bash
  2. #
  3. # VHG
  4. #
  5. # A versatile virtual hourglass
  6. #
  7. # Version 1.0
  8. #
  9. #
  10. # Copyright Michael Siegel 2018
  11. #
  12. # <LICENSE NOTE> (GPL 3)
  13.  
  14. # --- SHELL CONFIGURATION ---
  15.  
  16.  
  17. # --- ENVIRONMENT CHECKS ---
  18.  
  19. # check for sound playing utilities?
  20. # aplay? (WAV)
  21. # mpeg
  22. # ogg
  23.  
  24. # --- VARIABLE DECLARATIONS ---
  25.  
  26. cmd_name="${0##*/}" # Get basename of this script
  27. version="1.0"
  28.  
  29. cmd_info="A versatile virtual hourglass"
  30. use_info="" # Add usage info
  31. help_info="Run '$cmd_name -h' for help"
  32. sw_info="" # Add info on switches
  33. help="$cmd_name $version\n$cmd_info\n\n$use_info\n\n$sw_info"
  34.  
  35. # An array containing all available switches
  36. sw_list=(-h --help -V --version -t --time -m --message -s --sound)
  37. sw_count="${#sw_list[@]}" # Number of elements in $sw_list
  38.  
  39. t= # time value
  40. m= # alarm message (can start with - or --)
  41. # Defining a default message here and using that as an argument to f_alarm in
  42. # Main when no message was set would make more than half of the code in f_alarm
  43. # obsolete. But it's kind of illogical and bad style.
  44. s= # Will be set to 1 if -s is specified so vhg will play a sound on alarm.
  45. # Do not set this to any value. Parameter handling relies on $s being
  46. # not set at the beginning.
  47. s_file=~/.vhg/alarm.wav # Location of alarm sound file (Do not quote, or ~
  48. # won't be expanded.)
  49.  
  50. # --- FUNCTIONS ---
  51.  
  52. function f_t_check {
  53. # Perform string checks on the specified time value and set 't' conditonally
  54.  
  55. local t_spec="$1"
  56.  
  57. if [[ "$t_spec" != +([[:digit:]])*([d|h|m|s]) ]] # Wrong...
  58. # If $1 is NOT one or more (+()) digit(s), optionally followed by one of the
  59. # letters d, h, m or s (*() is "zero or more")
  60. then
  61. printf "$cmd_name: Invalid argument\n" >&2
  62. exit 1
  63. else
  64. t="$t_spec"
  65. fi
  66. }
  67.  
  68. function f_t_conv {
  69. # Convert the specified time value into a word expression that will be used
  70. # as the default alarm message
  71.  
  72. local t_spec="$1"
  73. local t_dig= # Digit part of the specified time
  74. local t_unit= # Unit part of the specified time
  75. local t_be= # Form of be to use in the message (is or are)
  76.  
  77. case "$t_spec" in
  78. *d) # Time specified in days
  79. t_dig="${t_spec%d}" # Get the digit part of the specified time
  80. if [ "$t_dig" -gt 1 ] # If the number is greater than 1
  81. then
  82. t_unit="days"
  83. t_be="are"
  84. else
  85. t_unit="day"
  86. t_be="is"
  87. fi
  88. ;;
  89. *h) # Time specified in hours
  90. t_dig="${t_spec%h}" # Get the digit part of the specified time
  91. if [ "$t_dig" -gt 1 ] # If the number is greater than 1
  92. then
  93. t_unit="hours"
  94. t_be="are"
  95. else
  96. t_unit="hour"
  97. t_be="is"
  98. fi
  99. ;;
  100. *m) # Time specified in minutes
  101. t_dig="${t_spec%m}" # Get the digit part of the specified time
  102. if [ "$t_dig" -gt 1 ] # If the number is greater than 1
  103. then
  104. t_unit="minutes"
  105. t_be="are"
  106. else
  107. t_unit="minute"
  108. t_be="is"
  109. fi
  110. ;;
  111. *s|*) # Time specified in second (30s or 30, for example)
  112. t_dig="${t_spec%s}" # Get the digit part of the specified time
  113. if [ "$t_dig" -gt 1 ] # If the number is greater than 1
  114. then
  115. t_unit="seconds"
  116. t_be="are"
  117. else
  118. t_unit="second"
  119. t_be="is"
  120. fi
  121. ;;
  122. esac
  123.  
  124. printf "$t_dig $t_unit $t_be up!"
  125. }
  126.  
  127. function f_alarm {
  128. # Print an alarm message on the CLI or via Xmessage, conditionally.
  129. # Also play a sound if -s is specified.
  130.  
  131. local m_spec="$m"
  132. local m_default="$(f_t_conv "$t")"
  133.  
  134. if [ ! "$m_spec" ]
  135. then
  136. m_spec="$m_default"
  137. fi
  138.  
  139. if [ "$s" == 1 ]
  140. then
  141. aplay "$s_file" > /dev/null 2>&1 &
  142. # if you don't redirect the output, aplay will print to stdout, bringing
  143. # itself back into the foreground and block the shell until you hit enter
  144. # check for aplay up in the environment checks section
  145. fi
  146.  
  147. # Select output module
  148. if [ "$DISPLAY" ] # If the script is run from X
  149. then
  150. if [ "$(type -p tkbash)" ]
  151. then
  152. ./gui/vhg-tk "$m_spec" # Use tkbash
  153. else
  154. ./gui/vhg-x "$m_spec" # Use Xmessage
  155. fi
  156. else
  157. printf "%s\n" "$cmd_name: $m_spec"
  158. fi
  159. }
  160.  
  161.  
  162. # --- PARAMETER PROCESSING ---
  163.  
  164. # display help content on user fuck-up
  165.  
  166. if [ "$#" == 0 ] # If the script is run without parameters
  167. then
  168. printf "%b\n" "$help"
  169. exit
  170. else
  171. # Process parameters in order of complexity
  172. i="$#"
  173. while [ "$#" -gt 0 ]
  174. do
  175. if [ "$#" -eq "$i" ]
  176. # Process basic switches only if they occur first and let them fall victim to
  177. # general error handling otherwise.
  178. then
  179. case "$1" in
  180. -h|--help)
  181. printf "%b\n" "$help"
  182. exit
  183. ;;
  184. -V|--version)
  185. printf "%s\n" "$cmd_name $version"
  186. exit
  187. ;;
  188. esac
  189. fi
  190. case "$1" in
  191. -s|--sound)
  192. if [ "$s" ] # If 's' has already been set
  193. then
  194. printf "$cmd_name: -s already specified\n" >&2
  195. exit 1
  196. else
  197. shift
  198. s=1
  199. fi
  200. ;;
  201. -t|--time)
  202. if [ "$t" ] # If 't' has already been set
  203. then
  204. printf "$cmd_name: -t already specified\n" >&2
  205. exit 1
  206. else
  207. shift
  208. if [ "$#" -eq 0 ] # If there is no following parameter
  209. then
  210. printf "$cmd_name: Missing argument\n" >&2
  211. # printf "$help_info\n"
  212. exit 1
  213. else
  214. # Check if $1 is a known/valid switch
  215. valid=0
  216. for((c=0; c<"$sw_count"; c++)) # Loop through the array of switches
  217. do
  218. if [ "$1" == "${sw_list[$c]}" ] # If array element matches $1
  219. then
  220. valid=1
  221. break
  222. fi
  223. done
  224. if [ "$valid" == 1 ] # If $1 is a known switch
  225. then
  226. printf "$cmd_name: Missing argument\n" >&2
  227. exit 1
  228. else
  229. f_t_check "$1" # Sets the t variable
  230. shift
  231. fi
  232. fi
  233. fi
  234. ;;
  235. -m|--message)
  236. if [ "$m" ] # If 'm' has already been set
  237. then
  238. printf "$cmd_name: -m already specified\n" >&2
  239. exit 1
  240. else
  241. shift
  242. if [ "$#" -eq 0 ] # If there is no following parameter
  243. then
  244. printf "$cmd_name: Missing argument\n" >&2
  245. exit 1
  246. else
  247. # Check if $1 is a known/valid switch
  248. valid=0
  249. for((c=0; c<"$sw_count"; c++))
  250. do
  251. if [ "$1" == "${sw_list[$c]}" ] # If array element matches $1
  252. then
  253. valid=1
  254. break
  255. fi
  256. done
  257. if [ "$valid" == 1 ]
  258. then
  259. printf "$cmd_name: Missing argument\n" >&2
  260. exit 1
  261. else
  262. m="$1" # Set $1 as the alarm message
  263. shift
  264. fi
  265. fi
  266. fi
  267. ;;
  268. *)
  269. printf "$cmd_name: Invalid argument\n" >&2
  270. # like, e.g., --help sepcified at the second position
  271. exit 1
  272. ;;
  273. esac
  274. done
  275. fi
  276.  
  277. # --- MAIN ---
  278.  
  279. if [ "$t" ]
  280. then
  281. # Run sleep and f_alarm as one job in the background so the shell won't be
  282. # blocked.
  283. sleep "$t" && f_alarm &
  284. # The above will print sth out, bring the job back to the foreground and
  285. # therefore block the shell until the user hits enter.
  286. else # No time value specified
  287. printf "$cmd_name: Missing argument\n" >&2
  288. fi
  289.