Home | History | Annotate | Download | only in scripts
      1 #!/bin/ksh -p
      2 #
      3 # CDDL HEADER START
      4 #
      5 # The contents of this file are subject to the terms of the
      6 # Common Development and Distribution License (the "License").
      7 # You may not use this file except in compliance with the License.
      8 #
      9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10 # or http://www.opensolaris.org/os/licensing.
     11 # See the License for the specific language governing permissions
     12 # and limitations under the License.
     13 #
     14 # When distributing Covered Code, include this CDDL HEADER in each
     15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16 # If applicable, add the following below this CDDL HEADER, with the
     17 # fields enclosed by brackets "[]" replaced with your own identifying
     18 # information: Portions Copyright [yyyy] [name of copyright owner]
     19 #
     20 # CDDL HEADER END
     21 #
     22 #
     23 
     24 #
     25 # Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     26 # Use is subject to license terms.
     27 # 
     28 
     29 # wx -- workspace extensions.  Jeff Bonwick, December 1992.
     30 
     31 # The bugster cat/subcat = consolidation/os-net-tools
     32 
     33 version() {
     34 	if [[ $(whence $0) = "/opt/onbld/bin/wx" ]] && \
     35 	    pkginfo SUNWonbld > /dev/null 2>&1; then
     36 		pkginfo -l SUNWonbld | egrep "PKGINST:|VERSION:|PSTAMP:"
     37 	else
     38 		ls -l $(whence $0)
     39 	fi    
     40 }
     41 
     42 ring_bell() {
     43 	# Sound bell to stderr, no newline 
     44 	print -u2 "\007\c"
     45 }
     46 
     47 fail() {
     48 	ring_bell
     49 	# output error message to stderr
     50 	print -u2 "$@ Aborting $command."
     51 	exit 1
     52 }
     53 
     54 ask() {
     55 	typeset question=$1 default_answer=$2
     56 	if [ -z "$default_answer" ]; then
     57 		echo "$question \c"
     58 	else
     59 		echo "$question [$default_answer]: \c"
     60 	fi
     61 	read answer
     62 	[ -z "$answer" ] && answer="$default_answer"
     63 }
     64 
     65 yesno() {
     66 	typeset question="$1"
     67 	answer=
     68 	while [ -z "$answer" ]; do
     69 		ask "$question" y/n
     70 		case $answer in
     71 			y|yes)	answer=yes;;
     72 			n|no)	answer=no;;
     73 			*)	answer=;;
     74 		esac
     75 	done
     76 }
     77 
     78 ok_to_proceed() {
     79 	yesno "$*"
     80 	if [[ "$answer" == no ]]; then
     81 		echo "Exiting, no action performed"
     82 		exit 1
     83 	fi
     84 }
     85 
     86 escape_re() {
     87 	# Escape the . so they are treated as literals in greps.
     88 	echo "$1"|sed 's{\.{\\.{g'
     89 }
     90 
     91 remove_local_nt_entry() {
     92 	# remove entries in local nt cache
     93 	grep -v "^$(escape_re $1) " $wxdir/local_nametable > \
     94 		$wxtmp/local_nametable
     95 	[[ ! -f $wxtmp/local_nametable ]] && \
     96 		fail "Error: cannot create $wxtmp/local_nametable"
     97 	mv -f $wxtmp/local_nametable $wxdir/local_nametable ||
     98 		fail "Error: cannot create $wxdir/local_nametable."
     99 }
    100 
    101 remove_renamed_entry() {
    102 	# remove entries in renamed list
    103 	# assuming arg is the new filename to remove
    104 	grep -v "^$(escape_re $1) " $wxdir/renamed > \
    105 		$wxtmp/renamed
    106 	[[ ! -f $wxtmp/renamed ]] && fail "Error: cannot create $wxtmp/renamed"
    107 	mv -f $wxtmp/renamed $wxdir/renamed ||
    108 		fail "Error: mv -f $wxtmp/renamed $wxdir/renamed failed"
    109 }
    110 
    111 add_local_nt_entry() {
    112 	# Add workspace nametable entry to local nt cache for better perf.
    113 	[[ -r $wsdata/nametable ]] || return 0
    114 	if ! grep -q "^$(escape_re $1) " $wxdir/local_nametable; then
    115 		# add entries from workspace nt to local nt cache
    116 		grep "^$(escape_re $1) " $wsdata/nametable >> \
    117 			$wxdir/local_nametable
    118 		[[ ! -f $wxdir/local_nametable ]] && \
    119 			fail "Error: cannot create $wxdir/local_nametable"
    120 	fi
    121 	return 0
    122 }
    123 
    124 remove_active_entry() {
    125 	# Remove entry from active list 
    126 	# $1 is the filepath to remove
    127 
    128 	nawk '
    129 	$1 == target {
    130 		# Get past filepath line
    131 		while(NF > 0)
    132 			getline;
    133 		# Get past blank lines
    134 		while(NF == 0)
    135 			getline;
    136 		# Get past comments
    137 		while(NF > 0)
    138 			getline;
    139 		# Get past ending blank lines
    140 		while(NF == 0) {
    141 			if (getline) {
    142 				continue;
    143 			} else {
    144 				next;
    145 			}
    146 		}
    147 	}
    148 	# print the other active list entries
    149 	{ print $0; } ' target=$1 $wxdir/active >$wxtmp/tmp_active ||
    150 		fail "Error: cannot create $wxtmp/tmp_active."
    151 	if mv -f $wxtmp/tmp_active $wxdir/active; then
    152 		echo "$1 removed from active list."
    153 		remove_local_nt_entry $1
    154 	else
    155 		cat >&2 <<-EOF
    156 An error occured trying to remove $1 from the active list.
    157 The active list may be corrupt.  You should check it out and 
    158 possibly run '$ME update' to fix.
    159 		EOF
    160 		fail 
    161 	fi
    162 }
    163 
    164 rename_active_entry() {
    165 	# renamed $1 to $2 filepath in active list
    166 	sed "s|^$(escape_re $1)$|$2|" $wxdir/active >\
    167 		$wxtmp/active || fail "Error: cannot create $wxtmp/active."
    168 	mv -f $wxtmp/active $wxdir/active || \
    169 		fail "Error: mv $wxtmp/active $wxdir/active failed."
    170 }
    171 
    172 is_active() {
    173 	# Return 0 if filepath arg is found in active list.
    174 	wx_active|grep -q "^$(escape_re $1)$"
    175 }
    176 
    177 #
    178 # ask user if s/he wants to remove an entry from the active list.
    179 # Will not remove entries that differ from parent or are new.
    180 #
    181 ask_remove_active_entry() {
    182 	# if an arg is passed in then this is assumed to be the filepath
    183 	# otherwise we assume the variables were set properly by the caller
    184 	if [[ $# -eq 1 ]]; then
    185 		dir=$(dirname $1)
    186 		file=$(basename $1)
    187 		filepath=$1
    188 
    189 		if [[ ! -f $file ]]; then
    190 			echo "Cannot find $file"
    191 			return 1
    192 		fi
    193 	fi
    194 
    195 	if is_active $filepath; then
    196 		if wx_pnt_filepath $filepath; then
    197 			if ! cmp -s $file $parentfilepath; then
    198 				cat <<-EOF
    199 
    200 The file $filepath
    201 differs from parent file:
    202 $parentfilepath
    203 and will remain in the active list.
    204 				EOF
    205 				return
    206 			fi
    207 		else
    208 			# New file, leave in active list.
    209 			cat <<-EOF
    210 $filepath
    211 is new and will remain in active list.  Use:
    212 '$ME uncreate $filepath'
    213 to remove from active list.
    214 			EOF
    215 			return
    216 		fi
    217 		# Remove entry from active list because it is the same as 
    218 		# the parent.
    219 		echo "There is no difference between $filepath and the parent"
    220 		echo "$parentfilepath"
    221 		yesno "Okay to remove $filepath from active list?"
    222 		if [[ "$answer" == 'yes' ]]; then
    223 			remove_active_entry $filepath
    224 		fi
    225 	fi
    226 }
    227 
    228 refresh_pnt_nt_cache() {
    229 	# Refresh the parent nametable cache if necessary.
    230 	# Note, this is a cache for the parent nametable entries that
    231 	# have the same hash as the local active and renamed files.
    232 
    233 	# no parent so nothing to update.
    234 	[[ -z $parent ]] && return 0
    235 
    236 	if [[ ! -r $parent/Codemgr_wsdata/nametable ]]; then
    237 		fail "Error: cannot read $parent/Codemgr_wsdata/nametable"
    238 	fi
    239 
    240 	if [[ ! -f $wxtmp/parent_nametable ||
    241 	    $parent/Codemgr_wsdata/nametable -nt $wxtmp/parent_nametable ||
    242 	    $wsdata/parent -nt $wxtmp/parent_nametable ||
    243 	    $wxdir/local_nametable -nt $wxtmp/parent_nametable ]]; then
    244 		cut -f2- -d' ' $wxdir/local_nametable > $wxtmp/hash_list
    245 
    246 		if [[ ! -f $wxtmp/hash_list ]]; then
    247 			fail "Error: cannot create $wxtmp/hash_list."
    248 		fi
    249 
    250 		if [[ -s $wxtmp/hash_list ]]; then
    251 			# Use hash list to get only the parent files
    252 			# we're interested in.
    253 			fgrep -f $wxtmp/hash_list \
    254 			    $parent/Codemgr_wsdata/nametable \
    255 				 > $wxtmp/parent_nametable 
    256 			[[ ! -f $wxtmp/parent_nametable ]] && \
    257 				fail "Error: cannot create $wxtmp/parent_nametable"
    258 		else
    259 
    260 			# There aren't any files to search for so just
    261 			# update the timestamp.
    262 
    263 			touch $wxtmp/parent_nametable
    264 		fi
    265 	fi
    266 }
    267 
    268 # add an active file to the new list
    269 add_new() {
    270 	typeset efp=$(escape_re $1)
    271 	# update new file list
    272 	if [[ ! -f $wxdir/new ]]; then
    273 		touch $wxdir/new || fail "Error: cannot create $wxdir/new."
    274 	fi
    275 	if is_active $1 && ! grep -q "^$efp$" $wxdir/new; then
    276 		echo "$1" >> $wxdir/new || fail "Error: cannot update $wxdir/new."
    277 	fi
    278 }
    279 
    280 # remove a file from the new list
    281 remove_new() {
    282 	# remove entries in new list
    283 	typeset efp=$(escape_re $1)
    284 	if [[ -f $wxdir/new ]] && grep -q "^$efp$" $wxdir/new; then
    285 		grep -v "^$efp$" $wxdir/new > $wxtmp/new
    286 		[[ ! -f $wxtmp/new ]] && fail "Error: cannot create $wxtmp/new"
    287 		mv -f $wxtmp/new $wxdir/new || fail "Error: cannot create $wxdir/new." 
    288 	fi
    289 }
    290 
    291 update_active() {
    292 	# Try to add an entry to the active list
    293 	typeset efp=$(escape_re $1)
    294 
    295 	if ! is_active $1; then
    296 		if [[ -n "$comment_file" ]]; then
    297 			# Use sed to remove any empty lines from comment file.
    298 			(echo $1; echo; sed '/^[ 	]*$/d' $comment_file;\
    299 				echo) >>$wxdir/active ||
    300 				fail "Could not update active list."
    301 		else
    302 			(echo $1; echo; wx_show_comment; echo) \
    303 			    >> $wxdir/active ||
    304 				fail "Could not update active list."
    305 			echo "Remember to edit the comment in the active list "\
    306 				 "(use '$ME ea')."
    307 		fi
    308 		add_local_nt_entry $1
    309 	fi  # End if not in active list
    310 }
    311 
    312 sort_active() {
    313 	typeset origfp=$filepath
    314 
    315 	# Note must use filepath for wx_show_comment
    316 	wx_active | sort | while read filepath; do
    317 		(print "$filepath"; print; wx_show_comment; print)
    318 	done > $wxtmp/active_sort || \
    319 		fail "Error: cannot create $wxtmp/active_sort"
    320 	mv -f $wxtmp/active_sort $wxdir/active || \
    321 		fail "Error: cannot create $wxdir/active"
    322 
    323 	filepath=$origfp
    324 }
    325 
    326 sort_renamed() {
    327 	sort $wxdir/renamed > $wxtmp/renamed_sort || \
    328 		fail "Error: cannot create $wxtmp/renamed_sort"
    329 	mv -f $wxtmp/renamed_sort $wxdir/renamed || \
    330 		fail "Error: cannot create $wxdir/active"
    331 }
    332 
    333 update_active_comment() {
    334 	# replace comment in active list entry with contents of $comment_file
    335 	nawk '
    336 	# find active list entry to modify
    337 	$1 == filepath {
    338 		# print filepath line
    339 		while(NF > 0){
    340 			print $1;
    341 			getline;
    342 		}
    343 		#print 1 blank (delimit)
    344 		print "";
    345 		# Get past blank lines
    346 		while(NF == 0){
    347 			getline;
    348 		}
    349 		# Get past active entry comments
    350 		# append to or replace comment
    351 		if (comment_mode == "append"){
    352 			while(NF > 0) {
    353 				# output existing comments
    354 				print $0;
    355 				getline;
    356 			}
    357 		} else {
    358 			# get past existing comments
    359 			while(NF > 0) getline;
    360 		}
    361 
    362 		# output new comments
    363 		while (getline < comments){
    364 			# do not print blank lines
    365 			if (NF > 0)
    366 				print $0
    367 		}
    368 		close comments
    369 		# print delimiting blank line
    370 		printf "\n"
    371 
    372 		# Get past ending blank lines in active entry
    373 		NF=0
    374 		while(NF == 0) {
    375 			if (getline) {
    376 				continue;
    377 			} else {
    378 				next;
    379 			}
    380 		}
    381 	}
    382 	# print the other active list entries
    383 	{ print $0; } ' filepath=$1 comment_mode=$comment_mode \
    384 		comments=$comment_file $wxdir/active >$wxtmp/tmp_active && \
    385 		mv $wxtmp/tmp_active $wxdir/active 
    386 	if [[ $? -eq 0 ]]; then
    387 		echo "$1 comment(s) updated in active list."
    388 	else
    389 		cat <<-EOF
    390 
    391 An error occured trying to update comments for $1 in the active list.
    392 The active list ($wxdir/active) may be corrupt.  You should check it out
    393 and possilbly run '$ME ea' to fix.
    394 
    395 		EOF
    396 		fail
    397 	fi
    398 }
    399 
    400 lookup_parent() {
    401 	# Find a local file's parent filepath.
    402 	# Returns 1 if not found (local file is new)
    403 	# Sets env var. parentfilepath and parenthash if found
    404 	# Requires a file arg.
    405 	# Updates local and parent nt caches.
    406 
    407 	typeset efp parententry localfile hash1 hash2 hash3 hash4 \
    408 		local_nt pnt_nt
    409 
    410 	parentfile=
    411 	parenthash=
    412 
    413 	if [[ -z $parent ]]; then
    414 		cat >&2 <<-EOF
    415 
    416 Warning: there is no parent for the current workspace so local file:
    417 $1
    418 is assumed to be new.
    419 		EOF
    420 		return 1
    421 	fi
    422 	if [[ ! -f $wsdata/nametable ]]; then
    423 		# Nothing has been brought over so assuming new file.
    424 		cat >&2 <<-EOF
    425 
    426 Warning: the $wsdata/nametable
    427 doesn't exist so
    428 $1
    429 is assumed to be new.
    430 		EOF
    431 		return 1
    432 	fi
    433 
    434 	if [[ ! -r $parent/Codemgr_wsdata/nametable ]]; then
    435 		fail "Error: cannot read $parent/Codemgr_wsdata/nametable."
    436 	fi
    437 	if [[ ! -f $wxtmp/parent_nametable ]] || $need_pnt_refresh; then
    438 		refresh_pnt_nt_cache
    439 		need_pnt_refresh=false
    440 	fi
    441 	if [[ ! -f $wxdir/local_nametable ]]; then
    442 		touch $wxdir/local_nametable ||
    443 			fail "Error: cannot create $wxdir/local_nametable."
    444 	fi
    445 
    446 	efp=$(escape_re $1)
    447 
    448 	for local_nt in $wxdir/local_nametable $wsdata/nametable; do
    449 
    450 		# May be multiple entries in nametable, see if one
    451 		# matches parent.
    452 
    453 		grep "^$efp " $local_nt |\
    454 		while read localfile hash1 hash2 hash3 hash4; do
    455 			for pnt_nt in $wxtmp/parent_nametable \
    456 			    $parent/Codemgr_wsdata/nametable; do
    457 				# get current parent nt entry
    458 				parententry=$(grep \
    459 				    " $hash1 $hash2 $hash3 $hash4$" $pnt_nt)
    460 				if [[ -n "$parententry" ]]; then
    461 					# found parent entry
    462 					parentfile=$(echo "$parententry" |\
    463 						cut -f1 -d' ')
    464 					parenthash="$(echo "$parententry" |\
    465 						cut -f2- -d' ')"
    466 					if [[ "$local_nt" == \
    467 						"$wsdata/nametable" ]]; then
    468 
    469 						# Update the local nt
    470 						# hash cache if parent
    471 						# found and local
    472 						# workspace nt used.
    473 
    474 						add_local_nt_entry $localfile
    475 					fi
    476 					if [[ $pnt_nt == \
    477 					    $parent/Codemgr_wsdata/nametable ]]
    478 					then
    479 
    480 						# Update the parent nt
    481 						# hash cache if actual
    482 						# parent nt used.
    483 
    484 						echo $parententry >>\
    485 						    $wxtmp/parent_nametable
    486 					fi
    487 
    488 					# break out of all the loops if
    489 					# parent found
    490 
    491 					break 3
    492 				fi
    493 			done # for pnt_nt
    494 		done # while read active file
    495 	done # for local_nt
    496 
    497 	if [[ -z "$parentfile" ]]; then
    498 		# parent filepath not found.
    499 		return 1
    500 	else
    501 		# parent filepath found.
    502 		return 0
    503 	fi
    504 }
    505 
    506 #
    507 # Detect if a file was locally renamed
    508 #
    509 renamed() {
    510 	# Return 0 if renamed, 1 if not locally renamed
    511 	# parentfile and parenthash set as side effect
    512 	# Must be used by commands that set filepath (like wx_eval)
    513 
    514 	if [[ ! -f $wxdir/renamed ]]; then
    515 		update_renamed_dir
    516 	fi
    517 
    518 	# new is the new filename in the current ws, old is the previous
    519 	# filename that should exist in parent ws.
    520 
    521 	if grep -q "^$(escape_re $filepath) " $wxdir/renamed; then
    522 		if lookup_parent $filepath; then
    523 			return 0
    524 		else
    525 
    526 			# New files aren't in $wxdir/renamed so no
    527 			# parent is a problem
    528 
    529 			fail "Error: renamed $filepath but no matching parent"\
    530 				"file in $parent"
    531 		fi
    532 	else
    533 		# not locally renamed
    534 		return 1
    535 	fi
    536 }
    537 
    538 wx_pnt_filepath() {
    539 	# return 0 if parent file found. Side effect: sets parentfilepath
    540 	# and parentsdot.  parentfile and parenthash are set via lookup_parent.
    541 
    542 	# if an arg is passed in then this is assumed to be the filepath
    543 	# otherwise we assume the variables were set properly by the caller
    544 	if [[ $# -eq 1 ]]; then
    545 		dir=$(dirname $1)
    546 		file=$(basename $1)
    547 		filepath=$1
    548 	fi
    549 
    550 	# Find the parent filename
    551 	if lookup_parent $filepath; then
    552 		parentfilepath=$parent/$parentfile
    553 		parentsdot=$parent/$(dirname $parentfile)/SCCS/s.$(basename \
    554 		    $parentfile)
    555 		if [[ -f $parentfilepath && -s $parentsdot ]]; then
    556 			# found
    557 			return 0
    558 		else
    559 			fail "Error: located parent filepath $parentfilepath"\
    560 				"but file does not exist or SCCS file is empty."
    561 		fi
    562 	fi
    563 
    564 	# wasn't found
    565 	return 1
    566 }
    567 
    568 get_pb_output() {
    569 	# Get output of putback -n (useful for parsing to find diffs between
    570 	# workspaces).  Creates $wxtmp/putback.err and $wxtmp/putback.out
    571 	typeset -i rc=0
    572 	typeset origdir=$(pwd)
    573 	# clean up if interrupted.
    574 	trap "rm $wxtmp/putback.out;exit 1" HUP INT QUIT TERM
    575 
    576 	cat <<-EOF
    577 Doing a '$PUTBACK -n $*' to find diffs between workspaces.
    578 Please be patient as this can take several minutes.
    579 	EOF
    580 
    581         cd $workspace
    582 
    583 	$PUTBACK -n $* 2>$wxtmp/putback.err >$wxtmp/putback.out
    584 	rc=$?
    585 	# Note a blocked putback returns a 2 but is not a problem.
    586 	if [[ $rc -ne 0 && $rc -ne 2 ]]; then
    587 		rm $wxtmp/putback.out
    588 		fail "Error, $PUTBACK -n $* failed. See $wxtmp/putback.err"\
    589 			"for details."
    590 	fi
    591 	trap - HUP INT QUIT TERM
    592         cd $origdir
    593 	return 0
    594 }
    595 
    596 wx_usage() {
    597 	version
    598 
    599 	cat << EOF
    600 
    601 See <http://www.opensolaris.org/os/community/on/wx/> for usage tips.
    602 
    603 Usage:  $ME command [-D] [args]
    604 
    605         -D turn on debugging for any command (output to stderr)
    606 
    607 ===================== Initialization and Update Commands ====================
    608         $ME init [-f(t|q|n) [-s]] [src-root-dir]     
    609                         initialize workspace for $ME usage
    610                         -f(t|q|n): non-interactive mode of update.  Use this
    611                                    to keep init from asking questions.
    612                             -ft: thorough update (update both active and 
    613                                  renamed lists with all diffs between parent
    614                                  and current workspace).
    615                             -fq: quick update (update active list with files
    616                                  currently checked out in current workspace).
    617                             -fn: no update (just create empty active and 
    618                                  renamed lists if they don't exist already).
    619                             -s:  keep active list sorted by default.  Must
    620                                  follow a -f(t|q|n) flag.
    621                         src-root-dir: optional path relative to top of 
    622                                       workspace where wx will search for files.
    623                                       Use "." to set src-root to top of
    624                                       workspace.  Default is usr.
    625         $ME update [-q|-r] [-s]
    626                         Update the active and renamed file lists by
    627                         appending names of all files that have been
    628                         checked out, changed, created or renamed as
    629                         compared to the parent workspace.  This is the
    630                         most accurate way of updating but it is slow.
    631                         All files in the workspace must be under SCCS
    632                         control in order for update to find them.  Note,
    633                         this operation can be sped up in some cases by
    634                         setting the PUTBACK env. variable to use 
    635                         "cm_env -g -o putback". (See
    636                         http://webhome.holland.sun.com/casper/ for more
    637                         info about the turbo def.dir.flp tool).
    638 
    639                         -q: quick update (only updates active list with
    640                             files currently checked out in workspace).  This
    641                             is faster but will not find renames or files that
    642                             have been checked-in/delget'ed.
    643                         -r: only update the renamed list.  Does not update
    644                             the active list.
    645                         -s: sort the active list.
    646 
    647 ======================== Information Commands ===========================
    648         $ME list [-r|-p|-w] list active files (the ones you are working on)
    649                         -r: list only renamed active files.
    650                         -p: output list of both active and renamed files 
    651                             suitable for input to putback. 
    652                         -w: output list of both active and renamed files
    653                             suitable for input to webrev (see $ME webrev 
    654                             subcommand below).
    655         $ME active          alias for list 
    656         $ME pblist          alias for list -p (see above).
    657 
    658         $ME renamed [-a|-d|-p]
    659                          list locally renamed files. The output format is:
    660                          "new_name previous_name". Note, deleted files are
    661                          a special case of rename. 
    662                         -a: list only renamed active files (same as list -r)
    663                         -d: list only deleted files
    664                         -p: show "new_name parent_name" (Note, parent_name 
    665                             may not be the same as previous_name)
    666         $ME new [-t]    List new active files (files that exist in child only)
    667                         Note, should be run before reedit (see reedit below).
    668                         -t: thorough, does not use new cache (slower but more
    669                             accurate if new cache isn't current).
    670         $ME out         find all checked-out files in workspace
    671         $ME info        [file ...] show all info about active files
    672 
    673         $ME diffs [file ...]
    674                         show sccs diffs for files (current vs previous
    675                         local version).  Will show diffs for all active
    676                         files if no files given on command line.  Will
    677                         use WXDIFFCMD environment variable if set.  Hint,
    678                         try: export WXDIFFCMD="diff -bwU5"
    679 
    680         $ME tdiffs [file ...]
    681                         Similar to diffs but new files are also displayed.
    682                         New files are those listed by '$ME new'.
    683 
    684         $ME pdiffs [file ...]   show diffs against parent files
    685                         Will show diffs between local file and it's
    686                         parent for all active files if no files given on
    687                         command line.  Will use WXDIFFCMD environment
    688                         variable if set. 
    689 
    690         $ME tpdiffs [file ...]   show diffs against parent files
    691                         Similar to pdiffs but new files are also displayed.
    692                         A file is considered new if it does not exist in
    693                         the parent.
    694 
    695         $ME prt [-y]    show sccs history for all active files
    696 
    697         $ME comments    display check-in comments for active files
    698         $ME bugs [-u]   display all bugids in check-in comments
    699         $ME arcs [-u]   display all ARC cases in check-in comments
    700         $ME pbcom [-v] [-u] [-N]  display summarized comments suitable for putback
    701                         Default is to display only bugs and arc cases. Will
    702                         display warnings about non-bug comments to stderr.
    703                         -v: display all comments verbatim including non-bug/arc 
    704                         -u: prevent sorting, order determined by active list
    705                         -N: don't check bug synopsis against bug database
    706 
    707 ======================== File Manipulation Commands ======================
    708         $ME edit [-s] [file ...]        
    709                         check out either file(s) on command line or
    710                         all active files if no file args.
    711                         (Updates the active list.)
    712                         -s: silent, less sccs diagnostic output.  This is 
    713                             true for the other commands that accept the 
    714                             -s flag.
    715         $ME checkout    Alias for edit command.
    716         $ME co          Alias for edit command.
    717 
    718         $ME unedit [-s][-f] [file ...] 
    719                         Returns file(s) to state prior to edit/checkout
    720                         Note, files will be unlocked and any changes made
    721                         when file was last checked out will be lost.
    722                         Unedit all active files if no files listed on
    723                         command line.  Removes active list entry if there
    724                         are no diffs between local and parent file.
    725                         (Updates active list)
    726                         -f: force unedit, non-interactive. Will backup
    727                             if wx files newer than last backup.
    728         $ME uncheckout  Alias for unedit command.
    729         $ME unco        Alias for unedit command.
    730 
    731         $ME delget [-(c|C) comment_file][-s][-f] [file ...] 
    732                         Check in all active files or files on command
    733                         line. Check in comments will be those in active
    734                         file.  See '$ME comments' for more info.
    735                         -c comment_file: use comment(s) in specified comment
    736                                          file when checking in file(s). Note,
    737                                          each comment should be on new line,
    738                                          blank lines not allowed.  Existing
    739                                          comments in active list will be 
    740                                          replaced by contents of comment_file.
    741                         -C comment_file: Similar to -c but comments are 
    742                                          appended to current active list 
    743                                          comments.
    744                         -f: force checkin, no checks, non-interactive.
    745                             Use this if your sure the files okay to checkin
    746                             otherwise this command will check for
    747                             keyword problems. Will backup if wx files
    748                             newer than last backup.
    749 
    750                         NOTE: use redelget to reset new file's version to 1.1.
    751 
    752         $ME checkin     Alias for delget command.
    753         $ME ci          Alias for delget command.
    754 
    755         $ME create [-(c|C) comment_file] [-f] [-o] file [file ...]
    756                         Creates one or more files in the workspace.
    757                         (Updates active list)
    758                         -(c|C) comment_file: see delget
    759                         -f: force create regardless of warnings,
    760                             (non-interactive).
    761                         -o: also check out file for further editing.
    762 
    763         $ME uncreate [-f] [file ...]
    764                         Undoes the create of a new file.  The file's
    765                         active list entry, its SCCS history and the
    766                         entry in the workspace nametable will be removed
    767                         but the file will stay in the workspace.
    768                         Will uncreate all new files in active list if
    769                         no file argument is specified.
    770                         -f: force uncreate, non-interactive. Will backup
    771                             if wx files newer than last backup.
    772 
    773         $ME get [-k][-r #][-p] [file ...]
    774                         Get a copy of all active files or files on command
    775                         line.  By default this is a read only version of
    776                         the file.
    777                         -r #: get specified version #
    778                         -p: output to stdout
    779                         -k: don't expand the sccs ID string
    780         $ME extract     Alias for get command.
    781 
    782         $ME reedit [-m] [-s] [file ...]
    783                         Collapse the sccs delta (file history) such that
    784                         all changes made to the file in the current
    785                         workspace are now in one delta.  If no files are
    786                         given on command line then all the active files
    787                         are processed.  The files are left in a checked
    788                         out state so you can make further changes if a
    789                         resolve to make all your changes look like a
    790                         single delta.  This eliminates the uninteresting
    791                         leaf deltas that arise from resolving conflicts,
    792                         so your putbacks do not contain a bunch of noise
    793                         about every bringover/resolve you did in the
    794                         interim.  Accepts the same compression flags as
    795                         $ME backup.  If [file ...] given, wx only
    796                         reedits files passed on command line.  This adds
    797                         files to active list if not already there.
    798                         
    799                         NOTE: reedit is appropriate for leaf workspaces
    800                         ONLY -- applying reedit to an interior-node
    801                         workspace would delete all childrens comments
    802                         and confuse Teamware tools in general.
    803                         
    804                         NOTE: if files are listed as new that are not
    805                         then DO NOT use the reedit as it will destroy
    806                         the file history.
    807 
    808                         NOTE: if a file is new reedit will leave the
    809                         file checked out so in order to keep the delta
    810                         version at 1.1 redelget must be used for
    811                         checkin.
    812 
    813                         -m: only reedit files that have more that one
    814                             delta as compared to parent file.  New files
    815                             will be recreated with comment found in
    816                             active list.
    817                         -s: silent checkin
    818 
    819         $ME recheckout  Alias for reedit command.
    820         $ME reco        Alias for reedit command.
    821 
    822         $ME redelget [-m][-s] [file ...]
    823                         Similar to reedit but the file is checked in
    824                         when the command is done. This is the command to
    825                         use to collapse new files to their initial
    826                         1.1 delta (will assign comment in active list).
    827         $ME recheckin   Alias for redelget command.
    828         $ME reci        Alias for redelget command.
    829 
    830         $ME delete [-f] [file ...]
    831                         Delete one or more files from the workspace.
    832                         Will delete all files in active list if no file
    833                         args.  Note, for files brought over from parent,
    834                         this command actually moves the file under the
    835                         deleted_files/ subdir so it can be recovered.
    836                         For new files this command can remove the file
    837                         and file history completely.
    838                         (Updates active list if file is in there.)
    839                         -f : force delete regardless of warnings 
    840                              (non-interactive)
    841 
    842                              Warning, this will completely remove new
    843                              files from the workspace.  Will backup
    844                              if wx files newer than last backup.
    845         $ME rm          Alias for delete command.
    846 
    847         $ME mv file newfile     
    848                         Rename file to newfile
    849                         (Updates active list with new file name)
    850         $ME mv file newdir      
    851         $ME mv dir newdir       
    852                         Renames dir or file to newdir.  If newdir exists
    853                         then dir will be subdir under newdir.  Note,
    854                         this renames all files in dir and can take a
    855                         while if there are a lot of files affected by
    856                         the rename.  (Updates active list)
    857 
    858         $ME reset [-f] [file ...]
    859                         Resets file contents and history to that of
    860                         parent file.  If the file was renamed locally it
    861                         will be renamed to that of the parent.  It does not
    862                         work on new files (see uncreate or delete).
    863 
    864                         NOTE: use with care.  If something goes wrong,
    865                         do a wx restore from the last backup and copy
    866                         wx/tmp/nametable.orig to Codemgr_wsdata/nametable.
    867 
    868 ======================== Teamware Commands ======================
    869         $ME putback [-v][-f][-N][Teamware putback flags, see below][file ...]
    870                         Use Teamware putback command