1 /*
2  * Copyright (C) 1998-2001  Mark Hessling <M.Hessling@qut.edu.au>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  *
18  * Mark Hessling  M.Hessling@qut.edu.au  http://www.lightlink.com/hessling/
19  */
20 
21 static char RCSid[] = "$Id: loader.c,v 1.21 2005/07/03 07:58:51 mark Exp $";
22 
23 #include "rxpack.h"
24 
25 #ifndef R_OK
26 # define R_OK 4
27 #endif
28 
29 #ifdef HAVE_PROTO
30 # if !defined(HAVE_GETOPT)
31 int getopt( int argc, char *argv[], char *optstring );
32 # endif
33 #else
34 # if !defined(HAVE_GETOPT)
35 int getopt( );
36 # endif
37 #endif
38 
39 int gotOutput = 0;
40 
41 /* These are required by the getopt() function */
42 extern char *optarg;
43 extern int  optind;
44 
45 extern PackageInitialiser *GETPACKAGEINITIALISER();
46 extern PackageTerminator *GETPACKAGETERMINATOR();
47 extern RexxSubcomHandler *GETPACKAGESUBCOMHANDLER();
48 extern RexxExitHandler *GETPACKAGEINITHANDLER();
49 extern RexxFunction *GETPACKAGEFUNCTIONS();
50 extern RxPackageConstantDef *GETPACKAGECONSTANTS();
51 extern void PACKAGEUSAGE();
52 
53 #if defined(RUN_AS_GUI)
54 # include <windows.h>
55 # define STARTUPCONSOLE() StartupConsole()
56 # define CLOSEDOWNCONSOLE() ClosedownConsole()
StartupConsole(void)57 void StartupConsole( void )
58 {
59    if ( gotOutput == 0 )
60    {
61       AllocConsole();
62       freopen( "conin$", "r", stdin );
63       freopen( "conout$", "w", stdout );
64       freopen( "conout$", "w", stderr );
65       gotOutput = 1;
66    }
67 }
ClosedownConsole(void)68 void ClosedownConsole( void )
69 {
70    if ( gotOutput )
71    {
72       fprintf( stderr, "\n==> Press ENTER key to close this window. <==" );
73       getchar();
74       fclose(stdin);
75       fclose(stdout);
76       fclose(stderr);
77       gotOutput = 0;
78    }
79 }
80 
RxExitHandlerForSayTraceRedirection(REH_ARG0_TYPE ExitNumber,REH_ARG1_TYPE Subfunction,REH_ARG2_TYPE ParmBlock)81 REH_RETURN_TYPE RxExitHandlerForSayTraceRedirection
82 
83 #if defined(HAVE_PROTO)
84    ( REH_ARG0_TYPE ExitNumber, REH_ARG1_TYPE Subfunction, REH_ARG2_TYPE ParmBlock )
85 #else
86    ( ExitNumber, Subfunction, ParmBlock )
87    REH_ARG0_TYPE ExitNumber;    /* code defining the exit function    */
88    REH_ARG1_TYPE Subfunction;   /* code defining the exit subfunction */
89    REH_ARG2_TYPE ParmBlock;     /* function dependent control block   */
90 #endif
91 {
92    long i = 0;
93    int rc = 0;
94 
95    StartupConsole();
96 
97    switch( Subfunction )
98    {
99       case RXSIOSAY:
100       {
101          RXSIOSAY_PARM *say_parm = (RXSIOSAY_PARM *)ParmBlock;
102          if ( say_parm->rxsio_string.strptr != NULL )
103          {
104             for( i = 0; i < (long)say_parm->rxsio_string.strlength; i++ )
105             {
106                fputc( ( char )say_parm->rxsio_string.strptr[i], stdout );
107             }
108          }
109          fputc( '\n', stdout );
110          rc = RXEXIT_HANDLED;
111          break;
112       }
113       case RXSIOTRC:
114       {
115          RXSIOTRC_PARM *trc_parm = (RXSIOTRC_PARM *)ParmBlock;
116          if ( trc_parm->rxsio_string.strptr != NULL )
117          {
118             for( i = 0; i < (long)trc_parm->rxsio_string.strlength; i++ )
119             {
120                fputc( ( char )trc_parm->rxsio_string.strptr[i], stderr );
121             }
122          }
123          fputc( '\n', stderr );
124          rc = RXEXIT_HANDLED;
125          break;
126       }
127       case RXSIOTRD:
128       {
129          RXSIOTRD_PARM *trd_parm = (RXSIOTRD_PARM *)ParmBlock;
130          int i = 0, ch = 0;
131          do
132          {
133             if ( i < 256 )
134                trd_parm->rxsiotrd_retc.strptr[i++] = ch = getc( stdin ) ;
135          } while( ch != '\012' && (ch != EOF ) ) ;
136          trd_parm->rxsiotrd_retc.strlength = i - 1;
137          rc = RXEXIT_HANDLED;
138          break;
139       }
140       case RXSIODTR:
141       {
142          RXSIODTR_PARM *dtr_parm = (RXSIODTR_PARM *)ParmBlock;
143          int i = 0, ch = 0;
144          do
145          {
146             if ( i < 256 )
147                dtr_parm->rxsiodtr_retc.strptr[i++] = ch = getc( stdin ) ;
148          } while( ch != '\012' && (ch != EOF ) ) ;
149          dtr_parm->rxsiodtr_retc.strlength = i - 1;
150          rc = RXEXIT_HANDLED;
151          break;
152       }
153       default:
154          rc = RXEXIT_NOT_HANDLED;
155          break;
156    }
157    return rc;
158 }
159 #else
160 # define STARTUPCONSOLE()
161 # define CLOSEDOWNCONSOLE()
162 #endif
163 
164 /*-----------------------------------------------------------------------------
165  * Checks to see if supplied filename is readable.
166  *----------------------------------------------------------------------------*/
file_readable(char * filename)167 static int file_readable
168 
169 #ifdef HAVE_PROTO
170    (char *filename)
171 #else
172    (filename)
173    char  *filename;
174 #endif
175 {
176    if ((access(filename,R_OK)) == (-1))
177       return(0);
178    else
179       return(1);
180 }
181 
182 
183 /*-----------------------------------------------------------------------------
184  * Processing starts here for stand-alone rexxsql executable...
185  *----------------------------------------------------------------------------*/
main(int argc,char * argv[])186 int main
187 
188 #if HAVE_PROTO
189    (int argc, char *argv[])
190 #else
191    (argc, argv)
192    int   argc;
193    char  *argv[];
194 #endif
195 {
196    int c=0;
197    char *ProgramName=NULL;
198    FILE *fp;
199    long i=0, ArgCount=0;
200    int interactive = FALSE;
201    int rc=0;
202    RXSTRING retstr;
203    CHAR retbuf[RETBUFLEN];
204    CHAR initexitname[100];
205    RXSTRING ArgList;
206 #if !defined(DYNAMIC_LIBRARY)
207 # if defined(USE_WINREXX) || defined(USE_QUERCUS)
208    RXSYSEXIT ExitList[3];
209 # elif defined(RUN_AS_GUI)
210    RXSYSEXIT ExitList[3];
211 # else
212    RXSYSEXIT ExitList[2];
213 # endif
214 #endif
215    RxPackageGlobalDataDef MyGlob, *RxPackageGlobalData;
216 
217    memset( (char *)&MyGlob, 0, sizeof( RxPackageGlobalDataDef ) );
218 
219    strcpy( MyGlob.RxTraceFileName, "stderr" );
220    strcpy( MyGlob.ConstantPrefix, "!" );
221    MyGlob.RxTraceFilePointer = stderr;
222    /*
223     * Get any program options.
224     */
225    while ((c = getopt(argc, argv, "Dudivh?f:")) != EOF)
226    {
227       switch (c)
228       {
229          case 'f':
230             strcpy( MyGlob.RxTraceFileName, optarg );
231             break;
232          case 'v':
233             MyGlob.RxRunFlags |= MODE_VERBOSE;
234             break;
235          case 'd':
236             MyGlob.RxRunFlags |= MODE_DEBUG;
237             break;
238          case 'D':
239             MyGlob.RxRunFlags |= MODE_INTERNAL;
240             break;
241          case 'i':
242             interactive = TRUE;
243             break;
244          case 'u':
245             DeregisterRxFunctions( &MyGlob, GETPACKAGEFUNCTIONS(), 1 );
246             return(0);
247             break;
248          case 'h':
249          default :
250             STARTUPCONSOLE();
251             PACKAGEUSAGE();
252             CLOSEDOWNCONSOLE();
253             exit(1);
254       }
255    }
256 
257    /*
258     * Check if any more arguments are presented
259     */
260    if (optind >= argc)
261    {
262       if (interactive)
263       {
264          ProgramName = tmpnam(NULL);
265          if ((fp = fopen(ProgramName,"w")) == NULL)
266          {
267             STARTUPCONSOLE();
268             (void)fprintf(stderr, "Could not create temporary file for stdin\n");
269             CLOSEDOWNCONSOLE();
270             exit(REXX_FAIL);
271          }
272          for ( ; ; )
273          {
274             if ((i = getc(stdin)) == EOF)
275                break;
276             putc(i,fp);
277          }
278          (void)fclose(fp);
279       }
280       else
281       {
282          STARTUPCONSOLE();
283          PACKAGEUSAGE();
284          CLOSEDOWNCONSOLE();
285          exit(1);
286       }
287    }
288    else
289    {
290       /*
291        * Next argument is the name of the Rexx program...
292        */
293       ProgramName = argv[optind++];
294       /*
295        * ... and must be readable.
296        */
297 
298       if (!file_readable(ProgramName))
299       {
300          STARTUPCONSOLE();
301          (void)fprintf(stderr, "Could not read file: %s\n",ProgramName);
302          CLOSEDOWNCONSOLE();
303          exit(REXX_FAIL);
304       }
305    }
306 
307    /*
308     * Get number of arguments to the Rexx program
309     */
310    ArgCount = argc - optind;
311 
312    /*
313     * Build an array of arguments if any.
314     */
315    if (ArgCount)
316    {
317       int len=0;
318 
319       for ( i = optind; i < argc; i++ )
320       {
321          len += strlen( (char *)argv[i] );
322       }
323       if ( ( ArgList.strptr = (RXSTRING_STRPTR_TYPE)malloc( len + 1 + ArgCount) ) == (RXSTRING_STRPTR_TYPE)NULL )
324       {
325          STARTUPCONSOLE();
326          (void)fprintf( stderr, "%s: out of memory\n", argv[0] );
327          CLOSEDOWNCONSOLE();
328          exit( REXX_FAIL );
329       }
330       strcpy( ArgList.strptr, "" );
331       for ( i = optind; i < argc; i++ )
332       {
333          strcat( ArgList.strptr, (RXSTRING_STRPTR_TYPE)argv[optind++] );
334          if ( i != argc )
335             strcat( ArgList.strptr, (RXSTRING_STRPTR_TYPE)" " );
336       }
337       ArgList.strlength = ArgCount + len - 1;
338    }
339    else
340    {
341       ArgList.strptr = NULL;
342       ArgList.strlength = 0;
343    }
344 
345    /*
346     * Initialise the package interface, but don't set the trace file
347     */
348    RxPackageGlobalData = InitRxPackage( &MyGlob, GETPACKAGEINITIALISER(), &rc );
349    if ( rc != 0 )
350       return( rc );
351    /*
352     * Register all external functions
353     */
354    if ( ( rc = RegisterRxFunctions( RxPackageGlobalData, GETPACKAGEFUNCTIONS(), RXPACKAGENAME ) ) != 0 )
355       return( rc );
356    /*
357     * Register a default subcommand handler to pass commands to the OS
358     */
359    if ( ( rc = RegisterRxSubcom( RxPackageGlobalData, GETPACKAGESUBCOMHANDLER() ) ) != 0 )
360       return( rc );
361    /*
362     * Register a RXINI handler to set the package constants
363     */
364    sprintf( initexitname, "%s%s", RXPACKAGENAME, "INIT" );
365    if ( ( rc = RegisterRxInit( RxPackageGlobalData, GETPACKAGEINITHANDLER(), initexitname ) ) != 0 )
366       return( rc );
367    FunctionPrologue( RxPackageGlobalData, GETPACKAGEINITIALISER(), RXPACKAGENAME, 0L, NULL );
368    /*
369     * Set up the system exit for the Say and Trace redirection and RxIni
370     */
371 #if !defined(DYNAMIC_LIBRARY)
372 # if defined(USE_WINREXX) || defined(USE_QUERCUS)
373    ExitList[0].sysexit_name = RXPACKAGENAME;
374    ExitList[0].sysexit_code = RXSIO;
375    ExitList[1].sysexit_name = initexitname;
376    ExitList[1].sysexit_code = RXINI;
377    ExitList[2].sysexit_code = RXENDLST;
378 #elif defined(RUN_AS_GUI)
379    /*
380     * Register the system exit
381     */
382    RexxRegisterExitExe( ( RREE_ARG0_TYPE )RXPACKAGENAME,
383                           ( RREE_ARG1_TYPE )RxExitHandlerForSayTraceRedirection,
384                           ( RREE_ARG2_TYPE )NULL);
385    ExitList[0].sysexit_name = RXPACKAGENAME;
386    ExitList[0].sysexit_code = RXSIO;
387    ExitList[1].sysexit_name = initexitname;
388    ExitList[1].sysexit_code = RXINI;
389    ExitList[2].sysexit_code = RXENDLST;
390 # else
391    ExitList[0].sysexit_name = initexitname;
392    ExitList[0].sysexit_code = RXINI;
393    ExitList[1].sysexit_code = RXENDLST;
394 # endif
395 #endif
396 
397    MAKERXSTRING( retstr, retbuf, sizeof( retbuf ) );
398    /*
399     * Execute the Rexx script. Use RXCOMMAND mode so that the Rexx program
400     * expects the same parameter list if called directly via the Rexx
401     * interpreter.
402     */
403    RexxStart( ( RS_ARG0_TYPE )(ArgCount) ? 1 : 0,
404               ( RS_ARG1_TYPE )&ArgList,
405               ( RS_ARG2_TYPE )ProgramName,
406               ( RS_ARG3_TYPE )NULL,
407               ( RS_ARG4_TYPE )RXPACKAGENAME,
408               ( RS_ARG5_TYPE )RXCOMMAND,
409 #if !defined(DYNAMIC_LIBRARY)
410               ( RS_ARG6_TYPE )ExitList,
411 #elif defined(RUN_AS_GUI)
412               ( RS_ARG6_TYPE )ExitList,
413 #else
414               ( RS_ARG6_TYPE )NULL,
415 #endif
416               ( RS_ARG7_TYPE )&rc,
417               ( RS_ARG8_TYPE )&retstr);
418 
419    if ( RxPackageGlobalData
420    &&   !RxPackageGlobalData->terminated )
421    {
422       rc = FunctionEpilogue( RxPackageGlobalData, RXPACKAGENAME, (ULONG)rc );
423       /*
424        * Terminate the package interface.
425        */
426       (void)TermRxPackage( &RxPackageGlobalData, GETPACKAGETERMINATOR(), GETPACKAGEFUNCTIONS(), RXPACKAGENAME, 0 );
427       RxPackageGlobalData = NULL;
428    }
429 
430    if ( ArgList.strptr )
431       free(ArgList.strptr);
432    /*
433     * Return the exit value from the program. This is useful for UNIX/DOS etc.
434     * if the value is kept to 0-success, small positive numbers (say < 100)
435     * to indicate errors!
436     */
437    if ( interactive )
438       unlink( ProgramName );
439 
440    CLOSEDOWNCONSOLE();
441    return rc;
442 }
443 
444 #if defined(RUN_AS_GUI)
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)445 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
446 {
447    int rc;
448    rc = main( __argc, __argv );
449    return rc;
450 }
451 #endif
452