3 * Copyright © 2001 Novell, Inc. All Rights Reserved.
5 * You may distribute under the terms of either the GNU General Public
6 * License or the Artistic License, as specified in the README file.
12 * DESCRIPTION : Main function, Commandline handlers and shutdown for NetWare implementation of Perl.
14 * Date : January 2001.
43 // Thread group ID for this NLM. Set only by main when the NLM is initially loaded,
44 // so it should be okay for this to be global.
49 int gThreadGroupID = -1;
53 // Global to kill all running scripts during NLM unload.
55 bool gKillAll = FALSE;
58 // Global structure needed by OS to register command parser.
59 // fnRegisterCommandLineHandler gets called only when the NLM is initially loaded,
60 // so it should be okay for this structure to be a global.
62 static struct commandParserStructure gCmdParser = {0,0,0};
65 // True if the command-line parsing procedure has been registered with the OS.
66 // Altered only during initial NLM loading or unloading so it should be okay as a global.
68 BOOL gCmdProcInit = FALSE;
71 // Array to hold the screen name for all new screens.
73 char sPerlScreenName[MAX_DN_BYTES * sizeof(char)] = {'\0'};
76 // Structure to pass data when spawning new threadgroups to run scripts.
78 typedef struct tagScriptData
85 #define CS_CMD_NOT_FOUND -1 // Console command not found
86 #define CS_CMD_FOUND 0 // Console command found
89 The stack size is make 256k from the earlier 64k since complex scripts (charnames.t and complex.t)
90 were failing with the lower stack size. In fact, we tested with 128k and it also failed
91 for the complexity of the script used. In case the complexity of a script is increased,
92 then this might warrant an increase in the stack size. But instead of simply giving a very large stack,
93 a trade off was required and we stopped at 256k!
95 #define PERL_COMMAND_STACK_SIZE (256*1024L) // Stack size of thread that runs a perl script from command line
97 #define MAX_COMMAND_SIZE 512
100 #define kMaxValueLen 1024 // Size of the Environment variable value limited/truncated to 1024 characters.
101 #define kMaxVariableNameLen 256 // Size of the Environment variable name.
104 typedef void (*PFUSEACCURATECASEFORPATHS) (int);
105 typedef LONG (*PFGETFILESERVERMAJORVERSIONNUMBER) (void);
106 typedef void (*PFUCSTERMINATE) (); // For ucs terminate.
107 typedef void (*PFUNAUGMENTASTERISK)(BOOL); // For longfile support.
108 typedef int (*PFFSETMODE) (FILE *, char *);
111 // local function prototypes
113 void fnSigTermHandler(int sig);
114 void fnRegisterCommandLineHandler(void);
115 void fnLaunchPerl(void* context);
116 void fnSetUpEnvBlock(char*** penv);
117 void fnDestroyEnvBlock(char** env);
118 int fnFpSetMode(FILE* fp, int mode, int *err);
120 void fnGetPerlScreenName(char *sPerlScreenName);
125 /*============================================================================================
129 Description : Called when the NLM is first loaded. Registers the command-line handler
130 and then terminates-stay-resident.
132 Parameters : argc (IN) - No of Input strings.
133 argv (IN) - Array of Input strings.
137 ==============================================================================================*/
139 void main(int argc, char *argv[])
141 char sysCmdLine[MAX_COMMAND_SIZE] = {'\0'};
142 char cmdLineCopy[sizeof(PERL_COMMAND_NAME)+sizeof(sysCmdLine)+2] = {'\0'};
144 ScriptData* psdata = NULL;
147 // Keep this thread alive, since we use the thread group id of this thread to allocate memory on.
148 // When we unload the NLM, clib will tear the thread down.
151 gThreadHandle = kCurrentThread();
153 gThreadGroupID = GetThreadGroupID ();
156 signal (SIGTERM, fnSigTermHandler);
157 fnInitGpfGlobals(); // For importing the CLIB calls in place of the Watcom calls
158 fnInitializeThreadInfo();
161 // Ensure that we have a "temp" directory
163 if (access(DEFTEMP, 0) != 0)
166 // Create the file NUL if not present. This is done only once per NLM load.
167 // This is required for -e.
168 // Earlier verions were creating temporary files (in perl.c file) for -e.
169 // Now, the technique of creating temporary files are removed since they were
170 // fragile or insecure or slow. It now uses the memory by setting
171 // the BIT_BUCKET to "nul" on Win32, which is equivalent to /dev/nul of Unix.
172 // Since there is no equivalent of /dev/nul on NetWare, the work-around is that
173 // we create a file called "nul" and the BIT_BUCKET is set to "nul".
174 // This makes sure that -e works on NetWare too without the creation of temporary files
175 // in -e code in perl.c
177 char sNUL[MAX_DN_BYTES] = {'\0'};
179 strcpy(sNUL, DEFPERLROOT);
180 strcat(sNUL, "\\nul");
181 if (access((const char *)sNUL, 0) != 0)
183 // The file, "nul" is not found and so create the file.
186 fp = fopen((const char *)sNUL, (const char *)"w");
191 fnRegisterCommandLineHandler(); // Register the command line handler
192 SynchronizeStart(); // Restart the NLM startup process when using synchronization mode.
194 fnGetPerlScreenName(sPerlScreenName); // Get the screen name. Done only once per NLM load.
197 // If the command line has two strings, then the first has to be "Perl" and the second is assumed
198 // to be a script to be run. If only one string (i.e., Perl) is input, then there is nothing to do!
200 if ((argc > 1) && getcmd(sysCmdLine))
202 strcpy(cmdLineCopy, PERL_COMMAND_NAME);
203 strcat(cmdLineCopy, (char *)" "); // Space between the Perl Command and the input script name.
204 strcat(cmdLineCopy, sysCmdLine); // The command line parameters built into
206 // Create a safe copy of the command line and pass it to the
207 // new thread for parsing. The new thread will be responsible
208 // to delete it when it is finished with it.
210 psdata = (ScriptData *) malloc(sizeof(ScriptData));
213 psdata->m_commandLine = NULL;
214 psdata->m_commandLine = (char *) malloc(MAX_DN_BYTES * sizeof(char));
215 if(psdata->m_commandLine)
217 strcpy(psdata->m_commandLine, cmdLineCopy);
218 psdata->m_fromConsole = TRUE;
221 // kStartThread((char *)"ConsoleHandlerThread", fnLaunchPerl, NULL, PERL_COMMAND_STACK_SIZE, (void *)psdata);
222 // Establish a new thread within a new thread group.
223 BeginThreadGroup(fnLaunchPerl, NULL, PERL_COMMAND_STACK_SIZE, (void*)psdata);
225 // Start a new thread in its own thread group
226 BeginThreadGroup(fnLaunchPerl, NULL, PERL_COMMAND_STACK_SIZE, (void*)psdata);
241 // Keep this thread alive, since we use the thread group id of this thread to allocate memory on.
242 // When we unload the NLM, clib will tear the thread down.
245 kSuspendThread(gThreadHandle);
247 SuspendThread(GetThreadID());
256 /*============================================================================================
258 Function : fnSigTermHandler
260 Description : Called when the NLM is unloaded; used to unregister the console command handler.
262 Parameters : sig (IN)
266 ==============================================================================================*/
268 void fnSigTermHandler(int sig)
274 kResumeThread(gThreadHandle);
277 // Unregister the command line handler.
281 UnRegisterConsoleCommand (&gCmdParser);
282 gCmdProcInit = FALSE;
285 // Free the global environ buffer
288 // Kill running scripts.
290 if (!fnTerminateThreadInfo())
292 ConsolePrintf("Terminating Perl scripts...\n");
295 // fnTerminateThreadInfo will be run for 5 threads. If more threads/scripts are run,
296 // then the NLM will unload without terminating the thread info and leaks more memory.
297 // If this number is increased to reduce memory leaks, then it will unnecessarily take more time
298 // to unload when there are a smaller no of threads. Since this is a rare case, the no is kept as 5.
300 while (!fnTerminateThreadInfo() && k < 5)
307 // Delete the file, "nul" if present since the NLM is unloaded.
309 char sNUL[MAX_DN_BYTES] = {'\0'};
311 strcpy(sNUL, DEFPERLROOT);
312 strcat(sNUL, "\\nul");
313 if (access((const char *)sNUL, 0) == 0)
315 // The file, "nul" is found and so delete it.
316 unlink((const char *)sNUL);
323 /*============================================================================================
325 Function : fnCommandLineHandler
327 Description : Gets called by OS when someone enters an unknown command at the system console,
328 after this routine is registered by RegisterConsoleCommand.
329 For the valid command we just spawn a thread with enough stack space
330 to actually run the script.
332 Parameters : screenID (IN) - id for the screen.
333 cmdLine (IN) - Command line string.
337 ==============================================================================================*/
339 LONG fnCommandLineHandler (LONG screenID, BYTE * cmdLine)
341 ScriptData* psdata=NULL;
342 int OsThrdGrpID = -1;
343 LONG retCode = CS_CMD_FOUND;
348 // Initialisation for MPK_ON
357 if (gThreadGroupID != -1)
358 OsThrdGrpID = SetThreadGroupID (gThreadGroupID);
362 cptr = fnSkipWhite(cmdLine); // Skip white spaces.
363 if ((strnicmp(cptr, PERL_COMMAND_NAME, strlen(PERL_COMMAND_NAME)) == 0) &&
364 ((cptr[strlen(PERL_COMMAND_NAME)] == ' ') ||
365 (cptr[strlen(PERL_COMMAND_NAME)] == '\t') ||
366 (cptr[strlen(PERL_COMMAND_NAME)] == '\0')))
368 // Create a safe copy of the command line and pass it to the new thread for parsing.
369 // The new thread will be responsible to delete it when it is finished with it.
371 psdata = (ScriptData *) malloc(sizeof(ScriptData));
374 psdata->m_commandLine = NULL;
375 psdata->m_commandLine = (char *) malloc(MAX_DN_BYTES * sizeof(char));
376 if(psdata->m_commandLine)
378 strcpy(psdata->m_commandLine, (char *)cmdLine);
379 psdata->m_fromConsole = TRUE;
382 // kStartThread((char *)"ConsoleHandlerThread", fnLaunchPerl, NULL, PERL_COMMAND_STACK_SIZE, (void *)psdata);
383 // Establish a new thread within a new thread group.
384 BeginThreadGroup(fnLaunchPerl, NULL, PERL_COMMAND_STACK_SIZE, (void*)psdata);
386 // Start a new thread in its own thread group
387 BeginThreadGroup(fnLaunchPerl, NULL, PERL_COMMAND_STACK_SIZE, (void*)psdata);
394 retCode = CS_CMD_NOT_FOUND;
398 retCode = CS_CMD_NOT_FOUND;
401 retCode = CS_CMD_NOT_FOUND;
407 if (OsThrdGrpID != -1)
408 SetThreadGroupID (OsThrdGrpID);
417 /*============================================================================================
419 Function : fnRegisterCommandLineHandler
421 Description : Registers the console command-line parsing function with the OS.
427 ==============================================================================================*/
429 void fnRegisterCommandLineHandler(void)
431 // Allocates resource tag for Console Command
432 if ((gCmdParser.RTag =
433 AllocateResourceTag (GetNLMHandle(), (char *)"Console Command", ConsoleCommandSignature)) != 0)
435 gCmdParser.parseRoutine = fnCommandLineHandler; // Set the Console Command parsing routine.
436 RegisterConsoleCommand (&gCmdParser); // Registers the Console Command parsing function
445 /*============================================================================================
447 Function : fnSetupNamespace
449 Description : Sets the name space of the current threadgroup to the long name space.
455 ==============================================================================================*/
457 void fnSetupNamespace(void)
459 SetCurrentNameSpace(NWOS2_NAME_SPACE);
462 //LATER: call SetTargetNameSpace(NWOS2_NAME_SPACE)? Currently, if
463 // I make this call, then CPerlExe::Rename fails in certain cases,
464 // and it isn't clear why. Looks like a CLIB bug...
465 // SetTargetNameSpace(NWOS2_NAME_SPACE);
467 //Uncommented that above call, retaining the comment so that it will be easy
468 //to revert back if there is any problem - sgp - 10th May 2000
470 //Commented again, since Perl debugger had some problems because of
471 //the above call - sgp - 20th June 2000
474 // if running on Moab, call UseAccurateCaseForPaths. This API
475 // does bad things on 4.11 so we call only for Moab.
476 PFGETFILESERVERMAJORVERSIONNUMBER pf_getfileservermajorversionnumber = NULL;
477 pf_getfileservermajorversionnumber = (PFGETFILESERVERMAJORVERSIONNUMBER)
478 ImportSymbol(GetNLMHandle(), (char *)"GetFileServerMajorVersionNumber");
479 if (pf_getfileservermajorversionnumber && ((*pf_getfileservermajorversionnumber)() > 4))
481 PFUSEACCURATECASEFORPATHS pf_useaccuratecaseforpaths = NULL;
482 pf_useaccuratecaseforpaths = (PFUSEACCURATECASEFORPATHS)
483 ImportSymbol(GetNLMHandle(), (char *)"UseAccurateCaseForPaths");
484 if (pf_useaccuratecaseforpaths)
485 (*pf_useaccuratecaseforpaths)(TRUE);
487 PFUNAUGMENTASTERISK pf_unaugmentasterisk = NULL;
488 pf_unaugmentasterisk = (PFUNAUGMENTASTERISK)
489 ImportSymbol(GetNLMHandle(), (char *)"UnAugmentAsterisk");
490 if (pf_unaugmentasterisk)
491 (*pf_unaugmentasterisk)(TRUE);
501 /*============================================================================================
503 Function : fnLaunchPerl
505 Description : Parse the command line into argc/argv style parameters and then run the script.
507 Parameters : context (IN) - void* that will be typecasted to ScriptDate structure.
511 ==============================================================================================*/
513 void fnLaunchPerl(void* context)
515 char* defaultDir = NULL;
516 char curdir[_MAX_PATH] = {'\0'};
517 ScriptData* psdata = (ScriptData *) context;
519 unsigned int moduleHandle = 0;
520 int currentThreadGroupID = -1;
529 if (psdata->m_fromConsole)
531 // get the default working directory name
533 defaultDir = fnNwGetEnvironmentStr("PERL_ROOT", DEFPERLROOT);
536 defaultDir = getcwd(curdir, sizeof(curdir)-1);
538 // set long name space
542 // make the working directory the current directory if from console
544 if (psdata->m_fromConsole)
553 // May have to check this, I am blindly calling UCSTerminate, irrespective of
554 // whether it is initialized or not
555 // Copied from the previous Perl - sgp - 31st Oct 2000
556 moduleHandle = FindNLMHandle("UCSCORE.NLM");
559 PFUCSTERMINATE ucsterminate = (PFUCSTERMINATE)ImportSymbol(moduleHandle, "therealUCSTerminate");
560 if (ucsterminate!=NULL)
565 if (psdata->m_fromConsole)
567 // change thread groups for the call to free the memory
568 // allocated before the new thread group was started
572 if (gThreadGroupID != -1)
573 currentThreadGroupID = SetThreadGroupID (gThreadGroupID);
580 if(psdata->m_commandLine)
582 free(psdata->m_commandLine);
583 psdata->m_commandLine = NULL;
594 if (currentThreadGroupID != -1)
595 SetThreadGroupID (currentThreadGroupID);
599 // kExitThread(NULL);
601 // just let the thread terminate by falling off the end of the
602 // function started by BeginThreadGroup
603 // ExitThread(EXIT_THREAD, 0);
612 /*============================================================================================
614 Function : fnRunScript
616 Description : Parses and runs a perl script.
618 Parameters : psdata (IN) - ScriptData structure.
622 ==============================================================================================*/
624 void fnRunScript(ScriptData* psdata)
632 PCOMMANDLINEPARSER pclp = NULL;
634 // Set up the environment block. This will only work on
635 // on Moab; on 4.11 the environment block will be empty.
638 BOOL use_system_console = TRUE;
639 BOOL newscreen = FALSE;
640 int newscreenhandle = 0;
642 // redirect stdin or stdout and run the script
643 FILE* redirOut = NULL;
644 FILE* redirIn = NULL;
645 FILE* redirErr = NULL;
646 FILE* stderr_fp = NULL;
648 int stdin_fd=-1, stdin_fd_dup=-1;
649 int stdout_fd=-1, stdout_fd_dup=-1;
650 int stderr_fd=-1, stderr_fd_dup=-1;
654 // Main callback instance
656 if (fnRegisterWithThreadTable() == FALSE)
660 // parse the command line into argc/argv style:
661 // number of params and char array of params
663 pclp = (PCOMMANDLINEPARSER) malloc(sizeof(COMMANDLINEPARSER));
666 fnUnregisterWithThreadTable();
671 // Initialise the variables
672 pclp->m_isValid = TRUE;
673 pclp->m_redirInName = NULL;
674 pclp->m_redirOutName = NULL;
675 pclp->m_redirErrName = NULL;
676 pclp->m_redirBothName = NULL;
677 pclp->nextarg = NULL;
678 pclp->sSkippedToken = NULL;
680 pclp->new_argv = NULL;
683 pclp->m_qSemaphore = NULL;
685 pclp->m_qSemaphore = 0L;
688 pclp->m_noScreen = 0;
689 pclp->m_AutoDestroy = 0;
691 pclp->m_argv_len = 1;
695 pclp->m_argv = (char **) malloc(pclp->m_argv_len * sizeof(char *));
696 if (pclp->m_argv == NULL)
701 fnUnregisterWithThreadTable();
705 pclp->m_argv[0] = (char *) malloc(MAX_DN_BYTES * sizeof(char));
706 if (pclp->m_argv[0] == NULL)
714 fnUnregisterWithThreadTable();
719 // Parse the command line
720 fnCommandLineParser(pclp, (char *)psdata->m_commandLine, FALSE);
721 if (!pclp->m_isValid)
725 for(i=0; i<pclp->m_argv_len; i++)
727 if(pclp->m_argv[i] != NULL)
729 free(pclp->m_argv[i]);
730 pclp->m_argv[i] = NULL;
741 pclp->nextarg = NULL;
743 if(pclp->sSkippedToken != NULL)
745 free(pclp->sSkippedToken);
746 pclp->sSkippedToken = NULL;
749 if(pclp->m_redirInName)
751 free(pclp->m_redirInName);
752 pclp->m_redirInName = NULL;
754 if(pclp->m_redirOutName)
756 free(pclp->m_redirOutName);
757 pclp->m_redirOutName = NULL;
759 if(pclp->m_redirErrName)
761 free(pclp->m_redirErrName);
762 pclp->m_redirErrName = NULL;
764 if(pclp->m_redirBothName)
766 free(pclp->m_redirBothName);
767 pclp->m_redirBothName = NULL;
771 // Signal a semaphore, if indicated by "-{" option, to indicate that
772 // the script has terminated and files are closed
774 if (pclp->m_qSemaphore != 0)
777 kSemaphoreSignal(pclp->m_qSemaphore);
779 SignalLocalSemaphore(pclp->m_qSemaphore);
786 fnUnregisterWithThreadTable();
791 // Simulating a shell on NetWare can be difficult. If you don't
792 // create a new screen for the script to run in, you can output to
793 // the console but you can't get any input from the console. Therefore,
794 // every invocation of perl potentially needs its own screen unless
795 // you are running either "perl -h" or "perl -v" or you are redirecting
796 // stdin from a file.
798 // So we need to create a new screen and set that screen as the current
799 // screen when running any script launched from the console that is not
800 // "perl -h" or "perl -v" and is not redirecting stdin from a file.
802 // But it would be a little weird if we didn't create a new screen only
803 // in the case when redirecting stdin from a file; in only that case,
804 // stdout would be the console instead of a new screen.
806 // There is also the issue of standard err. In short, we might as well
807 // create a new screen no matter what is going on with redirection, just
808 // for the sake of consistency.
810 // In summary, we should a create a new screen and make that screen the
811 // current screen unless one of the following is true:
812 // * The command is "perl -h"
813 // * The command is "perl -v"
814 // * The script was launched by another perl script. In this case,
815 // the screen belonging to the parent perl script should probably be
816 // the same screen for this process. And it will be if use BeginThread
817 // instead of BeginThreadGroup when launching Perl from within a Perl
820 // In those cases where we create a new screen we should probably also display
824 use_system_console = pclp->m_noScreen ||
825 ((pclp->m_argc == 2) && (strcmp(pclp->m_argv[1], (char *)"-h") == 0)) ||
826 ((pclp->m_argc == 2) && (strcmp(pclp->m_argv[1], (char *)"-v") == 0));
828 newscreen = (!use_system_console) && psdata->m_fromConsole;
832 newscreenhandle = CreateScreen(sPerlScreenName, 0);
834 DisplayScreen(newscreenhandle);
836 else if (use_system_console)
837 CreateScreen((char *)"System Console", 0);
840 if (pclp->m_redirInName)
842 if ((stdin_fd = fileno(stdin)) != -1)
844 stdin_fd_dup = dup(stdin_fd);
845 if (stdin_fd_dup != -1)
847 redirIn = fdopen (stdin_fd_dup, (char const *)"r");
849 stdin = freopen (pclp->m_redirInName, (char const *)"r", redirIn);
853 // undo the redirect, if possible
854 stdin = fdopen(stdin_fd, (char const *)"r");
861 The below code stores the handle for the existing stdout to be used later and the existing stdout is closed.
862 stdout is then initialised to the new File pointer where the operations are done onto that.
863 Later (look below for the code), the saved stdout is restored back.
865 if (pclp->m_redirOutName)
867 if ((stdout_fd = fileno(stdout)) != -1) // Handle of the existing stdout.
869 stdout_fd_dup = dup(stdout_fd);
870 if (stdout_fd_dup != -1)
872 // Close the existing stdout.
873 fflush(stdout); // Write any unwritten data to the file.
876 redirOut = fdopen (stdout_fd_dup, (char const *)"w");
878 stdout = freopen (pclp->m_redirOutName, (char const *)"w", redirOut);
882 // Undo the redirection.
883 stdout = fdopen(stdout_fd, (char const *)"w");
885 setbuf(stdout, NULL); // Unbuffered file pointer.
890 if (pclp->m_redirErrName)
892 if ((stderr_fd = fileno(stderr)) != -1)
894 stderr_fd_dup = dup(stderr_fd);
895 if (stderr_fd_dup != -1)
899 redirErr = fdopen (stderr_fd_dup, (char const *)"w");
901 stderr = freopen (pclp->m_redirErrName, (char const *)"w", redirErr);
905 // undo the redirect, if possible
906 stderr = fdopen(stderr_fd, (char const *)"w");
908 setbuf(stderr, NULL); // Unbuffered file pointer.
913 if (pclp->m_redirBothName)
915 if ((stdout_fd = fileno(stdout)) != -1)
917 stdout_fd_dup = dup(stdout_fd);
918 if (stdout_fd_dup != -1)
922 redirOut = fdopen (stdout_fd_dup, (char const *)"w");
924 stdout = freopen (pclp->m_redirBothName, (char const *)"w", redirOut);
928 // undo the redirect, if possible
929 stdout = fdopen(stdout_fd, (char const *)"w");
931 setbuf(stdout, NULL); // Unbuffered file pointer.
934 if ((stderr_fd = fileno(stderr)) != -1)
943 fnSetUpEnvBlock(&env); // Set up the ENV block
945 // Run the Perl script
946 exitstatus = RunPerl(pclp->m_argc, pclp->m_argv, env);
949 // clean up any redirection
951 if (pclp->m_redirInName && redirIn)
954 stdin = fdopen(stdin_fd, (char const *)"r"); // Put back the old handle for stdin.
957 if (pclp->m_redirOutName && redirOut)
959 // Close the new stdout.
963 // Put back the old handle for stdout.
964 stdout = fdopen(stdout_fd, (char const *)"w");
965 setbuf(stdout, NULL); // Unbuffered file pointer.
968 if (pclp->m_redirErrName && redirErr)
973 stderr = fdopen(stderr_fd, (char const *)"w"); // Put back the old handle for stderr.
974 setbuf(stderr, NULL); // Unbuffered file pointer.
977 if (pclp->m_redirBothName && redirOut)
984 stdout = fdopen(stdout_fd, (char const *)"w"); // Put back the old handle for stdout.
985 setbuf(stdout, NULL); // Unbuffered file pointer.
989 if (newscreen && newscreenhandle)
991 //added for --autodestroy switch
992 if(!pclp->m_AutoDestroy)
994 if ((redirOut == NULL) && (redirIn == NULL) && (!gKillAll))
996 printf((char *)"\n\nPress any key to exit\n");
1000 DestroyScreen(newscreenhandle);
1003 // Set the mode for stdin and stdout
1004 fnFpSetMode(stdin, O_TEXT, dummy);
1005 fnFpSetMode(stdout, O_TEXT, dummy);
1010 for(i=0; i<pclp->m_argv_len; i++)
1012 if(pclp->m_argv[i] != NULL)
1014 free(pclp->m_argv[i]);
1015 pclp->m_argv[i] = NULL;
1020 pclp->m_argv = NULL;
1025 free(pclp->nextarg);
1026 pclp->nextarg = NULL;
1028 if(pclp->sSkippedToken != NULL)
1030 free(pclp->sSkippedToken);
1031 pclp->sSkippedToken = NULL;
1034 if(pclp->m_redirInName)
1036 free(pclp->m_redirInName);
1037 pclp->m_redirInName = NULL;
1039 if(pclp->m_redirOutName)
1041 free(pclp->m_redirOutName);
1042 pclp->m_redirOutName = NULL;
1044 if(pclp->m_redirErrName)
1046 free(pclp->m_redirErrName);
1047 pclp->m_redirErrName = NULL;
1049 if(pclp->m_redirBothName)
1051 free(pclp->m_redirBothName);
1052 pclp->m_redirBothName = NULL;
1056 // Signal a semaphore, if indicated by -{ option, to indicate that
1057 // the script has terminated and files are closed
1059 if (pclp->m_qSemaphore != 0)
1062 kSemaphoreSignal(pclp->m_qSemaphore);
1064 SignalLocalSemaphore(pclp->m_qSemaphore);
1075 fnDestroyEnvBlock(env);
1076 fnUnregisterWithThreadTable();
1077 // Remove the thread context set during Perl_set_context
1078 Remove_Thread_Ctx();
1086 /*============================================================================================
1088 Function : fnSetUpEnvBlock
1090 Description : Sets up the initial environment block.
1092 Parameters : penv (IN) - ENV variable as char***.
1096 ==============================================================================================*/
1098 void fnSetUpEnvBlock(char*** penv)
1103 char var[kMaxVariableNameLen+1] = {'\0'};
1104 char val[kMaxValueLen+1] = {'\0'};
1105 char both[kMaxVariableNameLen + kMaxValueLen + 5] = {'\0'};
1106 size_t len = kMaxValueLen;
1109 while(scanenv( &sequence, var, &len, val ))
1114 // add one for null termination
1118 env = (char **) malloc (totalcnt * sizeof(char *));
1127 while( (cnt < (totalcnt-1)) && scanenv( &sequence, var, &len, val ) )
1130 strcpy( both, var );
1131 strcat( both, (char *)"=" );
1132 strcat( both, val );
1134 env[cnt] = (char *) malloc((sizeof(both)+1) * sizeof(char));
1137 strcpy(env[cnt], both);
1142 for(i=0; i<cnt; i++)
1160 for(i=cnt; i<=(totalcnt-1); i++)
1173 /*============================================================================================
1175 Function : fnDestroyEnvBlock
1177 Description : Frees resources used by the ENV block.
1179 Parameters : env (IN) - ENV variable as char**.
1183 ==============================================================================================*/
1185 void fnDestroyEnvBlock(char** env)
1187 // It is assumed that this block is entered only if env is TRUE. So, the calling function
1188 // must check for this condition before calling fnDestroyEnvBlock.
1189 // If no check is made by the calling function, then the server abends.
1191 while (env[k] != NULL)
1206 /*============================================================================================
1208 Function : fnFpSetMode
1210 Description : Sets the mode for a file.
1212 Parameters : fp (IN) - FILE pointer for the input file.
1213 mode (IN) - Mode to be set
1216 Returns : Integer which is the set value.
1218 ==============================================================================================*/
1220 int fnFpSetMode(FILE* fp, int mode, int *err)
1224 PFFSETMODE pf_fsetmode;
1227 if (mode == O_BINARY || mode == O_TEXT)
1232 // the setmode call is not implemented (correctly) on NetWare,
1233 // but the CLIB guys were kind enough to provide another
1234 // call, fsetmode, which does a similar thing. It only works
1236 pf_fsetmode = (PFFSETMODE) ImportSymbol(GetNLMHandle(), (char *)"fsetmode");
1238 ret = (*pf_fsetmode) (fp, ((mode == O_BINARY) ? "b" : "t"));
1241 // we are on 4.11 instead of Moab, so we just return an error
1267 /*============================================================================================
1269 Function : fnInternalPerlLaunchHandler
1271 Description : Gets called by perl to spawn a new instance of perl.
1273 Parameters : cndLine (IN) - Command Line string.
1277 ==============================================================================================*/
1279 void fnInternalPerlLaunchHandler(char* cmdLine)
1281 int currentThreadGroup = -1;
1283 ScriptData* psdata=NULL;
1286 // Create a safe copy of the command line and pass it to the
1287 // new thread for parsing. The new thread will be responsible
1288 // to delete it when it is finished with it.
1289 psdata = (ScriptData *) malloc(sizeof(ScriptData));
1292 psdata->m_commandLine = NULL;
1293 psdata->m_commandLine = (char *) malloc(MAX_DN_BYTES * sizeof(char));
1295 if(psdata->m_commandLine)
1297 strcpy(psdata->m_commandLine, cmdLine);
1298 psdata->m_fromConsole = FALSE;
1301 BeginThread(fnLaunchPerl, NULL, PERL_COMMAND_STACK_SIZE, (void*)psdata);
1303 // Start a new thread in its own thread group
1304 BeginThread(fnLaunchPerl, NULL, PERL_COMMAND_STACK_SIZE, (void*)psdata);
1322 /*============================================================================================
1324 Function : fnGetPerlScreenName
1326 Description : This function creates the Perl screen name.
1327 Gets called from main only once when the Perl NLM loads.
1329 Parameters : sPerlScreenName (OUT) - Resultant Perl screen name.
1333 ==============================================================================================*/
1335 void fnGetPerlScreenName(char *sPerlScreenName)
1338 // The logic for using 32 in the below array sizes is like this:
1339 // The NetWare CLIB SDK documentation says that for base 2 conversion,
1340 // this number must be minimum 8. Also, in the example of the documentation,
1341 // 20 is used as the size and testing is done for bases from 2 upto 16.
1342 // So, to simply chose a number above 20 and also keeping in mind not to reserve
1343 // unnecessary big array sizes, I have chosen 32 !
1344 // Less than that may also suffice.
1345 char sPerlRevision[32 * sizeof(char)] = {'\0'};
1346 char sPerlVersion[32 * sizeof(char)] = {'\0'};
1347 char sPerlSubVersion[32 * sizeof(char)] = {'\0'};
1349 // The defines for PERL_REVISION, PERL_VERSION, PERL_SUBVERSION are available in
1350 // patchlevel.h under root and gets included when perl.h is included.
1351 // The number 10 below indicates base 10.
1352 itoa(PERL_REVISION, sPerlRevision, 10);
1353 itoa(PERL_VERSION, sPerlVersion, 10);
1354 itoa(PERL_SUBVERSION, sPerlSubVersion, 10);
1356 // Concatenate substrings to get a string like Perl5.6.1 which is used as the screen name.
1357 sprintf(sPerlScreenName, "%s%s.%s.%s", PERL_COMMAND_NAME,
1358 sPerlRevision, sPerlVersion, sPerlSubVersion);
1365 // Global variable to hold the environ information.
1366 // First time it is accessed, it will be created and initialized and
1367 // next time onwards, the pointer will be returned.
1369 // Improvements - Dynamically read env everytime a request comes - Is this required?
1370 char** genviron = NULL;
1373 /*============================================================================================
1375 Function : nw_getenviron
1377 Description : Gets the environment information.
1383 ==============================================================================================*/
1389 return (&genviron); // This might leak memory upto 11736 bytes on some versions of NetWare.
1390 // return genviron; // Abending on some versions of NetWare.
1392 fnSetUpEnvBlock(&genviron);
1399 /*============================================================================================
1401 Function : nw_freeenviron
1403 Description : Frees the environment information.
1409 ==============================================================================================*/
1416 fnDestroyEnvBlock(genviron);