'Exit code' (sometimes called 'exit status') is a numeric code left by the program once it exits. The posix standard whether in windows or unices-like environments like linux and bsd expect an 'exit code' of zero to mean that the program has finished without any anomalies and with that the operating system and/or subsequent programs will be able to proceed accordingly. However, a non-zero value will indicate a warning or a fatal error. Windows programmers generally use 'exit code' between 1…255 to indicate both fatal errors and warnings. More experienced programmers, whenever possible, prefer to use the common terminal 'exit code' such as cmd.exe on Windows or bash on Linux, they already use some codes, for example:
- Invalid function number
- File not found
- Path not found
- Too many open files
- Access denied
- Invalid handle.
- Memory control blocks destroyed
- Insufficient memory
- Invalid memory block address
- Invalid environment
- invalid format
- Invalid access code
- (…)
My custom, when a file that is necessary for my application to proceed is not found then I close the program with 'exit code' equal to '2' which for MS-DOS/CMD on Windows is equivalent to 'File not found'. Experienced Windows programmers are used to this code. For everything else that there is no set pattern, we create arbitrary numeric code and if this someone is a good programmer they have documented that somewhere.
Stdout and Stderr are output devices. stdout it's basically the computer screen/terminal interface, when a text is sent there, actually the text is going to the computer screen/terminal. Stderr it's basically the same thing except for the following, every text sent to stderr is identified as a system error and there is usually a service that monitors for such by putting them in log files to be viewed later or trigger some event.
In my experience as a consultant and analyzing a lot of third-party programs I come to the conclusion that any 'exit code' or use of stdout/stderr in desktop programs is rare, but used more often in backend programs. On desktops, for some reason, programmers prefer to use their own logging mechanisms and it will be with them that they will diagnose if there is a problem.
Task schedulers or backup scripts (among other scripting features) take most advantage of stdout/stderr and 'exit code'. For example, Linux or Windows have excellent task schedulers that take advantage of the 'exit code' to understand whether a task has succeeded or failed. When the 'glitch' is noticed then the messages displayed during runtime (stdout/stderr) can be packaged and then emailed to someone responsible. This is how a script, service, or integration with other programs should work.
Using FreePascal one way to send a message to stdout/stderr is using the command WriteLn(device , message) where the device can be stderr or stdout. See this example where in the OnShow of the form we test the existence of a configuration file and if it doesn't exist then I send a message to stderr and the program continues:
if not FileExists('configure.ini') then begin
writeln(stderr,'File "configure.ini" not found.');
end;
In the example below it is basically the same thing, but the program will not proceed, it will be terminated with 'exit code' equal to 2:
if not FileExists('configure.ini') then begin writeln(stderr,'File "configure.ini" not found.'); Sleep(5000); // 5s wait
Halt(2); // <-- Exit Code 2
end;
This kind of thoughtfulness within a program is very welcome and helps to integrate your program with others. But how to notice them when running a program with graphical interface (GUI), since stdout/stderr are only seen in terminals?
You can run your program directly from the terminal or disable this option here in Project|Options|Compiler Options|Config and Target and disable the option Win32 gui application (-WG) :
The option Win32 gui application (-WG) unchecked allows displaying a terminal while the GUI is running, then any message sent to stdout/stderr will be displayed:
But there's a problem, when the program ends, the terminal behind it will be closed too and so you won't see the 'exit code' . To see the 'exit code' when the program is finished go to Tools|Options|Debugger|General and turn on the option Show message on stop with Error (exit Code<>0):
With the above option turned on, here's what happens when we end the program with a non-zero 'exit code':
To take advantage of the 'exit code' we need to know how our operating system gives access to it, only then will we know how to write scripts or create task schedules that take advantage of this information. Here's how we get the 'exit code' in Windows/Terminal:
In the example above, we saw that our program ended with 'exit code' equal to 2 as expected. We use the environment variable %ERRORLEVEL% from cmd.exe to see it. On Linux this environment variable would be $?. To take advantage of the 'exit code' within scripts, we would do it like this on Windows:
myapplication.exe if %ERRORLEVEL% neq 0 ( (...) )
On Linux, we would do it like this:
myapplication.exe if [ $? -ne 0 ] ; then (...) fi
Now we can create bat/vbs/python/bash scripts,… where we run our program and if it returns something other than zero we can abort the script or send an email notification, for example.
Now that our program is able to send messages to stdout/stderr we can schedule it to run with redirectors. On Linux there are even defaults in the log service where messages sent to stderr are handled indiscriminately usually taking them to log files, but on Windows it's complicated, it has an event viewer, but it's not a service plugged into stderr and it needs use its API to send something to be recorded in one of its logs which by default has the .evt extension. So on Windows for our application to be cross-platform we have to use redirectors to indicate where our messages to stderr should be saved:
with the redirector 2>logs.txt all messages that our program sends to stderr will be recorded in a log file called logs.txt. This way we guarantee that the log will be handled by the operating system using safe and hardly fallible methods. Of course, we can use third-party libraries for the same purpose that maybe display our message on a beautiful and more resourceful screen, but if it doesn't use stdout/stderr we are losing our program's ability to interoperate with others, including scripts, services and task schedulers.
In conclusion, when developing your programs - be they utility or commercial - make use of stdout/stderr and when your program is forced to terminate because of a crash, use 'exit code' so you will ensure that your program is able to interoperate with others. , including scripts, services, and task schedulers.