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