.ad 8
.bm 8
.fm 4
.bt $Copyright (c) 1992-2005 SAP AG-2002$$Page %$
.tm 12
.hm 6
.hs 3
.tt 1 $SQL$Project Distributed Database System$VPS11C$
.tt 2 $$$
.tt 3 $$General link parameter routines$2000-12-29$
****************************************************************
.nf

.nf

.nf

    ========== licence begin  GPL
    Copyright (c) 1992-2005 SAP AG

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end
.fo


.fo


.fo
Module  :
=========
.sp
Purpose :
.CM *-END-* purpose -------------------------------------
Define  :

char **p11opt (const char *caller, int argc, char **argv);

.CM *-END-* define --------------------------------------
Use     :
.CM *-END-* use -----------------------------------------
Synonym :
.CM *-END-* synonym -------------------------------------
.sp;.cp 3
Author  :
.sp
.cp 3
Created : 1994-11-23
.sp
.cp 3
Version : 1994-11-23
.sp
.cp 3
Release :      Date : 2000-12-29
Specification:
.CM *-END-* specification -------------------------------
.sp 2
***********************************************************
.sp
.cp 10
.fo
.oc _/1
Description:
Last changed by Marco P.(2000-08-07). Option for C++ Link
.CM *-END-* description ---------------------------------
.sp 2
***********************************************************
.sp
.cp 10
.nf
.oc _/1
Structure:
.CM *-END-* structure -----------------------------------
.sp 2
**********************************************************
.sp
.cp 10
.nf
.sp
.CM -lll-
Code    :
/*PRETTY*/
&ifdef DEBUG
&else
#line 68 "vps11c"
&endif

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include "gip00.h"
#include "vpr100.h"
#include "heo01.h" /* PTS 1108827 */
#ifdef _IBMR2
/*extern char *malloc ();*/
#else
#include <malloc.h>
#endif
#ifdef WIN32
#define POPEN _popen
#else
#define POPEN popen
#endif
#define MAXNARG 100
#define MAXARGL 132
#define CONLYLINK  PS01_LINKER      /* only native C-Link*/
#define CPPLINK    PS01_CPP_LINKER  /* C++ Link */
#define ENV_SAPDBSDKLIB "SAPDBSDKLIB"
#define ERR_EXAMINE_DBROOT_OR_FILENAME "can't get dbroot or filename from '%s'"

extern void exit (int);
int unlink (const char*);
extern int optind;
extern char * optarg;

char **p11opt (const char *caller, int argc, char **argv)

/*	Get link options and arguments from a command line.
	The name of the calling program is to be stored in caller,
	the parameters of the main function are input in argc and
	argv.
	The function returns a pointer to an argument list for
	p10exec, containing all command line options and libraries
	to build a database application program.
	NOTE:
	The default linker is the plattform specific C-Linker taken
	from gip00.h. If Option -P is set, the linker is the plattform
	specific C++ -Linker taken from gip00.h.
	If option -static is set the all linked librarys are static.
*/
	
