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