#!/bin/bash
#
# $Id: cl,v 1.2 2005/03/09 17:23:41 cholm Exp $
#
# Wrapper script for MS VC compiler.  Translates GCC like options into
# CL options  

# cmdprefix="echo"
arg="/nologo "
largs=""
debug=0
program="cl.exe" 
preprocess=0
compile=0
msvcrt=0
libc=0
libcmt=0
dep_argc=0
declare -a dep_argv
ld_argc=0
declare -a ld_argv

argc=0
declare -a argv

push_arg() {
    argv[${argc}]="$1" 
    let argc=$argc+1
}

clear_arg() {
    i=0
    while test $i -lt ${#argv} ; do 
	if test "x${argv[$i]}" = "x$1" ; then 
	    unset argv[$i]
	    break
	fi
	let i=$i+1
    done
}

push_dep_arg()
{
    :
    #dep_argv[${dep_argc}]="$1" 
    #let dep_argc=$dep_argc+1
}

push_ld_arg()
{
    ld_argv[${ld_argc}]="$1" 
    let ld_argc=$ld_argc+1
}

push_arg "/nologo"
push_arg "/GX" 
	    
while test $# -gt 0 ; do 
    case $1 in 
	-c) # Only compile 
	    compile=1
	    push_arg /c
	    ;;
	-g*) # debug option 
	    case $arg in 
		gdb*)   debug=`echo $arg | sed 's/gdb//` ;;
		stabs*) debug=`echo $arg | sed 's/stabs+?//` ;;
		*coff*) debug=`echo $arg | sed 's/x?coff+?//` ;;
		dwarf*) debug=`echo $arg | sed 's/dwarf\(-[0-9]\)+?//'` ;;
		vms*)   debug=`echo $arg | sed 's/vms//` ;;
		*)	debug=2 ;;
	    esac
	    ;;
	-o) # output option
	    if test $# -eq 1; then 
		echo "Option -$1 needs an argument" > /dev/stderr 
		exit 1
	    fi
	    case $2 in 
		*.o)     push_arg "/Fo`echo $2 | sed 's/\.o//'`.obj" ;; 
		*.obj)   push_arg "/Fo$2"				;;
		*.s)     push_arg "/Fa$2"                            ;;
		*.pch)   push_arg "/Fp`echo $2`"                     ;; 
		*.sbr)   push_arg "/Fr`echo $2`"                     ;; 
		*.i)     push_arg "/Fi`echo $2 | sed 's/\.o//'`.obj" ;; 
		*.exe)   push_arg "/Fe$2"                            ;;
		*.dll)   push_ld_arg "/out:$2"                       ;;
		*)       push_arg "/Fe$2.exe" ;;
	    esac
	    shift
	    ;; 
	-I*) # Include path
	    push_arg `echo $1 | sed 's,-I,/I,'`
	    if test $dep_argc -gt 0 ; then 
		push_dep_arg "$1"
	    fi
	    ;;
	-D*) # define option 
	    push_arg "`echo $1|sed -e 's,",\\",g' -e 's, ,\\ ,g' -e 's,^-D,/D,'`"
	    if test $dep_argc -gt 0 ; then 
		push_dep_arg "`echo $1|sed -e 's,",\\",g' -e 's, ,\\ ,g'`"
	    fi
	    ;;
	-U*) # undefine option 
	    undefine=
	    push_arg "`echo $1 | sed 's,^-U,/U,'`"
	    if test $dep_argc -gt 0 ; then 
		push_dep_arg "$1"
	    fi	    
	    ;;
	-w) # Disable warnings 
	    push_arg /w
	    ;;
	-W*) 
	    opt=`echo $1 | sed 's/-W\(..\).*/\1/'`
	    case $opt in 
		a,) # assembler options 
		;;
		l,) # linker options.  Replace commas with spaces
		
		    tmplargs=`echo $1 | sed -e 's/^-Wl,//' -e 's/,/ /g'`
		    # Process the linker arguments, and save it in the largs
	            # variable 
		    ignore_next=0
		    for i in $tmplargs ; do 
			case $i in 
			    -rpath)  ignore_next=1 ;; 
			    -soname) ignore_next=1 ;;
			    *)
			    	if test $ignore_next -le 0 ; then 
				    echo "Pushing $i" ; 
				    push_ld_arg $i 
				else
				    ignore_next=0
				fi
				;;
			esac 
			# shift
		    done 
		    ;;
		*)  # Different warning levels 
		    wopt=`echo $1 | sed 's,-W,,'`
		    case $wopt in 
			all)   push_arg /W5 ;;
			error) push_arg /WX ;;
			*)     push_arg /W1 ;; 
		    esac
		    ;;
	    esac
	    ;;
	
	-v)
	    # push_arg /showIncludes
	    ;;
	-O*)
	    lvl=`echo $1 | sed 's,^-O,,'` 
	    case "$lvl" in
		"0")     push_arg "/Od" ;;
		"1"|"")  push_arg "/O1" ;;
		"2")     push_arg "/O2" ;;
		"3")     push_arg "/Ox" ;;
		"s")     push_arg "/O1" ;;
	    esac
	    ;;
	-f*)
	    opt=`echo $1 | sed 's,-f,,'`
	    case $opt in 
		unsigned-char) # default char type is unsigned
		    push_arg /J
		    ;;
		syntax-only)   # syntax check only
		    push_arg /Zs
		    ;; 
		no-default-inline) # no inline 
		    push_arg /Ob0
		    ;;
		no-inline) # no inline 
		    push_arg /Ob0
		    ;;
		inline-functions)
		    push_arg /Ob600
		    ;;
		omit-frame-pointer)
		    push_arg /Oy
		    ;;
		no-omit-frame-pointer)
		    push_arg /Oy-
		    ;;
		inline-limit=*)
		    n=`echo $opt | sed 's/inline-limit=//'` 
		    push_arg "/Ob$n"
		    ;;
		gcse)
		    push_arg "/Og"
		    ;;
		strict-aliasing)
		    push_arg /Ow
		    ;;
		exceptions)
		    # push_arg /GX
		    ;;
		no-exceptions)
		    push_arg /GX-
		    ;;
		
		PIC)
		    push_arg /GD
		    ;;
		stack-check)
		    push_arg /Ge
		    ;;
		no-stack-limit)
		    push_arg /Gs
		    ;;
		stack-limit-symbol)
		    n=`echo $opt | sed 's/stack-limit-symbol=//'` 
		    push_arg "/Gs$n"
		    ;;
		instrument-functions)
		    push_arg /Gh
		    ;;
		no-rtti)
		    push_arg /GR-
		    ;;
		ms-extensions)
		    push_arg /Ze
		    ;;
		*)  ;; 
		
	    esac 
	    ;;
	-ansi)
	    push_arg /Za
	    ;;
	-m*)
	    opt=`echo $1 | sed 's,^-m,,'` 
	    case $opt in
		cpu) opt=`echo $1 | sed 's,^cpu,,'` ;;
		*)
	    esac
	    case $opt in
		386)                 push_arg /G3 ;;
		486)                 push_arg /G4 ;;
		pentium|pentium-mmx) push_arg /G5 ;;
		pentiumpro|pentium2|pentium3)          push_arg /G6 ;;
		pentium4|athlon)     push_arg /G7 ;;
		sse)		     push_arg /arch:SSE ;;
		sse2)		     push_arg /arch:SSE2 ;;
	    esac
	    ;;
	-x)  # language selection 
	    case $2 in 
		c)    lang="/Tc" ;; 
		c++)  lang="/Tp" ;;
		none) lang=      ;;
		*)    echo "language $2 unknown" > /dev/stderr ; exit 1 ;;  
	    esac
	    ;;
	--include) # Force include
	    if test $# -eq 1; then 
		echo "Option $1 needs an argument"  > /dev/stderr 
		exit 1
	    fi
	    push_arg "/FI$2"
	    shift
	    ;;
	-lmsvcrt)
	    msvcrt=1
	    ;;
	-lc)
	    libc=1
	    ;;
	# -lpthread|-pthread) 
	    # libcmt=1
	    # ;;
	-L*)
	    dir="`echo $1 | sed 's/^-L//'`"
	    if test -d "$dir" ; then 
		dir=`cygpath -s -w "$dir"` 
	    else
		dir=`cygpath -w "$dir"` 
	    fi
	    push_ld_arg "/LIBPATH:$dir"
	    ;;
	-nostdinc) # ignore "standard places"
	    push_arg /X
	    ;;
	-undef) # undefine standard macros
	    push_arg /u
	    ;;
	-C) # Do not make discard comments
	    push_arg /C	
	    ;;
	-P) # Do not make line directives
	    if test $preprocess -lt 1 ; then
		preprocess=1
		push_arg /EP
	    fi
	    ;;
	-E)  # Preprocess to stdout
	    if test $preprocess -lt 1 ; then
		preprocess=1
		push_arg /E
	    fi
	    ;; 
	-M*) # Dependency options. I think we have to run cpp directly here. 
	    push_dep_arg "$1"
	    case $1 in 
		-MT|-MQ|-MF)
		    if test $# -eq 1 ; then 
			echo "Option $1 needs an argument" > /dev/stderr 
			exit 1
		    fi
		    shift
		    push_dep_arg "$1"
		    ;;
	    esac
	    echo "not supported" > /dev/stderr 
	    ;;
	--help) # Help 
	    push_arg /?
	    ;; 
	-shared)
	    if test $debug -gt 0 ; then 
		push_ld_arg /dll
	    else
		push_ld_arg /dll
	    fi
	    ;;
	-V)
	    clear_arg /nologo
	    ;;
	--version)
	    vers=`${program} 2> /dev/stdout | sed -n 's/.*Version \([0-9.][0-9.]*\).*/\1/p'`
	    echo $vers 
	    ;;
	*) 
	    if test -f $1 ; then 
		if test ! "x$lang" = "x" ; then 
		    push_arg "/F${lang}$1" 
		else
		    case $1 in 
			*.cc)  push_arg "/Tp$1" ;; 
			*.lib) push_ld_arg "$1" ;; 
			*)     push_arg "$1" ;;
		    esac
		fi
		if test $dep_argc -gt 0 ; then 
		    push_dep_arg "$1"
		fi
	    else
	        # Other options are passed verbatim 
		push_arg $1
	    fi
	    ;;
    esac
    shift
done 

if test $msvcrt -gt 0 ; then 
    arg=/MD 
elif test $libcmt -gt 0 ; then 
    arg=/MT
elif test $libc -gt 0 ; then 
    arg=/ML
fi 
if test "x$arg" != "x" && test $debug -gt 0 ; then 
    arg="${arg}d" 
    push_arg $arg
    unset arg
fi
if test $debug -gt 0 ; then 
    case $debug in 
	1)  push_arg /Zd ;;
	2)  push_arg /Zi ;;
	3)  push_arg /Zi 
	    push_arg /ZI 
	    push_arg /Yd ;;
	*)  push_arg /Zi ;;
    esac
fi

if test $dep_argc -gt 0 ; then 
    echo cpp "${dep_argv[@]}" 
    cpp "${dep_argv[@]}" 
fi
if test $ld_argc -gt 0 ; then 
    linker=/link
else
    linker=
fi
echo ${program} "${argv[@]}" $linker "${ld_argv[@]}"
${cmdprefix} ${program} "${argv[@]}" $linker "${ld_argv[@]}"

