1 #!/bin/bash
   2 #
   3 # /home/lantw44/.bash_include
   4 #
   5 # vim: ts=4 sw=4 noet:
   6 #
   7 # -- UTF-8 --
   8 #
   9 # 設定用外部檔案:
  10 #     (1) 若 .bash_title 存在且未設定自動修改視窗標題,則依照本檔案內定規則修改
  11 #     (2) 若 .bash_addps 存在,則第一行的的內容會加到 colorprompting 變數,第二
  12 #         行的內容會加到 nocolorprompting 變數
  13 
  14 if [[ "$-" == *i* ]] ; then interactive_shell=1; fi
  15 
  16 [ "$interactive_shell" ] && echo "Running .bash_include"
  17 [ "$interactive_shell" ] && default_tty_setting="`stty -g`"
  18 [ "$interactive_shell" ] && TTY="`tty`" && \
  19     if [[ "$TTY" =~ "/dev/tty"[0-9]+ ]]; then
  20         tty_short="#v${TTY:8}"
  21     elif [[ "$TTY" == "/dev/tty"* ]]; then
  22         tty_short="#${TTY:8}"
  23     elif [[ "$TTY" == "/dev/pty"* ]]; then
  24         tty_short="#p${TTY:8}"
  25     elif [[ "$TTY" == "/dev/hvc"* ]]; then
  26         tty_short="#h${TTY:8}"
  27     elif [[ "$TTY" == "/dev/pts"* ]]; then
  28         tty_short="#p${TTY:9}"
  29     elif [[ "$TTY" == "/dev/console" ]]; then
  30         tty_short="#c${TTY:12}"
  31     else
  32         unset tty_short
  33     fi
  34 
  35 # Internal Variables
  36 
  37 colorprompting='\[\e[1;31m\]\!\[\e[m\] \[\e[35m\]$tty_short\[\e[m\][\[\e[1;33m\]\u\[\e[m\]@\[\e[1;32m\]\h\[\e[m\] \[\e[1;36m\]\w\[\e[m\]]'
  38 nocolorprompting='\! $tty_short[\u@\h \w]'
  39 
  40 if [ "$SSH_CONNECTION" ]
  41 then
  42     colorprompting="\[\e[1;44m\]*\[\e[m\]$colorprompting"
  43     nocolorprompting="*$nocolorprompting"
  44 fi
  45 
  46 if [ "$UNDER_JHBUILD" = "true" ]
  47 then
  48     colorprompting="$colorprompting[\[\e[1;35m\]JHBuild\[\e[m\]]"
  49     nocolorprompting="$nocolorprompting[JHBuild]"
  50 fi
  51 
  52 if [ -f "$HOME/.bash_addps" ]
  53 then
  54     exec 3< "$HOME/.bash_addps"
  55     read -u 3 -r oneline
  56     colorprompting="$oneline $colorprompting"
  57     read -u 3 -r oneline
  58     nocolorprompting="$oneline $nocolorprompting"
  59     exec 3<&-
  60     unset oneline
  61 fi
  62 
  63 colorprompting="${colorprompting}"'\[\e[41;37m\]$lasterror\[\e[m\]'
  64 nocolorprompting="${nocolorprompting}"'$lasterror'
  65 
  66 if [ "$WINDOW" ]
  67 then
  68     colorprompting="$colorprompting<$WINDOW>"
  69     nocolorprompting="$nocolorprompting<$WINDOW>"
  70 fi
  71 
  72 if [ "$TMUX_PANE" ]
  73 then
  74     colorprompting="$colorprompting$TMUX_PANE"
  75     nocolorprompting="$nocolorprompting$TMUX_PANE"
  76 fi
  77 
  78 if [[ "$PROMPT_COMMAND" != "S="* ]]; then
  79     if [ "$PROMPT_COMMAND" ]
  80     then
  81         PROMPT_COMMAND="; $PROMPT_COMMAND"
  82     fi
  83     PROMPT_COMMAND='S="$?"; [ "$S" != "0" ] && lasterror="($S)" || unset lasterror'"$PROMPT_COMMAND"
  84 fi
  85 
  86 colorprompting="${colorprompting}"'\$ '
  87 nocolorprompting="${nocolorprompting}"'\$ '
  88 colorsecondprompting="\[\e[36m\]-->\[\e[m\] "
  89 nocolorsecondprompting="--> "
  90 
  91 HISTSIZE=2147483647
  92 HISTFILESIZE=2147483647
  93 HISTCONTROL=ignoredups:ignorespace
  94 HISTTIMEFORMAT="%F %T "
  95 historycountfile="$HOME/.bash_history.count"
  96 historybackupfile="$HOME/.bash_history.bak"
  97 
  98 realpath_program="readlink -f"
  99 bgrunfiledir="$HOME/tmp/bgrun-$USER"
 100 trashdir="$HOME/trash"
 101 
 102 
 103 # Environment Variables
 104 
 105 export EDITOR=vim
 106 export FCEDIT=vim
 107 export VISUAL=vim
 108 export PAGER=less
 109 
 110 
 111 # Aliases
 112 
 113 alias startcolor='PS1=$colorprompting; PS2=$colorsecondprompting'
 114 alias stopcolor='PS1=$nocolorprompting; PS2=$nocolorsecondprompting'
 115 
 116 alias ll='ls -l'
 117 alias grep='grep --color=always'
 118 alias rm='rm -i'
 119 alias cp='cp -pi'
 120 alias mv='mv -i'
 121 alias jobs='jobs -l'
 122 alias less='less -RS'
 123 
 124 alias cccc='LANG=C;LANGUAGE=C;LC_ALL=C'
 125 alias enus='LANG=en_US.UTF-8;LANGUAGE=en_US:en;LC_ALL=en_US.UTF-8'
 126 alias big5='LANG=zh_TW.Big5;LANGUAGE=zh_TW:zh:en;LC_ALL=zh_TW.Big5'
 127 alias zhtw='LANG=zh_TW.UTF-8;LANGUAGE=zh_TW:zh:en;LC_ALL=zh_TW.UTF-8'
 128 
 129 alias savetty='default_tty_setting=`stty -g`'
 130 alias resetty='stty $default_tty_setting'
 131 
 132 alias vimhtml='vim -c "set ts=2" -c "set sw=2"'
 133 alias screen256='screen -T screen-256color'
 134 
 135 alias ndate='date +%H:%M:%S---%A---%x'
 136 alias npasswd="getent passwd | awk 'BEGIN {FS=\":\"} {printf \"%24s%3s%6s%6s %-28s%-18s>> %s\\n\",\$1,\$2,\$3,\$4,\$6,\$7,\$5}' | $PAGER"
 137 alias ngroup="getent group | awk 'BEGIN {FS=\":\"} {printf \"%24s%3s%6s >> %s\\n\",\$1,\$2,\$3,\$4}' | $PAGER"
 138 
 139 
 140 # Functions
 141 
 142 function compile_all ()
 143 {
 144     local noask=0
 145     local mycc="${CC}"
 146     local mycxx="${CXX}"
 147     local myexe="`get_executable_extension`"
 148     local newCFLAGS
 149     local newCXXFLAGS
 150     local newLDFLAGS
 151     [ "$1" = '' ] && echo "Which file(s) do you want to compile? " && return 1
 152     [ "$1" = "-n" ] && noask=1
 153     if [ "$noask" = "0" ]; then
 154         read -e -p "CFLAGS: " -i "$CFLAGS" newCFLAGS
 155         read -e -p "CXXFLAGS: " -i "$CXXFLAGS" newCXXFLAGS
 156         read -e -p "LDFLAGS: " -i "$LDFLAGS" newLDFLAGS
 157         [ "$newCFLAGS" '!=' '' ] && CFLAGS=$newCFLAGS
 158         [ "$newCXXFLAGS" '!=' '' ] && CXXFLAGS=$newCXXFLAGS
 159         [ "$newLDFLAGS" '!=' '' ] && LDFLAGS=$newLDFLAGS
 160     else
 161         shift
 162     fi
 163     [ -z "${mycc}" ] && mycc=cc
 164     [ -z "${mycxx}" ] && mycxx=c++
 165     while [ "$1" '!=' '' ]
 166     do
 167         local targetfile="`echo "$1" | sed 's|\(.*\)\..*|\1|'`$myexe"
 168         local suffix="`echo "$1" | sed 's|.*\.\(.*\)|\1|'`"
 169         if [ -f "$1" ]; then
 170             true
 171         else
 172             printf \
 173             "\e[1;33mWarning\e[0m: $1 Non-existent file or not a regular file\n"
 174             shift ; continue
 175         fi
 176         [ "$targetfile" = "$1" ] && shift && continue
 177         case "$suffix" in
 178             c)
 179                 echo "[${mycc}] $1 -> $targetfile"
 180                 ${mycc} $CFLAGS "$1" $LDFLAGS -o "$targetfile"
 181                 ;;
 182             cpp|cxx|cc|C)
 183                 echo "[${mycxx}] $1 -> $targetfile"
 184                 ${mycxx} $CXXFLAGS "$1" $LDFLAGS -o "$targetfile"
 185                 ;;
 186             *)
 187                 printf "$1: Unknown suffix (\e[1;33mskipped\e[0m)\n"
 188                 ;;
 189         esac
 190         [ "$?" '!=' "0" ] && printf \
 191             '\e[1;31mError\e[0m while compiling file\n'
 192         shift
 193     done
 194     return 0
 195 }
 196 
 197 
 198 function convert_to_html ()
 199 {
 200     while [ "$1" '!=' '' ]
 201     do
 202         for i in "$1"
 203         do
 204             vim $i -c 'set background=dark' \
 205                 -c 'highlight PreProc ctermfg=darkcyan' \
 206                 -c "$BEFORE_CONVERT_TO_HTML" \
 207                 -c "$BEFORE_CONVERT_TO_HTML1" \
 208                 -c "$BEFORE_CONVERT_TO_HTML2" \
 209                 -c TOhtml \
 210                 -c :w \
 211                 -c :qa
 212         done
 213         shift
 214     done
 215 }
 216 
 217 function mkscreenacl ()
 218 {
 219     local screen_permit_command="select windowlist other meta detach reset hardcopy info redisplay lastmsg next prev xon xoff windows suspend help colon copy paste writebuf readbuf displays stuff attach"
 220     while [ "$1" '!=' '' ]
 221     do
 222         for i in $screen_permit_command
 223         do
 224             echo "aclchg $1 +x $i"
 225         done
 226         echo "aclchg $1 -rw \"\#?\""
 227         shift
 228     done
 229 }
 230 
 231 function get_file_size ()
 232 {
 233     split_arguments "$@"
 234     "${prefixlist[@]}" du -s "${arglist[@]}" | {
 235         read -d "   " dirsize
 236         echo "$dirsize"
 237         read throwaway
 238     }
 239     unset arglist
 240     unset prefixlist
 241 }
 242 
 243 ########## Background ##########
 244 
 245 alias bgr=bgrun
 246 alias bgv=bgview
 247 alias bgl=bglist
 248 alias bgc=bgcount
 249 alias bgls=bglist
 250 alias bgrm=bgclean
 251 
 252 function bgrun ()
 253 {
 254     [ "$#" = "0" ] && return 1
 255     [ '!' -d "$bgrunfiledir" ] && createdir_askmode "$bgrunfiledir" 0750
 256     local current_time=`date "+%Y%m%d-%H%M%S"`
 257     local cmdname=`echo "$1" | sed -e 's/-/_/g' -e 's/\\//_/g' -e 's/ /_/g'`
 258     if [ "`echo "$cmdname" | cut -c 1`" = "_" ]
 259     then
 260         cmdname=`echo "$cmdname" | cut -c 2-`
 261     fi
 262     local filename="$bgrunfiledir/$current_time-$cmdname"
 263     echo "Writing to $filename"
 264     {
 265         echo -n "$BASHPID " > "$filename"
 266         echo "$@" >> "$filename"
 267         exec "$@" &>> "$filename"
 268     } &
 269 }
 270 
 271 function bglist ()
 272 {
 273     local viewtime=0
 274     [ "$1" = "--full" ] && viewtime=1
 275     {
 276         for i in `find "$bgrunfiledir" -maxdepth 1 -mindepth 1 | sort`
 277         do
 278             [ "$viewtime" = "1" ] && echo "$i"
 279             head -n 1 "$i" | {
 280                 local procpid
 281                 local cmdline
 282                 read -d ' ' procpid
 283                 read cmdline
 284                 printf "(%5d) %s\n" "$procpid" "$cmdline"
 285             }
 286         done
 287     } | {
 288         if [ "$viewtime" = "1" ]
 289         then
 290             echo " INDEX         TIME          PID   COMMAND"
 291             local readstat=0
 292             local -i i=1
 293             while true
 294             do
 295                 local dateandtime_long
 296                 local cmdline
 297                 read dateandtime_long
 298                 read cmdline
 299                 [ "$?" '!=' "0" ] && break
 300                 local dateandtime=`basename "$dateandtime_long"`
 301                 local part_year="${dateandtime:0:4}"
 302                 local part_month="${dateandtime:4:2}"
 303                 local part_date="${dateandtime:6:2}"
 304                 local part_hour="${dateandtime:9:2}"
 305                 local part_minute="${dateandtime:11:2}"
 306                 local part_second="${dateandtime:13:2}"
 307                 printf '%6d' "$i"
 308                 echo " $part_year-$part_month-$part_date $part_hour:$part_minute:$part_second $cmdline"
 309                 i=$i+1
 310             done
 311         else
 312             echo " INDEX    PID   COMMAND"
 313             cat -n
 314         fi
 315     } | $PAGER
 316 }
 317 
 318 function bgview ()
 319 {
 320     local -i yourchoice
 321     if [ "$1" = "" ]
 322     then
 323         yourchoice=`bgcount`
 324     else
 325         if [ "$1" -le "0" ]
 326         then
 327             yourchoice=$((`bgcount`+$1))
 328         else
 329             yourchoice=$1
 330         fi
 331     fi
 332     echo "Your choice is $yourchoice."
 333     local realfilename=`find "$bgrunfiledir" -maxdepth 1 -mindepth 1 | sort | sed -n ${yourchoice}p`
 334     head -n 1 "$realfilename" | {
 335         read -d ' ' procpid
 336         read cmdline
 337         echo "PID: $procpid"
 338         echo "Command Line: $cmdline"
 339     }
 340     read -e -p "View '$realfilename' ? " confirm
 341     if [ "$confirm" = "n" ] || [ "$confirm" = "N" ]
 342     then
 343         return 1
 344     fi
 345     {
 346         printf "===> Process Information: "
 347         cat "$realfilename"
 348     } | $PAGER
 349 }
 350 
 351 function bgcount ()
 352 {
 353     find "$bgrunfiledir" -maxdepth 1 -mindepth 1 | cut -d - -f 2,3 | wc | awk '{print $2}'
 354 }
 355 
 356 function bgclean ()
 357 {
 358     if [ "$1" = "all" ]
 359     then
 360         echo "Removing the directory $bgrunfiledir"
 361         rm -rf "$bgrunfiledir" &
 362         return 0
 363     else
 364         split_arguments "$@"
 365         local -i i=0
 366         while [ "${arglist[$i]}" ]
 367         do
 368             arglist[$i]="-e ${arglist[$i]}p"
 369             i=$i+1
 370         done
 371         local oneline
 372         find "$bgrunfiledir" -maxdepth 1 -mindepth 1 | sort | sed -n ${arglist[*]} | {
 373             while read oneline
 374             do
 375                 echo "Removing $oneline"
 376                 rm -f "$oneline"
 377             done
 378         }
 379     fi
 380     unset arglist
 381     unset prefixlist
 382 }
 383 
 384 function bgdu ()
 385 {
 386     local -i j=1
 387     {
 388         echo " INDEX     SIZE   PID   COMMAND"
 389         for i in `find "$bgrunfiledir" -maxdepth 1 -mindepth 1 | sort`
 390         do
 391             head -n 1 "$i" | {
 392                 local procpid
 393                 local cmdline
 394                 read -d ' ' procpid
 395                 read cmdline
 396                 printf "%6d %8d (%5d) %s\n" "$j" \
 397                     "`get_file_size "$i"`" \
 398                     "$procpid" "$cmdline"
 399             }
 400             j=$j+1
 401         done
 402     } | $PAGER
 403 }
 404 
 405 ########## Background End ##########
 406 
 407 function check_dmesg ()
 408 {
 409     [ "$#" = "0" ] && return 1
 410 
 411     while true
 412     do
 413         cdm_previous_dmesg_buf="$cdm_current_dmesg_buf"
 414         cdm_current_dmesg_buf="`dmesg`"
 415         [ "$cdm_previous_dmesg_buf" '!=' "$cdm_current_dmesg_buf" ] && \
 416             [ "$cdm_first_run" = "0" ] && \
 417             echo '===> You should check the system message buffer <==='
 418         sleep $1
 419         [ "$?" '!=' "0" ] && return 1
 420         cdm_first_run=0
 421     done
 422 }
 423 
 424 function check_system_status ()
 425 {
 426     [ "$#" = "0" ] && return 1
 427 
 428     filename_mail="$MAIL"
 429     filename_messages="/var/log/messages"
 430     filename_audit="/var/log/audit/audit.log"
 431 
 432     while true
 433     do
 434         previous_dmesg_buf="$current_dmesg_buf"
 435         current_dmesg_buf="`dmesg`"
 436         previous_mail_info="$current_mail_info"
 437         current_mail_info="`ls -l "$filename_mail"`"
 438         previous_messages_info="$current_messages_info"
 439         current_messages_info="`ls -l "$filename_messages"`"
 440         previous_audit_info="$current_audit_info"
 441         current_audit_info="`ls -l "$filename_audit"`"
 442         if [ "$first_run" = "0" ]
 443         then
 444             [ "$previous_dmesg_buf" '!=' "$current_dmesg_buf" ] && echo "===> The system message buffer is modified (dmesg) <==="
 445             [ "$previous_mail_info" '!=' "$current_mail_info" ] && echo "===> Your mailbox $filename_mail is modified <==="
 446             [ "$previous_messages_info" '!=' "$current_messages_info" ] && echo "===> $filename_messages is modified <==="
 447             [ "$previous_audit_info" '!=' "$current_audit_info" ] && echo "===> $filename_audit is modified <==="
 448         fi
 449         sleep $1
 450         first_run=0
 451     done
 452 }
 453 
 454 function prehistory_backup ()
 455 {
 456     echo "Checking your current history file"
 457     local -i currentcount="`wc -l < "$HISTFILE"`"
 458     currentcount="${currentcount/ */}"
 459     [ '!' -f "$historycountfile" ] && touch "$historycountfile"
 460     local -i previoushistorycount="$(< "$historycountfile")"
 461     if [ "$currentcount" -lt "$previoushistorycount" ]
 462     then
 463         printf "\e[1;31mWarning\e[m: Your $HISTFILE may be TRUNCATED OR OVERWRITTEN BY OTHER PROGRAMS!\n"
 464         printf "Note: \e[1;33m$currentcount\e[m < $previoushistorycount\n"
 465         echo "Your $historycountfile and $historybackupfile will not be overwritten until this problem is fixed."
 466         echo " 1. Check your $HISTFILE."
 467         echo " 2. Edit your $HISTFILE manually if some unexpected changes are found."
 468         echo "    (You may need $historybackupfile to do it) "
 469         echo " 3. Remove the file $historycountfile."
 470         echo " 4. Run the command \`prehistory_backup' again."
 471         return 3
 472     fi
 473     echo -n "Backing up your current history file ($previoushistorycount -> $currentcount, "
 474     if [ "$previoushistorycount" = "$currentcount" ]
 475     then
 476         echo "no modification)"
 477     else
 478         echo "+$[$currentcount-$previoushistorycount])"
 479     fi
 480     echo "$currentcount" > "$historycountfile"
 481     command cp -f "$HISTFILE" "$historybackupfile"
 482 }
 483 
 484 ########## Trash Manager ##########
 485 
 486 alias trash_put=trash_mv
 487 alias trash_add=trash_mv
 488 alias trash_list=trash_ls
 489 alias trash_ct=trash_count
 490 alias trash_restore=trash_recover
 491 alias trash_rc=trash_recover
 492 alias trash_drop=trash_rm
 493 alias trash_clean=trash_rm
 494 
 495 function trash_mv ()
 496 {
 497     [ "$#" = "0" ] && return 1
 498     [ '!' -d "$trashdir" ] && createdir_askmode "$trashdir" 0700
 499     local original_path
 500     local current_time
 501     local -i i=0
 502     split_arguments "$@"
 503     while [ "${arglist[$i]}" ]
 504     do
 505         original_path="`"${prefixlist[@]}" $realpath_program "${arglist[$i]}"`"
 506         current_time=`date "+%Y%m%d-%H%M%S"`
 507         better_time=`date "+%Y-%m-%d %H:%M:%S"`
 508         dirname="`basename "${arglist[$i]}" | sed -e 's/-/_/g' -e 's/ /_/g'`"
 509         fulldirname="$trashdir/$current_time-$dirname"
 510         mkdir -p "$fulldirname"
 511         echo "Move: ${arglist[$i]} -> $fulldirname"
 512         "${prefixlist[@]}" mv "${arglist[$i]}" "$fulldirname"
 513         if [ "$?" = "0" ]
 514         then
 515             echo "$better_time" > "$fulldirname/information.date"
 516             echo "$original_path" > "$fulldirname/information.path"
 517         else
 518             rmdir "$fulldirname"
 519         fi
 520         i=$i+1
 521         shift
 522     done
 523     unset arglist
 524     unset prefixlist
 525 }
 526 
 527 function trash_rm ()
 528 {
 529     split_arguments "$@"
 530     local -i i=0
 531     while [ "${arglist[$i]}" ]
 532     do
 533         arglist[$i]="-e ${arglist[$i]}p"
 534         i=$i+1
 535     done
 536     trash_dirname=`find "$trashdir" -mindepth 1 -maxdepth 1 | sort | sed -n ${arglist[*]} `
 537     echo 'Type rm -rf $trash_dirname to remove them.'
 538     unset arglist
 539     unset prefixlist
 540 }
 541 
 542 function trash_ls ()
 543 {
 544     local -i i=1
 545     local oneline
 546     find "$trashdir" -mindepth 1 -maxdepth 1 | sort | {
 547         while read oneline
 548         do
 549             printf "%6d %s %s\n" "$i" \
 550                 "$(< "$oneline/information.date")" \
 551                 "$(< "$oneline/information.path")"
 552             i=$i+1
 553         done
 554     } | $PAGER
 555 }
 556 
 557 function trash_pushd ()
 558 {
 559     [ -z "$1" ] && return 1
 560     pushd `find "$trashdir" -mindepth 1 -maxdepth 1 | sort | sed -n $1p`
 561 }
 562 
 563 function trash_cd ()
 564 {
 565     [ -z "$1" ] && return 1
 566     cd `find "$trashdir" -mindepth 1 -maxdepth 1 | sort | sed -n $1p`
 567 }
 568 
 569 function trash_recover ()
 570 {
 571     [ -z "$1" ] && return 1
 572     split_arguments "$@"
 573     local -i i=0
 574     while [ "${arglist[$i]}" ]
 575     do
 576         arglist[$i]="-e ${arglist[$i]}p"
 577         i=$i+1
 578     done
 579     find "$trashdir" -mindepth 1 -maxdepth 1 | sort | sed -n ${arglist[*]} | {
 580         while read oneline
 581         do
 582             local fromfile="$oneline/`basename "$(< "$oneline/information.path")"`"
 583             local tofile="`dirname "$(< "$oneline/information.path")"`"
 584             if [ -e "$(< "$oneline/information.path")" ]
 585             then
 586                 echo "Destination file exists."
 587                 continue
 588             fi
 589             echo "Move: $fromfile -> $tofile"
 590             "${prefixlist[@]}" mv -f "$fromfile" "$tofile"
 591             if [ "$?" = "0" ]
 592             then
 593                 echo "Remove: $oneline"
 594                 command rm -rf "$oneline"
 595             fi
 596         done
 597     }
 598     unset arglist
 599     unset prefixlist
 600 }
 601 
 602 function trash_count ()
 603 {
 604     find "$trashdir" -mindepth 1 -maxdepth 1 | wc | awk '{print $2}'
 605 }
 606 
 607 function trash_du ()
 608 {
 609     split_arguments "$@"
 610     local oneline
 611     local -i i=1
 612     find "$trashdir" -maxdepth 1 -mindepth 1 | sort | {
 613         while read oneline
 614         do
 615             printf "%6d %8d %s\n" "$i" \
 616                 "`get_file_size "$oneline" -- "${prefixlist[@]}"`" \
 617                 "$(< "$oneline/information.path")"
 618             i=$i+1
 619         done
 620     } | $PAGER
 621     unset arglist
 622     unset prefixlist
 623 }
 624 
 625 ########## Trash Manager End ##########
 626 
 627 function split_arguments ()
 628 {
 629     local argcount=$#
 630     local -i i=0
 631     local prefix_start=0
 632     while [ "$1" ]
 633     do
 634         if [ "$prefix_start" = "0" ]
 635         then
 636             if [ "$1" = "--" ]
 637             then
 638                 prefix_start=1
 639                 i=0
 640                 shift
 641                 continue
 642             else
 643                 arglist[$i]="$1"
 644             fi
 645         else
 646             prefixlist[$i]="$1"
 647         fi
 648         i=$i+1
 649         shift
 650     done
 651 }
 652 
 653 function check_important_files ()
 654 {
 655     important_files="$HOME/.screenrc $HOME/.vimrc"
 656     for i in $important_files
 657     do
 658         [ '!' -f "$i" ] && printf "\e[1;31mWarning\e[m: \e[1;33m$i\e[m does not exist.\n"
 659     done
 660 }
 661 
 662 ########## PATH Editor ##########
 663 
 664 function split_path_core ()
 665 {
 666     echo "$current_path" | {
 667         while read -d : oneline
 668         do
 669             [ '!' "$oneline" = '^' ] && echo "$oneline"
 670         done
 671         [ '!' "$oneline" = '^' ] && echo "$oneline"
 672     }
 673     unset oneline
 674 }
 675 
 676 function split_path ()
 677 {
 678     coproc split_path_core
 679     readarray -t -u ${COPROC[0]} patharr
 680     wait $COPROC_PID
 681 }
 682 
 683 function update_path ()
 684 {
 685     current_path=''
 686     local -i i=0
 687     local firsttime="yes"
 688     while [ "${patharr[$i]}" ]
 689     do
 690         if [ '!' "${patharr[$i]}" = "^" ]
 691         then
 692             if [ "$firsttime" ]
 693             then
 694                 firsttime=''
 695             else
 696                 current_path+=':'
 697             fi
 698             current_path+="${patharr[$i]}"
 699         fi
 700         i=$i+1
 701     done
 702 }
 703 
 704 function old_path_editor ()
 705 {
 706     old_path_editor_core
 707 }
 708 
 709 function old_ldpath_editor ()
 710 {
 711     old_path_editor_core ld
 712 }
 713 
 714 function old_path_editor_core ()
 715 {
 716     if [ "$1" = "ld" ]
 717     then
 718         export current_path="$LD_LIBRARY_PATH"
 719     else
 720         export current_path="$PATH"
 721     fi
 722     local should_continue="yes"
 723     local command
 724     local command_sub
 725     local command_sub2
 726     local -i i
 727     while [ "$should_continue" ]
 728     do
 729         split_path
 730         i=0
 731         echo "========================================"
 732         while [ "${patharr[$i]}" ]
 733         do
 734             echo "$i: ${patharr[$i]}"
 735             i=$i+1
 736         done
 737         [ "$i" = '0' ] && echo "(Empty or not declared)"
 738         echo "========================================"
 739         read -e -p "[A]ppend/(D)elete/(E)dit/(M)ove/(R)eset/(Q)uit ? " command
 740         case "$command" in
 741             ''|A|a)
 742                 read -e -p "Type a new entry: " patharr[$i]
 743                 update_path
 744                 ;;
 745             D|d)
 746                 read -e -p "Index: " command_sub
 747                 patharr[$command_sub]='^'
 748                 update_path
 749                 ;;
 750             E|e)
 751                 read -e -p "Index: " command_sub
 752                 read -e -p "Modify this entry: " -i "${patharr[$command_sub]}" patharr[$command_sub]
 753                 update_path
 754                 ;;
 755             M|m)
 756                 read -e -p "From: " command_sub
 757                 read -e -p "To: " command_sub2
 758                 swaptmp="${patharr[$command_sub]}"
 759                 patharr[$command_sub]="${patharr[$command_sub2]}"
 760                 patharr[$command_sub2]="$swaptmp"
 761                 unset swaptmp
 762                 update_path
 763                 ;;
 764             R|r)
 765                 if [ "$1" = "ld" ]
 766                 then
 767                     current_path="$LD_LIBRARY_PATH"
 768                 else
 769                     current_path="$PATH"
 770                 fi
 771                 ;;
 772             Q|q)
 773                 if [ "$1" = "ld" ]
 774                 then
 775                     export LD_LIBRARY_PATH="$current_path"
 776                     echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH"
 777                     history -s "LD_LIBRARY_PATH=$LD_LIBRARY_PATH"
 778                 else
 779                     export PATH="$current_path"
 780                     echo "PATH=$PATH"
 781                     history -s "PATH=$PATH"
 782                 fi
 783                 should_continue=''
 784                 ;;
 785             *)
 786                 printf " \e[33m*** Unknown command ***\e[m \n"
 787                 ;;
 788         esac
 789     done
 790     unset patharr
 791     unset current_path
 792 }
 793 
 794 ########## PATH Editor End ##########
 795 
 796 ########## New PATH Editor ##########
 797 
 798 function ldpath_editor ()
 799 {
 800     path_editor LD_LIBRARY_PATH
 801 }
 802 
 803 function newpath_init ()
 804 {
 805     unset newpath
 806     local pathsp="$pathorgval"
 807     local pathentry
 808     local -i i
 809     eval pathsp='"${pathsp// /\\}"'
 810     pathsp="${pathsp//:/ }"
 811     i=0
 812     for pathentry in $pathsp
 813     do
 814         newpath[$i]="${pathentry//\\/ }"
 815         i=$i+1
 816     done
 817 }
 818 
 819 function newpath_gen ()
 820 {
 821     local -i i
 822     pathmodval=""
 823     i=0
 824     while [ "${newpath[$i]}" ]
 825     do
 826         if [ "$i" != 0 ]; then pathmodval+=":"; fi
 827         pathmodval+="${newpath[$i]}"
 828         i=$i+1
 829     done
 830 }
 831 
 832 function path_editor ()
 833 {
 834     local newpathvarname
 835     local badcommand
 836     local command
 837     local command_sub
 838     local command_sub2
 839     local should_continue="yes"
 840     local -i i
 841 
 842     if [ -z "$1" ]
 843     then
 844         newpathvarname="PATH"
 845     else
 846         newpathvarname="$1"
 847     fi
 848 
 849     eval pathorgval=\${${newpathvarname}}
 850     newpath_init
 851 
 852     while [ "$should_continue" ]
 853     do
 854         i=0
 855         echo -n $'\e[2J\e[0;0H'
 856         if [ "$badcommand" = "yes" ]; then
 857             printf " \e[33m*** Command \`$command' is unknown ***\e[m \n"
 858             badcommand=""
 859         fi
 860         echo "        New PATH Editor for BASH        "
 861         echo "========================================"
 862         echo "Environment Variable: $newpathvarname"
 863         echo "----------------------------------------"
 864         while [ "${newpath[$i]}" ]
 865         do
 866             echo "$i: ${newpath[$i]}"
 867             i=$i+1
 868         done
 869         [ "$i" = '0' ] && echo "(Empty or not declared)"
 870         echo "========================================"
 871         read -e -p "[A]ppend/(I)nsert/(D)elete/(E)dit/(M)ove/(S)wap/(R)eset/(Q)uit ? " command
 872         case "$command" in
 873             ''|A|a)
 874                 read -e -p "Type a new entry: " newpath[$i]
 875                 ;;
 876             I|i)
 877                 read -e -p "Type a new entry: " command_sub
 878                 if [ -z "$command_sub" ]; then continue; fi
 879                 newpath_tmp=( "${newpath[@]}" )
 880                 unset newpath
 881                 newpath="$command_sub"
 882                 i=0
 883                 while [ "${newpath_tmp[$i]}" ]
 884                 do
 885                     newpath[$i+1]="${newpath_tmp[$i]}"
 886                     i=$i+1
 887                 done
 888                 unset newpath_tmp
 889                 ;;
 890             D|d)
 891                 read -e -p "Index: " command_sub
 892                 if [ -z "$command_sub" ]; then continue; fi
 893                 i="$command_sub"
 894                 i=$i+1
 895                 while [ "${newpath[$i]}" ]
 896                 do
 897                     newpath[$i-1]="${newpath[$i]}"
 898                     i=$i+1
 899                 done
 900                 unset newpath[$i-1]
 901                 ;;
 902             E|e)
 903                 read -e -p "Index: " command_sub
 904                 read -e -p "Modify this entry: " -i "${newpath[$command_sub]}" newpath[$command_sub]
 905                 ;;
 906             M|m)
 907                 read -e -p "From: " command_sub
 908                 read -e -p "To: " command_sub2
 909                 if [ "$command_sub" -eq "$command_sub2" ]; then continue; fi
 910                 cmdsubval="${newpath[$command_sub]}"
 911                 if [ "$command_sub" -gt "$command_sub2" ]; then
 912                     i="$command_sub"
 913                     while [ "$i" -gt "$command_sub2" ]
 914                     do
 915                         newpath[$i]="${newpath[$i-1]}"
 916                         i=$i-1
 917                     done
 918                     newpath[$command_sub2]="$cmdsubval"
 919                 else
 920                     i="$command_sub"
 921                     while [ "$i" -lt "$command_sub2" ]
 922                     do
 923                         newpath[$i]="${newpath[$i+1]}"
 924                         i=$i+1
 925                     done
 926                     newpath[$command_sub2]="$cmdsubval"
 927                 fi
 928                 unset cmdsubval
 929                 ;;
 930             S|s)
 931                 read -e -p "First entry: " command_sub
 932                 read -e -p "Second entry: " command_sub2
 933                 swaptmp="${newpath[$command_sub]}"
 934                 newpath[$command_sub]="${newpath[$command_sub2]}"
 935                 newpath[$command_sub2]="$swaptmp"
 936                 unset swaptmp
 937                 ;;
 938             R|r)
 939                 read -e -p "Discard all changes [y/N] ? " command_sub
 940                 if [ "$command_sub" = "y" ]; then
 941                     eval pathorgval=\${${newpathvarname}}
 942                     newpath_init
 943                 fi
 944                 ;;
 945             Q|q)
 946                 newpath_gen
 947                 eval export ${newpathvarname}=\"$pathmodval\"
 948                 echo "${newpathvarname}=$pathmodval"
 949                 history -s "${newpathvarname}=$pathmodval"
 950                 should_continue=''
 951                 ;;
 952             *)
 953                 badcommand="yes"
 954                 ;;
 955         esac
 956     done
 957     unset newpath
 958     unset pathorgval
 959     unset pathmodval
 960 }
 961 
 962 ########## New PATH Editor End ##########
 963 
 964 ########## Configuration File ##########
 965 
 966 function configfile_fetch ()
 967 {
 968     local cgit_mirror_list=(
 969         "http://www.tfcis.org/~lantw44/cgit/cgit.cgi/configfile/plain"
 970         "http://phantom.tfcis.org/~lantw44/cgit/cgit.cgi/configfile/plain"
 971         "http://master.lant.com.tw/~lantw44/cgit/cgit.cgi/configfile/plain")
 972     local github_mirror_list=(
 973         "https://raw.github.com/lantw44/configfile"
 974         "http://raw.github.com/lantw44/configfile")
 975     local args
 976     local file_url
 977     local file_version
 978     local completed
 979     local -a file_name
 980     local -i i
 981     local -i j
 982 
 983     if [ "$1" ]; then
 984         file_version="$1"
 985     else
 986         file_version="master"
 987     fi
 988 
 989     args=("$@")
 990     for((i=2, j=0; i<=$#; i++, j++)){
 991         file_name[$j]="${args[$i]}"
 992     }
 993 
 994     if [ -z "$file_name"]; then
 995         file_name=("bash_include" "vimrc" "screenrc")
 996     fi
 997 
 998     for file in ${file_name[@]}
 999     do
1000         completed="false"
1001 
1002         for site in ${cgit_mirror_list[@]}
1003         do
1004             [ "$completed" = "true" ] && break
1005             file_url="$site/$file?id=$file_version"
1006             if fetch_and_merge "$HOME/.${file}" "$file_url"
1007             then
1008                 completed="true"
1009                 break
1010             fi
1011         done
1012 
1013         for site in ${github_mirror_list[@]}
1014         do
1015             [ "$completed" = "true" ] && break
1016             file_url="$site/$file_version/$file"
1017             if fetch_and_merge "$HOME/.${file}" "$file_url"
1018             then
1019                 completed="true"
1020                 break
1021             fi
1022         done
1023 
1024     done
1025 }
1026 
1027 function configfile_initial_setup ()
1028 {
1029     cat >> ~/.bashrc << "EOF"
1030 if [ -f ~/.bash_include ]; then
1031     . ~/.bash_include
1032 fi
1033 EOF
1034     if [[ "$OSTYPE" == *freebsd* ]]; then
1035         cat >> ~/.bash_login << "EOF"
1036 GET_TTY_NAME=`tty | cut -c 9`
1037 [ "$GET_TTY_NAME" = 'v' ] && echo "Login from local virtual terminal: `tty`"
1038 [ "$GET_TTY_NAME" = 'p' ] && echo "Login from pseudo terminal: `tty`"
1039 [ "$GET_TTY_NAME" = '/' ] && echo "Login from pseudo terminal: `tty`"
1040 unset GET_TTY_NAME
1041 EOF
1042     fi
1043     cat >> ~/.bash_login << "EOF"
1044 if [ -f ~/.bashrc ]; then
1045     . ~/.bashrc
1046 fi
1047 EOF
1048     echo "Completed. Type \`help_function' to know how to use!"
1049     for i in ~/.bashrc ~/.bash_login ~/.bash_profile ~/.shrc ~/.profile
1050     do
1051         grep -q -e HISTSIZE -e HISTFILESIZE "$i" 2>/dev/null && \
1052             echo "Warning: HISTSIZE or HISTFILESIZE is set in $i!" && \
1053             echo "History file features may not work"
1054     done
1055 }
1056 
1057 function fetch_remote_file ()
1058 {
1059     local rval
1060     printf "==> Fetch remote file \e[1;33m$2\e[m as \e[1;35m$1\e[m ...\n"
1061     if check_command_existent curl; then
1062         curl -f -o "$1" "$2"
1063         rval=$?
1064     elif check_command_existent wget; then
1065         wget --progress=dot -O "$1" "$2"
1066         rval=$?
1067     elif check_command_existent fetch; then
1068         fetch -o "$1" "$2"
1069         rval=$?
1070     elif check_command_existent ftp; then
1071         ftp -o "$1" "$2"
1072         rval=$?
1073     else
1074         echo "<== Sorry, I don't know how to fetch remote files on your system"
1075         return 1
1076     fi
1077     if [ "$rval" = "0" ]; then
1078         printf "<== \e[1;32mDone\e[m\n"
1079     else
1080         printf "<== \e[1;31mFailed\e[m\n"
1081     fi
1082     return $rval
1083 }
1084 
1085 function fetch_and_merge ()
1086 {
1087     local merge_cmd
1088     local merge_cmd_prog
1089     local local_file="$1"
1090     local remote_file="$2"
1091     if fetch_remote_file "${local_file}.new" "${remote_file}"
1092     then
1093         if [ '!' -e "${local_file}" ]; then
1094             mv -vf "${local_file}.new" "${local_file}"
1095         else
1096             while true
1097             do
1098                 echo ""
1099                 cmp "${local_file}" "${local_file}.new" &> /dev/null && \
1100                     echo "Downloaded file is the same as installed one." && \
1101                     break
1102                 printf "Configuration files update tool: "
1103                 printf "Updating \e[1;35m${local_file}\e[m\n"
1104                 echo ""
1105                 echo " Install: Install the new version"
1106                 echo " Keep:    Keep the old version"
1107                 echo " Retry:   Give up downloaded file and try the next mirror"
1108                 echo ""
1109                 echo " Diff:    View the difference between versions"
1110                 echo " Merge:   Merge two files by yourself"
1111                 echo ""
1112                 read -e -p "[I]nstall/(K)eep/(R)etry/(D)iff/(M)erge ? " merge_cmd
1113                 case "${merge_cmd}" in
1114                     ''|I|i)
1115                         mv -vf "${local_file}.new" "${local_file}"
1116                         break
1117                         ;;
1118                     K|k)
1119                         rm -f "${local_file}.new"
1120                         break
1121                         ;;
1122                     R|r)
1123                         rm -f "${local_file}.new"
1124                         return 1
1125                         ;;
1126                     D|d)
1127                         diff -u "${local_file}" "${local_file}.new" | $PAGER
1128                         ;;
1129                     M|m)
1130                         read -e -p "Merge tool: " -i "$merge_cmd_prog" merge_cmd_prog
1131                         if $merge_cmd_prog "${local_file}" "${local_file}.new"; then
1132                             break
1133                         else
1134                             echo "Command is exited with error. Please try again."
1135                         fi
1136                         ;;
1137                     *)
1138                         printf " \e[33m*** Unknown command ***\e[m \n"
1139                         ;;
1140                 esac
1141             done
1142         fi
1143         return 0
1144     fi
1145     return 1
1146 }
1147 
1148 ########## Configuration File End  ##########
1149 
1150 function varset ()
1151 {
1152     local varoldvalue
1153     local varnewvalue
1154     while [ "$1" ]
1155     do
1156         eval varoldvalue=\${$1}
1157         read -r -e -p "$1=" -i "$varoldvalue" varnewvalue
1158         eval "$1"='"$varnewvalue"'
1159         shift
1160     done
1161 }
1162 
1163 function is_file_type ()
1164 {
1165     local filename="$1"
1166     local typename="$2"
1167     shift 2
1168     [ "`"$@" find "$filename" -maxdepth 0 -type "$typename"`" ] && return 0
1169     return 1
1170 }
1171 
1172 function editlink ()
1173 {
1174     local newdest
1175     local orgdest
1176     split_arguments "$@"
1177     local -i i=0
1178     while [ "${arglist[$i]}" ]
1179     do
1180         if is_file_type "${arglist[$i]}" "l" "${prefixlist[@]}"; then
1181             orgdest="`${prefixlist[@]} readlink "${arglist[$i]}"`"
1182             read -e -p "EditLink: ${arglist[$i]} -> " -i "$orgdest" newdest
1183         else
1184             printf "\e[1;33mWarning\e[m: ${arglist[$i]} is not a symbolic link.\n"
1185             i=$i+1
1186             continue
1187         fi
1188         if [ "$newdest" ] && [ "$newdest" '!=' "$orgdest" ]; then
1189             "${prefixlist[@]}" rm -f "${arglist[$i]}"
1190             "${prefixlist[@]}" ln -sv "$newdest" "${arglist[$i]}"
1191         fi
1192         i=$i+1
1193     done
1194     unset arglist
1195     unset prefixlist
1196 }
1197 
1198 function backup_file ()
1199 {
1200     split_arguments "$@"
1201     local current_time=`date +%Y%m%d`
1202     local rootfilename
1203     local -i i=0
1204     local -i j
1205     while [ "${arglist[$i]}" ]
1206     do
1207         if [ '!' -f "${arglist[$i]}" ]
1208         then
1209             printf "\e[1;31mError\e[m: ${arglist[$i]} does not exist or it is not a regular file.\n"
1210             i=$i+1
1211             continue
1212         fi
1213         rootfilename="${arglist[$i]}.$current_time"
1214         if [ -e "$rootfilename" ]
1215         then
1216             j=0
1217             while [ "$j" -lt "10" ]
1218             do
1219                 if [ -e "$rootfilename.$j" ]
1220                 then
1221                     j=$j+1
1222                     continue
1223                 else
1224                     history -s "$FUNCNAME" "$@"
1225                     "${prefixlist[@]}" \cp -p "${arglist[$i]}" "$rootfilename.$j"
1226                     history -s "${prefixlist[@]}" \cp -p "${arglist[$i]}" "$rootfilename.$j"
1227                     "${prefixlist[@]}" touch -r "${arglist[$i]}" "$rootfilename.$j"
1228                     history -s "${prefixlist[@]}" touch -r "${arglist[$i]}" "$rootfilename.$j"
1229                     break
1230                 fi
1231             done
1232             if [ '!' "$j" -lt "10" ]
1233             then
1234                 printf "\e[1;31mError\e[m: Can not create a backup file for ${arglist[$i]}.\n"
1235                 printf "\e[1;33mPlease delete some backup file because I only use 0 - 9.\e[m\n"
1236             fi
1237         else
1238             history -s "$FUNCNAME" "$@"
1239             "${prefixlist[@]}" cp -p "${arglist[$i]}" "$rootfilename"
1240             history -s "${prefixlist[@]}" cp -p "${arglist[$i]}" "$rootfilename"
1241             "${prefixlist[@]}" touch -r "${arglist[$i]}" "$rootfilename"
1242             history -s "${prefixlist[@]}" touch -r "${arglist[$i]}" "$rootfilename"
1243         fi
1244         i=$i+1
1245     done
1246     unset arglist
1247     unset prefixlist
1248 }
1249 
1250 function keep_sudo_credential ()
1251 {
1252     if [ "$1" ]
1253     then
1254         update_sudo_interval="$1"
1255     else
1256         update_sudo_interval="280"
1257     fi
1258     while true
1259     do
1260         sudo -v
1261         sleep "$update_sudo_interval"
1262     done
1263 }
1264 
1265 function get_memory_info ()
1266 {
1267     case "$OSTYPE" in
1268         *linux*|*gnu*)
1269             local meminfoline="`free -m | command grep -i mem`"
1270             local swapinfoline="`free -m | command grep -i swap`"
1271             local memtotal="`echo "$meminfoline" | awk '{print $2}'`"
1272             local memused="`echo "$meminfoline" | awk '{print $3}'`"
1273             local membuf="`echo "$meminfoline" | awk '{print $6}'`"
1274             local memcache="`echo "$meminfoline" | awk '{print $7}'`"
1275             local memprog=$(($memused-$membuf-$memcache))
1276             local swaptotal="`echo "$swapinfoline" | awk '{print $2}'`"
1277             local swapused="`echo "$swapinfoline" | awk '{print $3}'`"
1278             echo "Memory: $memused / $memtotal MB (`printf %2d $(($memused*100/$memtotal))`%)"
1279             echo "Detail:"
1280             echo "    Used:    `printf %5d $memprog` MB (`printf %2d $(($memprog*100/$memtotal))`%)"
1281             echo "    Buffers: `printf %5d $membuf` MB (`printf %2d $(($membuf*100/$memtotal))`%)"
1282             echo "    Cached:  `printf %5d $memcache` MB (`printf %2d $(($memcache*100/$memtotal))`%)"
1283             if [ "$swaptotal" = "0" ]
1284             then
1285                 echo "Swap: not available"
1286             else
1287                 echo "Swap: $swapused / $swaptotal MB (`printf %2d $(($swapused*100/$swaptotal))`%)"
1288             fi
1289             ;;
1290         *freebsd*)
1291             local mempagesize="`sysctl -n hw.pagesize`"
1292             local mempagecount="`sysctl -n hw.availpages`"
1293             local memactive="`sysctl -n vm.stats.vm.v_active_count`"
1294             local meminactive="`sysctl -n vm.stats.vm.v_inactive_count`"
1295             local memwire="`sysctl -n vm.stats.vm.v_wire_count`"
1296             local memcache="`sysctl -n vm.stats.vm.v_cache_count`"
1297             local memfree="`sysctl -n vm.stats.vm.v_free_count`"
1298             local swapenabled="`sysctl -n vm.swap_enabled`"
1299             echo "Memory (Active):   `printf %5d $(($memactive*$mempagesize/1048576))` MB (`printf %2d $(($memactive*100/$mempagecount))`%)"
1300             echo "Memory (Inactive): `printf %5d $(($meminactive*$mempagesize/1048576))` MB (`printf %2d $(($meminactive*100/$mempagecount))`%)"
1301             echo "Memory (Wired):    `printf %5d $(($memwire*$mempagesize/1048576))` MB (`printf %2d $(($memwire*100/$mempagecount))`%)"
1302             echo "Memory (Cache):    `printf %5d $(($memcache*$mempagesize/1048576))` MB (`printf %2d $(($memcache*100/$mempagecount))`%)"
1303             echo "Memory (Free):     `printf %5d $(($memfree*$mempagesize/1048576))` MB (`printf %2d $(($memfree*100/$mempagecount))`%)"
1304             echo "Total Memory:      `printf %5d $(($mempagecount*$mempagesize/1048576))` MB"
1305             if [ "$swapenabled" = "1" ]; then
1306                 echo ""
1307                 echo "Swap devices:"
1308                 swapinfo -m
1309             else
1310                 echo "Swap: not enabled"
1311             fi
1312             ;;
1313         *)
1314             echo "Unsupported operating system."
1315             ;;
1316     esac
1317 }
1318 
1319 function argv0 ()
1320 {
1321     local execname="$1"
1322     local argv0="$2"
1323     shift 2
1324     ( exec -a "$argv0" "$execname" "$@" )
1325 }
1326 
1327 function repeat ()
1328 {
1329     local repeat_times="$1"
1330     shift
1331     for ((i=0; i<repeat_times; i++))
1332     do
1333         "$@"
1334     done
1335 }
1336 
1337 function wait_success ()
1338 {
1339     local i=1
1340     until "$@"; do echo "Failed ... $i"; ((i++)) ; done
1341 }
1342 
1343 function fbterm_chewing ()
1344 {
1345     if [ -z "$1" ]; then
1346         fbterm -s 14 -- uim-fep -u chewing
1347     else
1348         local font_size="$1"
1349         shift
1350         fbterm -s "$font_size" "$@" -- uim-fep -u chewing
1351     fi
1352 }
1353 
1354 function set_console_title ()
1355 {
1356     case "$TERM" in
1357         screen*)
1358             printf "\033]0;"
1359             echo -n "$*"
1360             printf "\033\\"
1361             ;;
1362         xterm*)
1363             printf "\033]0;"
1364             echo -n "$*"
1365             printf "\007"
1366             ;;
1367         *)
1368             echo "Your terminal may not have the hardstatus line."
1369             echo "Note: TERM=$TERM"
1370             ;;
1371     esac
1372 }
1373 
1374 function mvfile ()
1375 {
1376     local nocheck=0
1377     [ "$1" = "-n" ] && nocheck=1 && shift
1378     split_arguments "$@"
1379     local -i i=0
1380     while [ "${arglist[$i]}" ]
1381     do
1382         if [ "$nocheck" = "0" ] && [ '!' -e "${arglist[$i]}" ]
1383         then
1384             printf "\e[33mWarning\e[m: ${arglist[$i]} does not exist. (Use -n to override)\n"
1385             i=$i+1
1386             continue
1387         fi
1388         echo "Old name: ${arglist[$i]}"
1389         read -p "New name: " -e -i "${arglist[$i]}" new_file_name
1390         if [ "$new_file_name" ] && [ "${arglist[$i]}" != "$new_file_name" ]
1391         then
1392             history -s "$FUNCNAME" "$@"
1393             "${prefixlist[@]}" mv -iv "${arglist[$i]}" "$new_file_name"
1394             history -s "${prefixlist[@]}" mv -iv "${arglist[$i]}" "$new_file_name"
1395         fi
1396         i=$i+1
1397     done
1398     unset arglist
1399     unset prefixlist
1400     unset new_file_name
1401 }
1402 
1403 function createdir_askmode ()
1404 {
1405     newdir_mode="$2"
1406     if mkdir -p "$1"
1407     then
1408         echo "Directory $1 is created."
1409         printf "Change the mode of the directory... "
1410         read -i "$newdir_mode" -p ">>> Mode: " -e newdir_mode
1411         chmod "$newdir_mode" "$1"
1412     else
1413         echo "Cannot create directory $1!"
1414         return 1
1415     fi
1416 }
1417 
1418 function get_terminal_size ()
1419 {
1420     # ESC 7              = 儲存游標位置和屬性
1421     # ESC [r             = 啟用全螢幕捲動
1422     # ESC [{row};{col}H  = 移動游標
1423     # ESC 6n             = 回報目前游標位置
1424     # ESC 8              = 還原游標位置和屬性
1425     echo -n $'\e7\e[r\e[999;999H\e[6n\e8' 1>&2
1426     read -s -d R getsize
1427     echo $getsize | sed 's#..\([0-9]*\);\([0-9]*\)#LINES=\1 COLUMNS=\2#'
1428 }
1429 
1430 function set_terminal_size ()
1431 {
1432     eval "export `get_terminal_size`"
1433     stty cols $COLUMNS rows $LINES
1434 }
1435 
1436 function unzip_nomac ()
1437 {
1438     unzip "$@" -x '__MACOSX/*' '*.DS_Store'
1439     return $?
1440 }
1441 
1442 function gen_ms_inet_shortcut () {
1443     [ "$#" != "2" ] && {
1444         echo "Usage: $FUNCNAME filename url"
1445     } && return 1
1446 
1447     {
1448         echo "[InternetShortcut]"
1449         echo "URL=$2"
1450     } > "$1"
1451 }
1452 
1453 function check_command_existent ()
1454 {
1455     type "$1" &> /dev/null
1456     return $?
1457 }
1458 
1459 function get_executable_extension ()
1460 {
1461     local lsloc="`command which ls`"
1462     local lsalt="`echo ${lsloc}.* | cut -d ' ' -f 1`"
1463     cmp "$lsloc" "$lsalt" &> /dev/null && echo ${lsalt:${#lsloc}} && return
1464 }
1465 
1466 function rpmdu () {
1467     local div_base=1
1468     local div_name="KB"
1469     local total=0
1470     if [ "`echo "$1" | cut -c 1`" = "-" ]
1471     then
1472         local optname=`echo "$1" | cut -c 2-`
1473         case "$optname" in
1474             "k")
1475                 ;;
1476             "m")
1477                 div_base=1024
1478                 div_name=MB
1479                 ;;
1480             "g")
1481                 div_base=1048576
1482                 div_name=GB
1483                 ;;
1484             *)
1485                 echo "Usage: $FUNCNAME [OPTION] package_name..."
1486                 echo "    -k KB"
1487                 echo "    -m MB"
1488                 echo "    -g GB"
1489                 return 1
1490                 ;;
1491         esac
1492         shift
1493     fi
1494 
1495     while [ "$1" ]
1496     do
1497         rpm -ql "$1" | {
1498             while read oneline
1499             do
1500                 if [ -f "$oneline" ]
1501                 then
1502                     du -k "$oneline"
1503                 fi
1504             done
1505         } | {
1506             while read -d $'\t' filesize
1507             do
1508                 total=$((${total}+${filesize}))
1509                 read
1510             done
1511             printf "%9d %s %s\n" "$(($total/$div_base))" "$div_name" "$1"
1512         }
1513 
1514         shift
1515     done
1516 }
1517 
1518 function rpmsize () {
1519     local div_base=1
1520     local div_name="Bytes"
1521     local total=0
1522     local filesize
1523     if [ "`echo "$1" | cut -c 1`" = "-" ]
1524     then
1525         optname=`echo "$1" | cut -c 2-`
1526         case "$optname" in
1527             "b")
1528                 ;;
1529             "k")
1530                 div_base=1024
1531                 div_name=KB
1532                 ;;
1533             "m")
1534                 div_base=1048576
1535                 div_name=MB
1536                 ;;
1537             "g")
1538                 div_base=1073741824
1539                 div_name=GB
1540                 ;;
1541             *)
1542                 echo "Usage: $FUNCNAME [OPTION] package_name..."
1543                 echo "    -b Byte"
1544                 echo "    -k KB"
1545                 echo "    -m MB"
1546                 echo "    -g GB"
1547                 return 1
1548                 ;;
1549         esac
1550         shift
1551     fi
1552     while [ "$1" ]
1553     do
1554         total=0
1555         filesize=`rpm -q "$1" --queryformat "%{SIZE} "`
1556         for i in $filesize
1557         do
1558             total=$((${total}+${i}))
1559         done
1560         printf "%12d %s %s\n" "$(($total/$div_base))" "$div_name" "$1"
1561         shift
1562     done
1563 }
1564 
1565 function freebsd_ports_should_rebuild () {
1566     reqcomp=$(ldd -f '%a %o %p\n' \
1567         /usr/local/bin/* /usr/local/sbin/* \
1568         /usr/local/lib/* /usr/local/libexec/* \
1569         /usr/local/libexec/*/* \
1570         2>/dev/null | grep 'not found' | \
1571         { while read oneline; do echo ${oneline} | cut -d ' ' -f 1; done; } | uniq)
1572     reqpkg=$({ for i in $reqcomp; do pkg_info -q -W $i; done } | sort | uniq)
1573     echo $reqpkg
1574 }
1575 
1576 ########## Help ##########
1577 
1578 alias helpf='help_function'
1579 alias helpm='help_myself'
1580 alias helpa='help_aliases'
1581 
1582 function print_iconv ()
1583 {
1584     [ "$1" = "$2" ] && cat && return 0
1585     iconv -f "$1" -t "$2"
1586 }
1587 
1588 function help_myself ()
1589 {
1590     echo "argc = $#"
1591     echo "argv[0] = $0"
1592     i=1
1593     while [ "$1" ]
1594     do
1595         echo "argv[$i] = $1"
1596         i=$(($i+1))
1597         shift
1598     done
1599 }
1600 
1601 function help_aliases ()
1602 {
1603     cat << "ENDHELPMSG"
1604  %%% Aliases: Command Prompt %%%
1605     startcolor    - Enable colorful PS1 prompting
1606     stopcolor     - Disable colorful PS1 prompting
1607 
1608  %%% Aliases: Terminal %%%
1609     savetty       - Save current terminal mode
1610     resetty       - Reset to last saved terminal mode
1611 
1612  %%% Aliases: Nice Format %%%
1613     ndate         - Format the output of `date'
1614     npasswd       - Format the output of `getent passwd'
1615     ngroup        - Format the output of `getent group'
1616 
1617  %%% Aliases: Other %%%
1618     vimhtml       - Start Vim and set tabstop and shiftwidth to 2
1619     screen256     - Start GNU Screen and set TERM to screen-256color
1620 ENDHELPMSG
1621 }
1622 
1623 function help_obsolete ()
1624 {
1625     cat << "ENDHELPMSG"
1626  @@@ Obsolete Group: PATH Editor @@@
1627     old_path_editor
1628     old_ldpath_editor
1629  x  split_path
1630  x  split_path_core
1631  x  update_path
1632  x  old_path_editor_core
1633 ENDHELPMSG
1634 }
1635 
1636 function help_function ()
1637 {
1638     [ "$#" = "0" ] && {
1639         cat << "ENDHELPMSG"
1640  <<< Help >>>
1641     help_myself [arguments ...]                            (helpm)
1642     help_function [functions ...]                          (helpf)
1643     help_aliases                                           (helpa)
1644     help_obsolete
1645  x  print_iconv
1646 
1647  <<< Group: Background >>>
1648     bgrun command [arguments ...]                          (bgr)
1649     bglist [--full]                                        (bgl, bgls)
1650     bgview [number]                                        (bgv)
1651     bgclean [all | numbers ...]                            (bgrm)
1652     bgcount                                                (bgc)
1653     bgdu
1654  <<< Group: Trash >>>
1655     trash_mv [filenames ...] [-- sudo_prefix ...]     (trash_put, trash_add)
1656     trash_ls                                          (trash_list)
1657     trash_cd number
1658     trash_pushd number
1659     trash_recover numbers ... [-- sudo_prefix ...]    (trash_restore, trash_rc)
1660     trash_rm numbers ...                              (trash_drop, trash_clean)
1661     trash_count                                       (trash_ct)
1662     trash_du [-- sudo_prefix ...]
1663  <<< Group: New PATH Editor >>>
1664     path_editor [variable]
1665     ldpath_editor
1666  x  newpath_init
1667  x  newpath_gen
1668  <<< Group: Configuration File >>>
1669     configfile_fetch [git_tag [file_name_list ...]]
1670     configfile_initial_setup
1671  x  fetch_remote_file local_file_name remote_url
1672  x  fetch_and_merge local_file_name remote_url
1673 
1674  <<< System: Terminal >>>
1675     set_console_title
1676     set_terminal_size
1677  <<< System: Information >>>
1678     get_memory_info
1679  <<< System: Packages Management >>>
1680     rpmdu [-kmg] packages ...
1681     rpmsize [-bkmg] packages ...
1682     freebsd_ports_should_rebuild
1683  <<< System: Privileges >>>
1684     keep_sudo_credential [seconds]
1685 
1686  <<< Tools: Interactive >>>
1687     compile_all [-n] filenames ...
1688     editlink filenames ... [-- sudo_prefix ...]
1689     mvfile [-n] filenames ... [-- sudo_prefix ...]
1690     varset variables ...
1691  <<< Tools: Non-interactive >>>
1692     argv0 executable arguments ... (include argv[0])
1693     backup_file filename ... [-- sudo_prefix ...]
1694     convert_to_html filename ...
1695     mkscreenacl usernames ...
1696     repeat times arguments ...
1697     wait_success arguments ...
1698 
1699  <<< Miscellaneous: Background Jobs >>>
1700     check_dmesg seconds
1701     check_system_status seconds
1702  <<< Miscellaneous: Compatibility >>>
1703     fbterm_chewing [size] [arguments ...]
1704     gen_ms_inet_shortcut filename url
1705     unzip_nomac filenames ...
1706  <<< Miscellaneous: Personal >>>
1707     check_important_files
1708     prehistory_backup
1709 
1710  <<< Shared Internal Functions >>>
1711  x  createdir_askmode dirname
1712  x  check_command_existent program
1713  x  is_file_type filename type [-- sudo_prefix ...]
1714  x  get_file_size filename [-- sudo_prefix ...]
1715  x  get_executable_extension
1716  x  get_terminal_size
1717  x  split_arguments [arguments ...]
1718 
1719 Some simple aliases are not printed. Type `help_aliases' to print them.
1720 Obsolete functions are not printed. Type `help_obsolete' to print them.
1721 ENDHELPMSG
1722     } | $PAGER && return 0
1723     local current_charset=`echo "$LC_ALL" | cut -d . -f 2`
1724     local -i i
1725     while [ "$1" ]
1726     do
1727         case "$1" in
1728             help_myself|helpm)
1729                 cat << "ENDHELPMSG" | print_iconv "UTF-8" "$current_charset"
1730 help_myself
1731     一個測試命令列的小函式
1732 ENDHELPMSG
1733                 ;;
1734             help_function|helpf)
1735                 cat << "ENDHELPMSG" | print_iconv "UTF-8" "$current_charset"
1736 help_function
1737     顯示 .bash_include 提供的額外函式清單
1738     註:前方加上「x」符號者表示此為內部使用的函式,不宜直接使用
1739 ENDHELPMSG
1740                 ;;
1741             bgrun|bgr)
1742                 cat << "ENDHELPMSG" | print_iconv "UTF-8" "$current_charset"
1743 bgrun command [arguments ...]
1744     執行指令 command 並將輸出導入檔案
1745     註:此函式會自動以目前時間和指令名稱為檔案命名
1746 ENDHELPMSG
1747                 ;;
1748             bglist|bgl|bgls)
1749                 cat << "ENDHELPMSG" | print_iconv "UTF-8" "$current_charset"
1750 bglist [--full]
1751     列出所有使用 bgrun 執行的指令
1752     若加上 --full 選項,則可同時察看時間
1753 ENDHELPMSG
1754                 ;;
1755             bgview|bgv)
1756                 cat << "ENDHELPMSG" | print_iconv "UTF-8" "$current_charset"
1757 bgview [number]
1758     顯示以 bgrun 執行指令的輸出,若省略 number,表示是最近一次執行的指令
1759     若 number >  0,
1760         表示第 number 個指令 (此數值可由 bglist 函式取得)
1761     若 number <= 0,
1762         表示第「指令總數-number」個指令 (指令總數可由 bgcount 函式取得)
1763 ENDHELPMSG
1764                 ;;
1765             bgclean|bgrm)
1766                 cat << "ENDHELPMSG" | print_iconv "UTF-8" "$current_charset"
1767 bgclean [all | numbers ...]
1768     bgclean all 可清除所有指令的輸出檔
1769     bgclean 3 5 7 10 表示清除第 3、5、7、10 個指令輸出檔 (編號可由 bglist 取得)
1770 ENDHELPMSG
1771                 ;;
1772             bgcount|bgc)
1773                 cat << "ENDHELPMSG" | print_iconv "UTF-8" "$current_charset"
1774 bgcount
1775     顯示指令輸出檔總數
1776 ENDHELPMSG
1777                 ;;
1778             bgdu)
1779                 cat << "ENDHELPMSG" | print_iconv "UTF-8" "$current_charset"
1780 bgdu
1781     顯示每個指令輸出檔的檔案大小 (單位:KB)
1782 ENDHELPMSG
1783                 ;;
1784             *)
1785                 echo "Help message for $1 is not found"
1786                 ;;
1787         esac
1788         shift
1789     done
1790 }
1791 
1792 ########## Help End ##########
1793 
1794 # Doing something
1795 
1796 umask 0022
1797 
1798 if [ "$interactive_shell" ]
1799 then
1800     echo "Running interactive shell configuration"
1801     check_important_files
1802     startcolor
1803     prehistory_backup
1804     bind '"\e[A":history-search-backward'
1805     bind '"\e[B":history-search-forward'
1806     if [ -e "$HOME/.bash_title" ]; then
1807         case "$TERM" in
1808             xterm*)
1809                 PROMPT_COMMAND="$PROMPT_COMMAND"'; printf "\033]0;%s@%s:%s (%s)\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}" "`date "+%H:%M:%S"`"'
1810                 ;;
1811             screen*)
1812                 PROMPT_COMMAND="$PROMPT_COMMAND"'; printf "\033]0;%s@%s:%s (%s)\033\\" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}" "`date "+%H:%M:%S"`"'
1813                 ;;
1814         esac
1815     fi
1816     [ "$TERM" = xterm ] && TERM=xterm-256color
1817     [ "$TERM" = screen ] && TERM=screen-256color
1818 fi
1819 
1820 [ "$interactive_shell" ] && echo "Setting shell options, completions, limits"
1821 
1822 shopt -s histappend
1823 shopt -s checkwinsize
1824 shopt -s checkjobs
1825 shopt -s checkhash
1826 shopt -s cmdhist
1827 shopt -s mailwarn
1828 
1829 complete -A alias helpa
1830 complete -A alias help_aliases
1831 complete -A command check_command_existent
1832 complete -A directory createdir_askmode
1833 complete -A function helpf
1834 complete -A function help_function
1835 complete -A variable varset
1836 complete -A variable path_editor
1837 complete -A user mkscreenacl
1838 
1839 if check_command_existent _command; then
1840     complete -F _command wait_success
1841 fi
1842 
1843 if check_command_existent _screen; then
1844     complete -F _screen screen256
1845 fi
1846 
1847 if check_command_existent _rpmdev_installed_packages; then
1848     complete -F _rpmdev_installed_packages rpmdu
1849     complete -F _rpmdev_installed_packages rpmsize
1850 fi
1851 
1852 ulimit -S -c unlimited 2> /dev/null
1853 
1854 [ "$interactive_shell" ] && {
1855     if [ "$WINDOW" ] && type screen &> /dev/null; then
1856         if [[ "`screen --version`" == *4.01* ]]; then
1857             echo "Setting options for GNU screen 4.1.0"
1858             screen -X cjkwidth off
1859         fi
1860     fi
1861 }
1862 
1863 [ "$interactive_shell" ] && {
1864     echo "Done"
1865     if [ "$UID" = "0" ] || [ "$EUID" = "0" ]
1866     then
1867         printf "\nNote: You may be \e[1;32mprivileged\e[m now!\n\n"
1868     fi
1869 }