added var function to print out variable values.
[feisty_meow.git] / scripts / core / functions.sh
1 #!/bin/bash
2
3 # This defines some general, useful functions.
4
5 # test whether we've been here before or not.
6 skip_all=
7 function_sentinel &>/dev/null
8 if [ $? -eq 0 ]; then
9   # there was no error, so we can skip the inits.
10   if [ ! -z "$SHELL_DEBUG" ]; then
11     echo skipping functions.sh because already defined.
12   fi
13   skip_all=yes
14 fi
15
16 if [ -z "$skip_all" ]; then
17   if [ ! -z "$SHELL_DEBUG" ]; then
18     echo function definitions begin...
19   fi
20   
21   # a handy little method that can be used for date strings.  it was getting
22   # really tiresome how many different ways the script did the date formatting.
23   function date_stringer() {
24     local sep="$1"; shift
25     if [ -z "$sep" ]; then sep='_'; fi
26     date +"%Y$sep%m$sep%d$sep%H%M$sep%S" | tr -d '/\n/'
27   }
28   
29   # makes a directory of the name specified and then tries to change the
30   # current directory to that directory.
31   function mcd() {
32     if [ ! -d "$1" ]; then mkdir -p "$1"; fi
33     cd "$1"
34   }
35
36   # displays the value of a variable in bash friendly format.
37   function var() {
38     local varname="$1"; shift
39     if [ -z "${!varname}" ]; then
40       echo "$varname undefined"
41     else
42       echo "$varname=${!varname}"
43     fi
44   }
45
46   function success_sound()
47   {
48     if [ ! -z "$CLAM_FINISH_SOUND" ]; then
49       bash $FEISTY_MEOW_SCRIPTS/multimedia/sound_play.sh "$CLAM_FINISH_SOUND"
50     fi
51   }
52
53   function error_sound()
54   {
55     if [ ! -z "$CLAM_ERROR_SOUND" ]; then
56       bash $FEISTY_MEOW_SCRIPTS/multimedia/sound_play.sh "$CLAM_ERROR_SOUND"
57     fi
58   }
59
60   # checks the result of the last command that was run, and if it failed,
61   # then this complains and exits from bash.  the function parameters are
62   # used as the message to print as a complaint.
63   function check_result()
64   {
65     if [ $? -ne 0 ]; then
66       echo -e "failed on: $*"
67       error_sound
68       exit 1
69     fi
70   }
71
72   # locates a process given a search pattern to match in the process list.
73   function psfind() {
74     local PID_DUMP="$(mktemp "$TMP/zz_pidlist.XXXXXX")"
75     local PIDS_SOUGHT=()
76     local patterns=($*)
77     if [ "$OS" == "Windows_NT" ]; then
78       # needs to be a windows format filename for 'type' to work.
79       if [ ! -d c:/tmp ]; then
80         mkdir c:/tmp
81       fi
82       # windows7 magical mystery tour lets us create a file c:\\tmp_pids.txt, but then it's not really there
83       # in the root of drive c: when we look for it later.  hoping to fix that problem by using a subdir, which
84       # also might be magical thinking from windows perspective.
85       tmppid=c:\\tmp\\pids.txt
86       # we have abandoned all hope of relying on ps on windows.  instead
87       # we use wmic to get full command lines for processes.
88       # this does not exist on windows home edition.  we are hosed if that's
89       # what they insist on testing on.
90       wmic /locale:ms_409 PROCESS get processid,commandline </dev/null >"$tmppid"
91       local flag='/c'
92       if [ ! -z "$(uname -a | grep "^MING" )" ]; then
93         flag='//c'
94       fi
95       # we 'type' the file to get rid of the unicode result from wmic.
96       cmd $flag type "$tmppid" >$PID_DUMP
97       \rm "$tmppid"
98       local CR='\r'  # embedded carriage return.
99       local appropriate_pattern="s/^.*  *\([0-9][0-9]*\)[ $CR]*\$/\1/p"
100       for i in "${patterns[@]}"; do
101         PIDS_SOUGHT+=$(cat $PID_DUMP \
102           | grep -i "$i" \
103           | sed -n -e "$appropriate_pattern")
104         if [ ${#PIDS_SOUGHT[*]} -ne 0 ]; then
105           # we want to bail as soon as we get matches, because on the same
106           # platform, the same set of patterns should work to find all
107           # occurrences of the genesis java.
108           break;
109         fi
110       done
111     else
112       /bin/ps $extra_flags wuax >$PID_DUMP
113       # pattern to use for peeling off the process numbers.
114       local appropriate_pattern='s/^[-a-zA-Z_0-9][-a-zA-Z_0-9]*  *\([0-9][0-9]*\).*$/\1/p'
115       # remove the first line of the file, search for the pattern the
116       # user wants to find, and just pluck the process ids out of the
117       # results.
118       for i in "${patterns[@]}"; do
119         PIDS_SOUGHT=$(cat $PID_DUMP \
120           | sed -e '1d' \
121           | grep -i "$i" \
122           | sed -n -e "$appropriate_pattern")
123         if [ ${#PIDS_SOUGHT[*]} -ne 0 ]; then
124           # we want to bail as soon as we get matches, because on the same
125           # platform, the same set of patterns should work to find all
126           # occurrences of the genesis java.
127           break;
128         fi
129       done
130     fi
131     if [ ! -z "$PIDS_SOUGHT" ]; then echo "$PIDS_SOUGHT"; fi
132     /bin/rm $PID_DUMP
133   }
134   
135   # finds all processes matching the pattern specified and shows their full
136   # process listing (whereas psfind just lists process ids).
137   function psa() {
138     if [ -z "$1" ]; then
139       echo "psa finds processes by pattern, but there was no pattern on the command line."
140       return 1
141     fi
142     p=$(psfind "$1")
143     if [ -z "$p" ]; then
144       # no matches.
145       return 0
146     fi
147     echo ""
148     echo "Processes containing \"$1\"..."
149     echo ""
150     if [ -n "$IS_DARWIN" ]; then
151       unset fuzil_sentinel
152       for i in $p; do
153         # only print the header the first time.
154         if [ -z "$fuzil_sentinel" ]; then
155           ps $i -w -u
156         else
157           ps $i -w -u | sed -e '1d'
158         fi
159         fuzil_sentinel=true
160       done
161     else 
162       # cases besides mac os x's darwin.
163       extra_flags=
164       if [ "$OS" = "Windows_NT" ]; then
165         # special case for windows.
166         extra_flags=-W
167         ps | head -1
168         for curr in $p; do
169           ps $extra_flags | grep "$curr" 
170         done
171       else
172         # normal OSes can handle a nice simple query.
173         ps wu $p
174       fi
175     fi
176   }
177   
178   # an unfortunately similarly named function to the above 'ps' as in process
179   # methods, but this 'ps' stands for postscript.  this takes a postscript file
180   # and converts it into pcl3 printer language and then ships it to the printer.
181   # this mostly makes sense for an environment where one's default printer is
182   # pcl.  if the input postscript causes ghostscript to bomb out, there has been
183   # some good success running ps2ps on the input file and using the cleaned
184   # postscript file for printing.
185   function ps2pcl2lpr() {
186     for $i in $*; do
187       gs -sDEVICE=pcl3 -sOutputFile=- -sPAPERSIZE=letter "$i" | lpr -l 
188     done
189   }
190   
191   function fix_alsa() {
192     sudo /etc/init.d/alsasound restart
193   }
194   
195   # switches from a /X/path form to an X:/ form.  this also processes cygwin paths.
196   function unix_to_dos_path() {
197     # we usually remove dos slashes in favor of forward slashes.
198     if [ ! -z "$SERIOUS_SLASH_TREATMENT" ]; then
199       # unless this flag is set, in which case we force dos slashes.
200       echo "$1" | sed -e 's/\\/\//g' | sed -e 's/\/cygdrive//' | sed -e 's/\/\([a-zA-Z]\)\/\(.*\)/\1:\/\2/' | sed -e 's/\//\\/g'
201     else
202       echo "$1" | sed -e 's/\\/\//g' | sed -e 's/\/cygdrive//' | sed -e 's/\/\([a-zA-Z]\)\/\(.*\)/\1:\/\2/'
203     fi
204   }
205   
206   # switches from an X:/ form to an /X/path form.
207   function dos_to_unix_path() {
208     # we always remove dos slashes in favor of forward slashes.
209     echo "$1" | sed -e 's/\\/\//g' | sed -e 's/\([a-zA-Z]\):\/\(.*\)/\/\1\/\2/'
210   }
211
212   # returns a successful value (0) if this system is debian or ubuntu.
213   function debian_like() {
214     # decide if we think this is debian or ubuntu or a variant.
215     DEBIAN_LIKE=$(if [ ! -z "$(grep -i debian /etc/issue)" \
216         -o ! -z "$(grep -i ubuntu /etc/issue)" ]; then echo 1; else echo 0; fi)
217     if [ $DEBIAN_LIKE -eq 1 ]; then
218       # success; this is debianish.
219       return 0
220     else
221       # this seems like some other OS.
222       return 1
223     fi
224   }
225   
226   # su function: makes su perform a login.
227   # for some OSes, this transfers the X authority information to the new login.
228   function su() {
229     if debian_like; then
230       # debian currently requires the full version which imports X authority
231       # information for su.
232   
233       # get the x authority info for our current user.
234       source $FEISTY_MEOW_SCRIPTS/x_win/get_x_auth.sh
235   
236       if [ -z "$X_auth_info" ]; then
237         # if there's no authentication info to pass along, we just do a normal su.
238         /bin/su -l $*
239       else
240         # under X, we update the new login's authority info with the previous
241         # user's info.
242         (unset XAUTHORITY; /bin/su -l $* -c "$X_auth_info ; export DISPLAY=$DISPLAY ; bash")
243       fi
244     else
245       # non-debian supposedly doesn't need the extra overhead any more.
246       # or at least suse doesn't, which is the other one we've tested on.
247       /bin/su -l $*
248     fi
249   
250     # relabel the console after returning.
251     bash $FEISTY_MEOW_SCRIPTS/tty/label_terminal_with_infos.sh
252   }
253   
254   # sudo function wraps the normal sudo by ensuring we replace the terminal
255   # label if they're doing an su with the sudo.
256   function sudo() {
257     local first_command="$1"
258     /usr/bin/sudo "$@"
259     if [ "$first_command" == "su" ]; then
260       # yep, they were doing an su, but they're back now.
261       bash $FEISTY_MEOW_SCRIPTS/tty/label_terminal_with_infos.sh
262     fi
263   }
264   
265   # trashes the .#blah files that cvs and svn leave behind when finding conflicts.
266   # this kind of assumes you've already checked them for any salient facts.
267   function clean_cvs_junk() {
268     for i in $*; do
269       find $i -follow -type f -iname ".#*" -exec perl $FEISTY_MEOW_SCRIPTS/files/safedel.pl {} ";" 
270     done
271   }
272
273   # overlay for nechung binary so that we can complain less grossly about it when it's missing.
274   function nechung() {
275     local wheres_nechung=$(which nechung 2>/dev/null)
276     if [ -z "$wheres_nechung" ]; then
277       echo "The nechung oracle program cannot be found.  You may want to consider"
278       echo "rebuilding the feisty meow applications with this command:"
279       echo "bash $FEISTY_MEOW_SCRIPTS/generator/bootstrap_build.sh"
280     else
281       $wheres_nechung
282     fi
283   }
284   
285   # recreates all the generated files that the feisty meow scripts use.
286   function regenerate() {
287     bash $FEISTY_MEOW_SCRIPTS/core/bootstrap_shells.sh
288     echo
289     nechung
290   }
291
292   # generates a random password where the first parameter is the number of characters
293   # in the password (default 20) and the second parameter specifies whether to use
294   # special characters (1) or not (0).
295   # found function at http://legroom.net/2010/05/06/bash-random-password-generator
296   function random_password()
297   {
298     [ "$2" == "0" ] && CHAR="[:alnum:]" || CHAR="[:graph:]"
299     cat /dev/urandom | tr -cd "$CHAR" | head -c ${1:-32}
300     echo
301   }
302
303   # a wrapper for the which command that finds items on the path.  some OSes
304   # do not provide which, so we want to not be spewing errors when that
305   # happens.
306   function whichable()
307   {
308     to_find="$1"; shift
309     which which &>/dev/null
310     if [ $? -ne 0 ]; then
311       # there is no which command here.  we produce nothing due to this.
312       echo
313     fi
314     echo $(which $to_find)
315   }
316
317   # copies a set of custom scripts into the proper location for feisty meow
318   # to merge their functions and aliases with the standard set.
319   function recustomize()
320   {
321     user="$1"; shift
322     if [ -z "$user" ]; then
323       # use our default example user if there was no name provided.
324       user=fred
325     fi
326     if [ ! -d "$FEISTY_MEOW_DIR/customizing/$user" ]; then
327       echo "The customization folder provided for $user should be:"
328       echo "  '$FEISTY_MEOW_DIR/customizing/$user'"
329       echo "but that folder does not exist.  Skipping customization."
330       return 1
331     fi
332     regenerate >/dev/null
333     pushd "$FEISTY_MEOW_GENERATED/custom" &>/dev/null
334     local incongruous_files="$(bash "$FEISTY_MEOW_SCRIPTS/files/list_non_dupes.sh" "$FEISTY_MEOW_DIR/customizing/$user" "$FEISTY_MEOW_GENERATED/custom")"
335     if [ ${#incongruous_files} -ge 1 ]; then
336       echo "cleaning unknown older overrides..."
337       perl "$FEISTY_MEOW_SCRIPTS/files/safedel.pl" $incongruous_files
338       echo
339     fi
340     popd &>/dev/null
341     echo "copying custom overrides for $user"
342     mkdir "$FEISTY_MEOW_GENERATED/custom" 2>/dev/null
343     perl "$FEISTY_MEOW_SCRIPTS/text/cpdiff.pl" "$FEISTY_MEOW_DIR/customizing/$user" "$FEISTY_MEOW_GENERATED/custom"
344     regenerate
345   }
346
347   function add_cygwin_drive_mounts() {
348     for i in c d e f g h q z ; do
349       ln -s /cygdrive/$i $i
350     done
351   }
352
353
354   # takes a file to modify, and then it will replace any occurrences of the
355   # pattern provided as the second parameter with the text in the third
356   # parameter.
357   function replace_pattern_in_file()
358   {
359     local file="$1"; shift
360     local pattern="$1"; shift
361     local replacement="$1"; shift
362     if [ -z "$file" -o -z "$pattern" -o -z "$replacement" ]; then
363       echo "replace_pattern_in_file: needs a filename, a pattern to replace, and the"
364       echo "text to replace that pattern with."
365       return 1
366     fi
367     sed -i -e "s%$pattern%$replacement%g" "$file"
368   }
369
370   ##############
371
372   function function_sentinel() { return 0; }
373   
374   if [ ! -z "$SHELL_DEBUG" ]; then echo function definitions end....; fi
375   
376 fi
377