/* REXX */ /* * Creates installation packages of the Qt library * Copyright (C) 2009 netlabs.org. OS/2 parts. * * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ signal on syntax signal on halt signal on novalue trace off numeric digits 12 '@echo off' /*------------------------------------------------------------------------------ globals ------------------------------------------------------------------------------*/ G.TAB = '09'x G.EOL = '0D0A'x G.ScriptPath = '' G.ScriptDir = '' G.ScriptFile = '' G.StartDir = '' G.ScreenWidth = -1 G.ScreenHeight = -1 /* */ G.QtBuildDir = '' G.QtBuildRev = '' G.QtBuildName = '' G.OutDir = '' G.Continue = 0 G.SkipConfigure = 0 G.SkipBuild = 0 G.SkipBuildDocs = 0 G.SkipInstall = 0 G.SkipWPI = 0 G.RevOverride = 0 G.QtBuildDate = '' G.QtInstDir = '' G.LogFile = '' G.QtVerMajor = '' G.QtVerMinor = '' G.QtVerPatch = '' G.QtVerBuild = '' G.QtVerFull = '' G.QtVerFullBuild = '' G.QtInstallPrefix = 'qt' /* all globals to be exposed in procedures */ Globals = 'G. Opt. Static.' /*------------------------------------------------------------------------------ startup + main + termination ------------------------------------------------------------------------------*/ /* init system REXX library */ if (RxFuncQuery('SysLoadFuncs')) then do call RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs' call SysLoadFuncs end /* detect script file and directory */ parse source . . G.ScriptPath G.ScriptDir = FixDir(filespec('D', G.ScriptPath) || filespec('P', G.ScriptPath)) G.ScriptFile = FixDir(filespec('N', G.ScriptPath)) G.StartDir = directory() /* check text screen resolution */ parse value SysTextScreenSize() with G.ScreenHeight G.ScreenWidth if (G.ScreenHeight < 25 | G.ScreenWidth < 80) then do address 'cmd' 'mode co80,25' parse value SysTextScreenSize() with G.ScreenHeight G.ScreenWidth if (G.ScreenHeight < 25 | G.ScreenWidth < 80) then do call SayErr 'WARNING: Cannot set screen size to 80 x 25!' call SayErr 'Some messages can be unreadable.' say call WaitForAnyKey end end parse arg args call ParseCommandLine args call Main call Done 0 /*------------------------------------------------------------------------------ functions ------------------------------------------------------------------------------*/ /** * Just do the job. */ Main: procedure expose (Globals) say /* Log to the current dir */ parse var G.ScriptFile G.LogFile'.'. G.LogFile = G.ScriptDir'\'G.LogFile'.log' if (G.Continue & FileExists(G.LogFile)) then do call lineout G.LogFile, "" call lineout G.LogFile, copies('>', 78) call lineout G.LogFile, "Continued execution of the previous packaging process!" call lineout G.LogFile, copies('>', 78) call lineout G.LogFile, "" end else call DeleteFile G.LogFile call SaySay G.ScriptFile": START" /* validate the options */ str = GetAbsDirPath(G.QtBuildDir) if (str == '') then do call SayErr 'Qt build directory "'G.QtBuildDir'" does not exist.' call Done 1 end G.QtBuildDir = str if (\G.Continue) then do if (DirExists(G.OutDir)) then do call SayErr 'Output directory "'G.OutDir'" already exists.'G.EOL||, 'Specify a different one.' call Done 1 end end if (\datatype(G.QtBuildRev, 'W')) then do call SayErr 'Revision 'G.QtBuildRev' is not an integer.' call Done 1 end if (G.QtBuildDate == '') then do G.QtBuildDate = date('S') G.QtBuildDate = insert('-', G.QtBuildDate, 4) G.QtBuildDate = insert('-', G.QtBuildDate, 7) end call SaySay call SaySay 'Qt Build Directory : "'G.QtBuildDir'"' call SaySay 'Qt Build Revision : 'G.QtBuildRev call SaySay 'Qt Build Name : 'G.QtBuildName call SaySay 'Qt Build Date : 'G.QtBuildDate call SaySay 'Output Directory : "'G.OutDir'"' call SaySay if (G.Continue) then do say 'WARNING: This is a continued execution of the previous attempt!' say end say 'If the above is correct, type "YES" to start packaging.' str = linein() if (str \== 'YES') then do call SayErr 'Wrong answer.' call Done 1 end /* prepare */ call SaySay 'Creating "'G.OutDir'" directory...' call MakeDir G.OutDir G.OutDir = GetAbsDirPath(G.OutDir) if (G.OutDir == '') then signal Nonsense /* configure the Qt build */ call SaySay 'Configuring Qt build...' if (\G.SkipConfigure) then do if (Exec('configure.cmd --official-build-quiet r'G.QtBuildRev,, G.QtBuildDir, '>'G.LogFile) \= 0) then call Done 1 end else call SayWrn '...skipped' /* get the Qt version */ qconfig_pri = G.QtBuildDir'\mkspecs\qconfig.pri' call SaySay 'Getting Qt version from "'qconfig_pri'"...' do while lines(qconfig_pri) str = linein(qconfig_pri) parse var str w1 w2 w3 if (w2 == '=') then do select when (w1 == 'QT_MAJOR_VERSION') then G.QtVerMajor = w3 when (w1 == 'QT_MINOR_VERSION') then G.QtVerMinor = w3 when (w1 == 'QT_PATCH_VERSION') then G.QtVerPatch = w3 when (w1 == 'QT_BUILD_VERSION') then G.QtVerBuild = w3 otherwise nop end end end call lineout qconfig_pri if (G.RevOverride) then G.QtVerBuild = 'r'G.QtBuildRev if (G.QtVerMajor == '' | G.QtVerMinor == '') then do call SayErr 'Could not determine the Qt version number.' call Done 1 end G.QtVerFull = G.QtVerMajor'.'G.QtVerMinor if (G.QtVerPatch \== '') then G.QtVerFull = G.QtVerFull'.'G.QtVerPatch if (G.QtVerBuild \== '') then G.QtVerFull = G.QtVerFull'.'G.QtVerBuild G.QtVerFullBuild = G.QtVerMajor'.'G.QtVerMinor if (G.QtVerPatch \== '') then G.QtVerFullBuild = G.QtVerFullBuild'.'G.QtVerPatch if (G.QtBuildName \== '') then G.QtVerFullBuild = G.QtVerFullBuild'-'G.QtBuildName call SaySay 'Qt full version number is 'G.QtVerFull if (G.QtVerBuild \== 'r'G.QtBuildRev) then do call SayErr 'Build code 'G.QtVerBuild' does not match build revision 'G.QtBuildRev call Done 1 end /* build Qt */ call SaySay 'Building Qt in "'G.QtBuildDir'"...' if (\G.SkipBuild) then do if (Exec('make', G.QtBuildDir, '>'G.LogFile) \= 0) then call Done 1 end else call SayWrn '...skipped' /* build Qt docs */ call SaySay 'Building Qt documentation in "'G.QtBuildDir'"...' if (\G.SkipBuildDocs) then do if (Exec('make docs', G.QtBuildDir, '>'G.LogFile) \= 0) then call Done 1 end else call SayWrn '...skipped' /* fake-install Qt to gather everything for distribution */ G.QtInstDir = G.OutDir'\temp-install' call SaySay 'Fake-installing Qt to "'G.QtInstDir'"...' if (\G.SkipInstall) then do call SetEnv 'INSTALL_ROOT', G.QtInstDir if (Exec('make install', G.QtBuildDir, '>'G.LogFile) \= 0) then call Done 1 end else call SayWrn '...skipped' /* make install recreates the full directory tree in INSTALL_ROOT, * get the real install root that points directly to the installed Qt tree */ G.QtInstDir = G.QtInstDir||filespec('P', G.QtBuildDir)||filespec('N', G.QtBuildDir) call SaySay 'Adjusted install directory to "'G.QtInstDir'"' /* Set up common environment */ call SetEnv 'OUT_ROOT', G.OutDir call SetEnv 'QT_BUILD', G.QtBuildDir call SetEnv 'QT_INSTALL', G.QtInstDir call SetEnv 'QT_VER_FULL',, translate(G.QtVerFullBuild,, xrange('61'x, '7a'x)'_', xrange('41'x, '5a'x)'.') G.OutDirWpi = G.OutDir'\wpi' G.OutDirZip = G.OutDir'\zip' call SetEnv 'WPI_ROOT', G.OutDirWpi call SetEnv 'ZIP_ROOT', G.OutDirZip /* Create WPI archives */ call SaySay 'Creating WPI archives in "'G.OutDirWpi'"...' if (\G.SkipWPI) then do call CreateAllWPI end else call SayWrn '...skipped' call SaySay G.ScriptFile": END" return /** * Creates all WPI archives */ CreateAllWPI: procedure expose (Globals) call MakeDir G.OutDirWpi /* set up the WARPIN environment */ call Exec "warpin_env.cmd", G.ScriptDir, '>'G.LogFile call SetEnv 'WIC', 'wic.exe' /* create the .WIS scripts */ G.vars.1 = 'version'; G.vars.1.v = G.QtVerMajor'.'G.QtVerMinor'.'G.QtVerPatch if (G.QtBuildName \== '') then G.vars.1.v = G.vars.1.v' 'G.QtBuildName G.vars.2 = 'version_path'; G.vars.2.v = G.QtVerMajor'\'G.QtVerMinor'\'G.QtVerPatch'\'G.QtBuildRev G.vars.3 = 'date'; G.vars.3.v = G.QtBuildDate G.vars.4 = 'install_prefix'; G.vars.4.v = G.QtInstallPrefix G.vars.5 = 'disable_tag_begin'; G.vars.5.v = '' G.vars.6 = 'disable_tag_end'; G.vars.6.v = '' G.vars.7 = 'enable_tag_begin'; G.vars.7.v = '!--' G.vars.8 = 'enable_tag_end'; G.vars.8.v = '--' G.vars.0 = 8 call ReplaceInFile 'lib.wis.tpl', G.OutDirWpi'\lib.wis', 'G.vars' /* disable the xsystray package and create another WPI, see #146 */ G.vars.5.v = '!--' G.vars.6.v = '--' G.vars.7.v = '' G.vars.8.v = '' call ReplaceInFile 'lib.wis.tpl', G.OutDirWpi'\lib_noxwpdep.wis', 'G.vars' /* other archives don't need "disable_tag_*" and friends */ G.vars.0 = 4 call ReplaceInFile 'dev.wis.tpl', G.OutDirWpi'\dev.wis', 'G.vars' call ReplaceInFile 'examples.wis.tpl', G.OutDirWpi'\examples.wis', 'G.vars' call ReplaceInFile 'doc.wis.tpl', G.OutDirWpi'\doc.wis', 'G.vars' drop G.vars. /* create the .WPI packages */ if (Exec('make -f Makefile.packages wpi.lib', G.ScriptDir, '>'G.LogFile) \= 0) then call Done 1 if (Exec('make -f Makefile.packages wpi.lib_noxwpdep', G.ScriptDir, '>'G.LogFile) \= 0) then call Done 1 if (Exec('make -f Makefile.packages wpi.dev', G.ScriptDir, '>'G.LogFile) \= 0) then call Done 1 if (Exec('make -f Makefile.packages wpi.examples', G.ScriptDir, '>'G.LogFile) \= 0) then call Done 1 if (Exec('make -f Makefile.packages wpi.doc', G.ScriptDir, '>'G.LogFile) \= 0) then call Done 1 /* */ /* */ return /** * Replaces all occurences of the given set of variables with their values * in a given text file. * * @param aFileIn Name of the text file to perform replacement in. * @param aFileOut Name of the text file to save the result to. * @param aVars Global stem (starting with G.) with variables and values. */ ReplaceInFile: procedure expose (Globals) parse arg aFileIn, aFileOut, aVars if (aFileIn == aFileOut | aFileIn == '' | aFileOut == '') then call Nonsense contents = charin(aFileIn,,chars(aFileIn)) call charout aFileIn do i = 1 to value(aVars'.0') contents =, Replace(contents, '${'value(aVars'.'i)'}', value(aVars'.'i'.v')) end call DeleteFile aFileOut call charout aFileOut, contents call charout aFileOut return /** * Parses the command line and sets up the corresponding global variables in * the G. stem. * * @param aArgs Command line to parse. */ ParseCommandLine: procedure expose (Globals) parse arg aArgs call TokenizeString aArgs, 'G.opts' ord = 0 do i = 1 to G.opts.0 if (left(G.opts.i, 1) == '-') then do o = substr(G.opts.i, 2) select when (wordpos(o, 'h H ? help') > 0) then call Usage when (o == 'rawhelp') then call Usage 1 when (o == 'c') then G.Continue = 1 when (o == 'C') then G.SkipConfigure = 1 when (o == 'B') then G.SkipBuild = 1 when (o == 'D') then G.SkipBuildDocs = 1 when (o == 'I') then G.SkipInstall = 1 when (o == 'W') then G.SkipWPI = 1 when (o == '-rev-override') then G.RevOverride = 1 when (o == '-date-override') then do i = i + 1 if (i > G.opts.0) then a = ''; else a = G.opts.i if (a == '') then call Error "E_MissingOptionArg", o G.QtBuildDate = a end otherwise call Error "E_InvalidOption", o end end else do ord = ord + 1 a = G.opts.i select when (ord == 1) then G.QtBuildDir = a when (ord == 2) then G.QtBuildRev = a when (ord == 3) then G.QtBuildName = a when (ord == 4) then G.OutDir = a otherwise call Error "E_InvalidArgument", a end end end /* drop the contents of our global stem */ do i = 1 to G.opts.0 drop G.opts.i end drop G.opts.0 if (G.QtBuildDir == '' | G.QtBuildRev == '' | G.OutDir == '') then call Usage return /** * Prints the usage information. */ Usage: procedure expose (Globals) parse arg just_say just_say = (just_say == 1) if (\just_say) then do address 'cmd' 'call' G.ScriptFile '-rawhelp | more' call Done 0 end say 'Script to create installation packages of the Qt library.' say say 'Usage: ' say say ' 'G.ScriptFile' [options]' say say ' : Directory containing a complete Qt4 source tree' say ' to make packages for.' say ' : SVN revision number of the tree (e.g. 123).' say ' : Symbolic build name (e.g. "CSD1" or "GA").' say ' : Directory where all generated packages will be placed to.' say say 'Options (not normally necessary):' say say ' -c : Continue a failed packaging process' say ' -C : Skip the configure stage' say ' -B : Skip the build stage' say ' -D : Skip the build documentation stage' say ' -I : Skip the fake-install stage' say ' -W : Skip creation of the WPI archives' call Done 0 /*------------------------------------------------------------------------------ utility functions ------------------------------------------------------------------------------*/ /** * Executes the command using the OS/2 shell. * * @param aCommand Command name and arguments. * @param aWorkDir Command working directory. * @param aStdOut File to redirect standard output stream of the command to. * @param aErrOut File to redirect standard error stream of the command to. * @return Command exit code. * * @note Start aStdOut/aErrOut with '>' if you want to have them appended rather * than overwritten. */ Exec: procedure expose (Globals) parse arg aCommand, aWorkDir, aStdOut, aStdErr if (aWorkDir == '') then aWorkDir = '.' call SaySay 'Executing "'aCommand'" in "'aWorkDir'"...' if (translate(right(word(aCommand, 1), 4)) == '.CMD') then do aCommand = 'call 'aCommand end stdOut = strip(aStdOut, 'L', '>') stdErr = strip(aStdErr, 'L', '>') redir = '' if (aStdOut \== '') then do if length(stdOut) < length(aStdOut) then redir = ' 1>>"'stdOut'"' else redir = ' 1>"'stdOut'"' if (aStdErr == '') then redir = redir' 2>&1' end if (aStdErr \== '') then do if length(stdErr) < length(aStdErr) then redir = redir' 2>>"'stdErr'"' else redir = redir' 2>"'stdErr'"' end if (stdOut == G.LogFile | stdErr == G.LogFile) then call lineout G.LogFile, copies('-', 78) call lineout stdOut /* make sure it's closed */ call lineout stdErr /* make sure it's closed */ curDir = directory() call directory aWorkDir address 'cmd' aCommand||redir call directory curDir if (stdOut == G.LogFile | stdErr == G.LogFile) then call lineout G.LogFile, copies('-', 78) call SaySay 'Exit code 'rc return rc /** * Gets the OS/2 environment variable. * * @param aName Variable name. * @return Variable value. */ GetEnv: procedure expose (Globals) parse arg aName extLibPath = (translate(aName) == 'BEGINLIBPATH' | translate(aName) == 'ENDLIBPATH') if (extLibPath) then val = SysQueryExtLibPath(left(aName, 1)) else val = value(aName,, 'OS2ENVIRONMENT') return val /** * Sets the OS/2 environment variable. * * @param aName Variable name. * @param aValue Variable Value. */ SetEnv: procedure expose (Globals) parse arg aName, aValue extLibPath = (translate(aName) == 'BEGINLIBPATH' | translate(aName) == 'ENDLIBPATH') if (extLibPath) then call SysSetExtLibPath aValue, left(aName, 1) else call value aName, aValue, 'OS2ENVIRONMENT' return /** * Unsets the OS/2 environment variable. * * @param aName Variable name. * @param aValue Variable Value. */ UnsetEnv: procedure expose (Globals) parse arg aName extLibPath = (translate(aName) == 'BEGINLIBPATH' | translate(aName) == 'ENDLIBPATH') if (extLibPath) then call SysSetExtLibPath "", left(aName, 1) else call value aName, "", 'OS2ENVIRONMENT' return DeleteFile: procedure expose (Globals) parse arg file rc = SysFileDelete(file) if (rc \= 0 & rc \= 2) then do call SayErr 'FATAL: Could not delete file '''file'''!' call SayErr 'SysFileDelete returned 'rc call Done 1 end return MakeDir: procedure expose (Globals) parse arg aDir aDir = translate(aDir, '\', '/') curdir = directory() base = aDir todo.0 = 0 do while 1 d = directory(base) if (d \== '') then leave i = todo.0 + 1 todo.i = filespec('N', base) todo.0 = i drv = filespec('D', base) path = filespec('P', base) if (path == '\' | path == '') then do base = drv||path leave end base = drv||strip(path, 'T', '\') end call directory curdir do i = todo.0 to 1 by -1 if (i < todo.0 | (base \== '' & right(base,1) \== '\' &, right(base,1) \== ':')) then base = base'\' base = base||todo.i rc = SysMkDir(base) if (rc \= 0) then do call SayErr 'FATAL: Could not create directory '''base'''!' call SayErr 'SysMkDir returned 'rc call Done 1 end end return /** * Replaces all occurences of a given substring in a string with another * substring. * * @param str the string where to replace * @param s1 the substring which to replace * @param s2 the substring to replace with * @return the processed string * * @version 1.1 */ Replace: procedure expose (Globals) parse arg str, s1, s2 l1 = length(s1) l2 = length(s2) i = 1 do while (i > 0) i = pos(s1, str, i) if (i > 0) then do str = delstr(str, i, l1) str = insert(s2, str, i-1) i = i + l2 end end return str /** * Returns a list of all words from the string as a stem. * Delimiters are spaces, tabs and new line characters. * Words containg spaces must be enclosed with double * quotes. Double quote symbols that need to be a part * of the word, must be doubled. * * @param string the string to tokenize * @param stem * the name of the stem. The stem must be global * (i.e. its name must start with 'G.'), for example, * 'G.wordlist'. * @param leave_ws * 1 means whitespace chars are considered as a part of words they follow. * Leading whitespace (if any) is always a part of the first word (if any). * * @version 1.1 */ TokenizeString: procedure expose (Globals) parse arg string, stem, leave_ws leave_ws = (leave_ws == 1) delims = '20090D0A'x quote = '22'x /* " */ num = 0 token = '' len = length(string) last_state = '' /* D - in delim, Q - in quotes, W - in word */ seen_QW = 0 do i = 1 to len c = substr(string, i, 1) /* determine a new state */ if (c == quote) then do if (last_state == 'Q') then do /* detect two double quotes in a row */ if (substr(string, i + 1, 1) == quote) then i = i + 1 else state = 'W' end else state = 'Q' end else if (verify(c, delims) == 0 & last_state \== 'Q') then do state = 'D' end else do if (last_state == 'Q') then state = 'Q' else state = 'W' end /* process state transitions */ if ((last_state == 'Q' | state == 'Q') & state \== last_state) then c = '' else if (state == 'D' & \leave_ws) then c = '' if (last_state == 'D' & state \== 'D' & seen_QW) then do /* flush the token */ num = num + 1 call value stem'.'num, token token = '' end token = token||c last_state = state seen_QW = (seen_QW | state \== 'D') end /* flush the last token if any */ if (token \== '' | seen_QW) then do num = num + 1 call value stem'.'num, token end call value stem'.0', num return /** * Fixes the directory path by a) converting all slashes to back * slashes and b) ensuring that the trailing slash is present if * the directory is the root directory, and absent otherwise. * * @param dir the directory path * @param noslash * optional argument. If 1, the path returned will not have a * trailing slash anyway. Useful for concatenating it with a * file name. */ FixDir: procedure expose (Globals) parse arg dir, noslash noslash = (noslash = 1) dir = translate(dir, '\', '/') if (right(dir, 1) == '\' &, (noslash | \(length(dir) == 3 & (substr(dir, 2, 1) == ':')))) then dir = substr(dir, 1, length(dir) - 1) return dir /** * Shortcut to FixDir(dir, 1) */ FixDirNoSlash: procedure expose (Globals) parse arg dir return FixDir(dir, 1) /** * Returns 1 if the specified dir exists and 0 otherwise. */ DirExists: procedure expose (Globals) parse arg dir return (GetAbsDirPath(dir) \== '') /** * Returns the absolute path to the given directory * or an empty string if no directory exists. */ GetAbsDirPath: procedure expose (Globals) parse arg dir if (dir \== '') then do curdir = directory() dir = directory(FixDir(dir)) call directory curdir end return dir /** * Returns 1 if the specified file exists and 0 otherwise. */ FileExists: procedure expose (Globals) parse arg file return (GetAbsFilePath(file) \= '') /** * Returns the absolute path to the given file (including the filename) * or an empty string if no file exists. */ GetAbsFilePath: procedure expose (Globals) parse arg file if (file \= '') then do file = stream(FixDir(file), 'C', 'QUERY EXISTS') end return file /** * Prefixes all lines of text with the given prefix. * * @param aLines Text to prefix. * @param aPrefix Prefix. * * @return Prefixed text. */ PrefixLines: procedure expose (Globals) parse arg aLines, aPrefix return aPrefix||Replace(aLines, G.EOL, G.EOL||aPrefix) SaySayEx: procedure expose (Globals) parse arg str, prefix, noeol noeol = (noeol == 1) if (noeol) then call charout, str else say str if (G.LogFile \== '') then do str = time('L') str if (noeol) then call charout G.LogFile, str else call lineout G.LogFile, str end return SaySay: procedure expose (Globals) parse arg str, noeol noeol = (noeol == 1) if (noeol) then call charout, str else say str if (G.LogFile \== '') then do str = PrefixLines(str, time('L')' ') if (noeol) then call charout G.LogFile, str else call lineout G.LogFile, str end return SayWrn: procedure expose (Globals) parse arg str, noeol str = 'WARNING: 'str call SaySay str, noeol return SayErr: procedure expose (Globals) parse arg str, noeol str = 'ERROR: 'str call SaySay str, noeol return /** * Prints the error or warning message corresponding to the first * argument (error code). If it starts with 'E_' an error message is * assumed, if it starts with 'W_' -- it's a warning message. * * The special error code 'E_OK' prints 'all done' and exits the * script. * * @param code error or warning code (as a string) * @param ... * arbitrary amount of arguments with additional error information. * These arguments are used to substitute %1, %2 (upto %9) markers * in the error message text. */ Error: procedure expose (Globals) e.E_CantOpenFile = 'Cannot open file ''%1'' (RC = %2).' e.E_CantDeleteFile = 'Cannot delete file ''%1'' (RC = %2).' e.E_InvalidOption = 'Invalid option: ''-%1''.' e.E_InvalidOptionArg = 'Invalid argument for option ''-%1'': ''%2''.' e.E_MissingOptionArg = 'Missing argument for option ''-%1''.' e.E_FileNotFound = 'File not found: ''%1''.' parse upper arg code str = value('e.'code) do i = 2 to arg() str = Replace(str, '%'||(i-1), arg(i)) end if (left(code,2) == 'E_') then str = 'ERROR: 'str else if (left(code,2) == 'W_') then str = 'WARNING: 'str else str = 'Something is really wrong...' if (word(SysCurPos(), 2) > 0) then say say str if (left(code,2) == 'E_') then call Done 1 return code /** * NoValue signal handler. */ NoValue: errl = sigl say say say 'EXPRESSION HAS NO VALUE at line #'errl'!' say say 'This is usually a result of a misnamed variable.' say 'Please contact the author.' call Done 252 /** * Nonsense handler. */ Nonsense: errl = sigl say say say 'NONSENSE at line #'errl'!' say say 'The author decided that this point of code should' say 'have never been reached, but it accidentally had.' say 'Please contact the author.' call Done 253 /** * Syntax signal handler. */ Syntax: errn = rc errl = sigl say say say 'UNEXPECTED PROGRAM TERMINATION!' say say 'REX'right(errn , 4, '0')': 'ErrorText(rc)' at line #'errl say say 'Possible reasons:' say say ' 1. Some of REXX libraries are not found but required.' say ' 2. You have changed this script and made a syntax error.' say ' 3. Author made a mistake.' say ' 4. Something else...' call Done 254 /** * Halt signal handler. */ Halt: say say 'CTRL-BREAK pressed, exiting.' call Done 255 /** * Always called at the end. Should not be called directly. * @param the exit code */ Done: procedure expose (Globals) parse arg code /* protect against recursive calls */ if (value('G.Done_done') == 1) then exit code call value 'G.Done_done', 1 /* cleanup stuff goes there */ if (symbol('G.AtExit.0') == 'VAR') then do /* run all AtExit slots */ do i = 1 to G.AtExit.0 if (symbol('G.AtExit.'i) == 'VAR') then call RunAtExitSlot i end end drop G.AtExit. /* finally, exit */ if (code \= 0) then do call SaySay G.ScriptFile': FAILED with exit code 'code if (G.LogFile \= '') then do say say 'You may find the execution details in the following log file:' say '"'G.LogFile'".' end end exit code