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