{
	static const char LNKVER [] = "LNKVER=";
	static const char link_static [] = " static";
#ifdef  WIN32
	const char *optstr = "M:S:";
	static const char PCRVER [] = "PCRVER=";
	static const char exec [] = "-out:";
	static const char  exe [] = ".exe";
	static const char *ext [] = {".obj", ".rbj", ".lib", ""};
	static const char pcrmt [] = "-MT";   /* use pcr62mt.dll */
	static const char pcrmd [] = "-MD";   /* use pcr62md.dll */
	static const char pcrsmt[] = "-SMT";  /* use pcr62smt.lib */
	int done = 0;
	int NameSet = 0;
	char *qte = "\"";
#else
	const char *optstr = "A:bD:de:L:l:gMNnPo:rSsT:tu:VXxy:z";
	static const char exec [] = "-o";
	static const char *ext [] = {".o", ".c", ".a", ""};
	char *qte = "";
#endif

	const int next = sizeof (ext) / sizeof (char*);
	
	static char *arg [MAXNARG];
	static char *extarg;
	static char *env;
	struct stat stbuf;
	FILE *sqllist;

        int vargc;
        char **vargv;
        int i;
        char szThisVersion[6];
        char *szVersionArg = szThisVersion;

#ifdef WIN32
#if defined BIT64
        boolean Bit32 = false;
#else
        boolean Bit32 = true;
#endif
#else
#if defined BIT64 && ! defined OSF1
        boolean Bit32 = false;
#else
        boolean Bit32 = true;
#endif
#endif

        const char *szLIBPath   = LIBPATH_IP00;
        const char *szLIB64Path = LIB64PATH_IP00;
#ifdef WIN32
        const char *szSDKPath   = "\\sdk\\";
#else
        const char *szSDKPath  = "/sdk/";
#endif

        char *szPutEnvDBRoot, *szCallSqllist;
        tsp00_Pathc szDBRoot;
        tsp00_Pathc szProgName;
        char *ProgToCall;
        boolean hasSDK = true;

	int o, narg = 1, actind = optind, err = 0;
        arg[0]=CONLYLINK; /* default linker is cpp-linker*/

#ifdef WIN32
	env = malloc (strlen(PCRVER) + sizeof (link_static) +
			sizeof(pcrmt) + sizeof(pcrmd) + sizeof(pcrsmt));
        strcpy(env, PCRVER);

#else
	env = malloc (strlen (LNKVER) + strlen (caller) + sizeof (link_static));
        strcpy(env, LNKVER);
	strcat(env, caller);
#endif

        sprintf(szThisVersion, "%d%d%02d", MAJOR_VERSION_NO_SP100, MINOR_VERSION_NO_SP100, CORRECTION_LEVEL_SP100);
        if (argc) {
          /* strip -<version> option from argument */
          /* all other arguments are maped to vargv */
          vargv = (char**) calloc (argc, sizeof (char*));
          for(i=0, vargc=0; i < argc; i++) {
            if (strlen(argv[i]) > 1) {
              if (argv[i][0] == '-') {
                if (argv[i][1] >= '0' && argv[i][1] <= '9') {
                  szVersionArg = &argv[i][1];
                  if (strncmp (szVersionArg, "74", 2))
                    hasSDK = false;
                  continue;
                }
                if (!strcmp(&argv[i][1], "BIT32")) {
                  Bit32 = true;
                  continue;
                }
                else
                  if (!strcmp(&argv[i][1], "BIT64")) {
                    Bit32 = false;
                    continue;
                  }
              }
            }
            vargv[vargc] = argv[i];
            vargc++;
          }
        }
        else {
          vargv = argv;
          vargc = argc;
        }

#ifdef WIN32
	done = 0;

        /* Test if cpclnk option is specified, must be the first option if so*/
        {
        int i = vargv[optind] != NULL ? (int)vargv[optind][0]:0;
	if (i== (int)'-')
            if (strncmp(vargv[optind],"-M",2) != 0 &&
                strncmp(vargv[optind],"-S",2) != 0)
                done = 1;
        }

        while (!done && ((o = getopt (vargc, vargv, optstr)) != -1))
#else
	while ((o = getopt (vargc, vargv, optstr)) != -1)
#endif
	{
		switch (o)
		{

#ifdef WIN32
		case 'M':
		/* either MT or MD is specified
		 * Detect which precompiler runtime lib to use
                 * or pass option to the linker
		*/
			if (strcmp(optarg,"T") == 0) /* MT is specified */
			    strcat (env, pcrmt);
			else
			    if (strcmp(optarg,"D") ==0) /* MD is specified */
			      strcat (env, pcrmd);
			    else /* pass option to the linker */
                                if (narg + optind - actind < MAXNARG)
		                {
			            arg [narg++] = (char*) vargv [actind];
                                }
		                else
			            narg++;
                        done = 1;
				
			break;
		case 'S':
			/* SMT is specified */
			if (strcmp(optarg,"MT") == 0)
				strcat (env, pcrsmt);
			else/* pass option to the linker */
                            if (narg + optind - actind < MAXNARG)
			    {
			        arg [narg++] = (char*) vargv [actind];
			    }
			    else
		                narg++;
                        done = 1;

		        break;
#else
		case 's':
		  strcat (env, link_static);
		  break;
		case 'P':
		  arg[0]=CPPLINK;
		  break;
#endif
		
		case '?':
			err = 1;
			break;
		default:
			if (narg + optind - actind < MAXNARG)
			{
				for (; actind < optind; actind++)
					arg [narg++] = (char*) vargv [actind];
			}
			else
				narg++;
		}
		actind = optind;
	}
	err = err || optind == vargc;
	if (err)
          fprintf (stderr,
#ifdef WIN32
                   "Usage: %s [-<sdkver>] [-BIT32|-BIT64] [-MT|-MD|-SMT] [linkopts] file [file...]\n\n"\
                   "Options:\n",
#else
                   "Usage: %s [-<sdkver>] [-BIT32|-BIT64] [-Ps] [linkopts] file [file...]\n\n"\
                   "Options:\n"\
                   "C++ Linker         ::  -P\n"\
                   "static link        ::  -s\n",
#endif
                   caller);
	if (err)
          fprintf (stderr,
                   "Use 32/64 Bit libs    ::  -BIT32|-BIT64\n"\
                   "Overwrite default sdk ::  -[0-9]+   use -7402 for Version 7.4.2\n",
                   caller);
        if (narg + vargc - optind + 2 >= MAXNARG) {
          fprintf (stderr, "Error-%s: too many arguments\n", caller);
          err = 1;
        }
        if (err)
          exit (1);

#ifndef  WIN32
	arg [narg++] = (char*) exec;
	arg [narg++] = (char*) vargv [optind];
#endif
	unlink (vargv [optind]);
	putenv (env);
	for (; optind < vargc && narg < MAXNARG; optind++, narg++)
	{
		int i;
		char *s;

#ifdef WIN32
		i = vargv[optind] != NULL ? (int)vargv[optind][0]:0;
		if (i== (int)'-' || i== (int)'/')
#else
		if ( *( vargv [optind] ) == '-' )
#endif
		{
			/* assume it is a link option */
			arg [narg] = vargv [optind];
		}
		else
		{
#ifdef WIN32
			/* Set Name for the executabel on first argument
			 * which is not a linker option */
			if (!NameSet) /* Name for output not set yet */
			{
			    arg [narg] = malloc(strlen (vargv[optind]) + strlen (exec)
			    		       + strlen (exe) + 1);
			    strcpy (arg [narg], exec);
			    strcat (arg [narg], vargv [optind]);
			    strcat (arg [narg], exe);
			    NameSet=1;
			    {
				char * tmpFile = malloc
				           (strlen (vargv[optind]) + strlen (ext[0]) + 1);
				strcpy (tmpFile, vargv[optind]);
				s = strchr(tmpFile,'\0');
     				for (i = 0; i < next; i++) /* Test whether to use file or not */
	     			{
		    		    strcpy (s, ext [i]);
			    	    if (stat (tmpFile, &stbuf) == 0)
				    {
					  arg[++narg] = tmpFile;
					  break;
				    }
				}
			    }
			}
			else {
#endif
			/* must be some kind of a file */
			arg [narg] = malloc
				(strlen (vargv[optind]) + strlen (ext[0]) + 1);
			strcpy (arg [narg], vargv [optind]);
			s = strchr (arg [narg], '\0');
			for (i = 0; i < next; i++)
			{
				strcpy (s, ext [i]);
				if (stat (arg [narg], &stbuf) == 0)
				break;
			}
			if (i == next)
			{
				*s = '\0';
				err = 1;
				fprintf (stderr, "Error-%s: no file %s\n",
					caller,	arg [narg]);
			}
#ifdef WIN32
			}
#endif
		}
	}
	if (narg >= MAXNARG)
	{
		fprintf (stderr, "Error-%s: too many arguments\n", caller);
		err = 1;
	}
	
	if (err)
		exit (1);

	{   /* PTS 1108827 */
	  tsp01_RteError          RteError;

          if ( !sqlGetMyModuleFilename (vargv[0], szProgName, sizeof(szProgName), &RteError) ) {
            fprintf ( stderr, "%s: GetModuleFileName failed!\n", caller);
            fprintf ( stderr, "OS_ERROR  %d: %s\n" , RteError.OsErrCode, RteError.OsErrText);
            fprintf ( stderr, "RTE_ERROR %d: %s\n" , RteError.RteErrCode, RteError.RteErrText);
            exit (1);
          }
	}
        sqlGetDBrootFromExecPath (szProgName, szDBRoot, TERM_WITHOUT_DELIMITER_EO01);

        if (szDBRoot[0] == '\0' ||
            (ProgToCall = (char *) strrchr (szProgName , PATH_DELIMITER_EO01)) == NULL) {
          fprintf (stderr, ERR_EXAMINE_DBROOT_OR_FILENAME, szProgName);
          exit (1);
        }
        szPutEnvDBRoot = (char*) malloc (strlen(ENV_SAPDBSDKLIB) + 1 +
                                 strlen(szDBRoot) +
                                 strlen(szSDKPath) +
                                 strlen(szVersionArg) + 30 );
        sprintf(szPutEnvDBRoot, "%s=%s", ENV_SAPDBSDKLIB, szDBRoot);
        if (hasSDK) {
	  strcat(szPutEnvDBRoot, szSDKPath);
	  strcat(szPutEnvDBRoot, szVersionArg);
	}
        strcat(szPutEnvDBRoot, PATHSEP_IP00);
        if (Bit32)
          strcat(szPutEnvDBRoot, szLIBPath);
        else
          strcat(szPutEnvDBRoot, szLIB64Path);
#ifdef DEBUG
        printf("szPutEnvDBRoot=%s\n", szPutEnvDBRoot);
#endif
        putenv (szPutEnvDBRoot);
        szCallSqllist = (char*) malloc (strlen(szDBRoot) +
                                        strlen(szSDKPath) +
                                        strlen(szVersionArg) + 30 );
#ifdef WIN32
	if (hasSDK) {
	  sprintf (szCallSqllist, "%s%s%s%s%cbin%csqllist.bat%s",
		   qte, szDBRoot, szSDKPath, szVersionArg, PATH_DELIMITER_EO01,
		   PATH_DELIMITER_EO01, qte);
	} else {
	  sprintf (szCallSqllist, "%s%s%cbin%csqllist.bat%s",
		   qte, szDBRoot, PATH_DELIMITER_EO01,
		   PATH_DELIMITER_EO01, qte);
	}
#else
	if (hasSDK) {
	  sprintf (szCallSqllist, "%s%s%s%cbin%csqllist",
		   szDBRoot, szSDKPath, szVersionArg, PATH_DELIMITER_EO01,
		   PATH_DELIMITER_EO01);
	} else {
	  sprintf (szCallSqllist, "%s%cbin%csqllist",
		   szDBRoot, PATH_DELIMITER_EO01,
		   PATH_DELIMITER_EO01);
	}
#endif
#ifdef DEBUG
        printf("szCallSqllist=%s\n", szCallSqllist);
#endif
	sqllist = POPEN (szCallSqllist, "r");
        free(szPutEnvDBRoot);
        free(szCallSqllist);
	if (sqllist == NULL)
	{
		fprintf (stderr, "Error-%s: sqllist not found\n", caller);
		exit (1);
	}
	extarg = (char *) malloc (MAXARGL);
	while (arg [narg] = malloc (MAXARGL+2),
		fgets (extarg, MAXARGL, sqllist) != 0)
	/* sqllist outputs the runtime library list */
	{
		char *s = strchr (extarg, '\n');

		if (s == NULL)
		{
			fprintf (stderr,
				"Error-%s: sqllist line too long: %s\n",
				caller, extarg);
			exit (1);
		}
		if (++narg >= MAXNARG)
		{
			fprintf (stderr,
				"Error-%s: too many lines in sqllist\n"
				"last line read: %s\n", caller, arg [narg-1]);
			exit (1);
		}
		*s = '\0';
 		strcpy (arg[narg-1], qte);
 		strcat (arg[narg-1], extarg);
 		strcat (arg[narg-1], qte);
	}
	free (extarg);
	if (narg >= MAXNARG)
	{
		fprintf (stderr,
			"Error-%s: too many lines in sqllist\n"
			"last line read: %s\n", caller, arg [narg-1]);
		exit (1);
	}
&if $MACH = HP9
	arg [narg++] = "+DA1.0";
	arg [narg++] = "+DS1.0";
&endif
&if $MACH = PA11
	arg [narg++] = "+DA1.1";
	arg [narg++] = "+DS2.0";
&endif
&if $MACH = PA20W
	arg [narg++] = "+DA2.0W";
	arg [narg++] = "+DS2.0";
&endif
&if $MACH = HP_IA64
        arg [narg++] = "+DD64";
&endif
#ifdef BIT64
& if $MACH = SUN
    arg [narg++] = "-xtarget=ultra";
    arg [narg++] = "-xarch=v9";
& elif $MACH = _IBMR2
    arg [narg++] = "-q64";
& elif $MACH = NMP
    arg [narg++] = "-Klp64";
    arg [narg++] = "-Kpthread";
& elif $MACH = SDBonPPC64
    arg [narg++] = "-m64";
    arg [narg++] = "-Wl,-melf64ppc";
&if $OSSPEC = SVR4
    arg [narg++] = "-lxnet";
&endif
& endif
#else
&if $MACH = NMP
    arg [narg++] = "-Kpthread";
&if $OSSPEC = SVR4
    arg [narg++] = "-lxnet";
&endif
& endif
#endif
	arg [narg++] = 0;
	return arg;
}
.CM *-END-* code ----------------------------------------
.SP 2
***********************************************************
