Chapter 37 Exercises: Interfacing with the Operating System
Part A: Conceptual Understanding
A.1. What is an environment variable? Give three examples of commonly used environment variables and explain what each one provides.
Guidance
An environment variable is a key-value pair set by the operating system or user that configures the runtime environment for processes. Examples: (1) PATH — list of directories where the OS searches for executable files. (2) HOME (Unix) or USERPROFILE (Windows) — path to the user's home directory. (3) TEMP or TMP — path to the temporary files directory. Other valid examples: LANG (locale), EDITOR (default text editor), SHELL (user's shell).A.2. Explain the difference between static linking and dynamic loading when calling C libraries from Pascal. When would you choose each approach?
Guidance
Static linking (using `external 'libname'`) resolves the library at compile/link time. The program will not start if the library is missing. Dynamic loading (using LoadLibrary/GetProcAddress) loads the library at runtime. The program starts even if the library is missing, and you can handle the absence gracefully. Choose static when the library is always required (e.g., system libraries). Choose dynamic when the library is optional (e.g., a plugin, an optional database driver) or when you need to support systems where the library may not be installed.A.3. Why do different operating systems store application data in different directories? What is the XDG Base Directory Specification on Linux?
Guidance
Each OS has conventions for organizing user data: Windows uses AppData (Roaming for synced data, Local for machine-specific), macOS uses ~/Library/Application Support, Linux follows the XDG Base Directory Specification. XDG defines: $XDG_CONFIG_HOME (default ~/.config) for configuration files, $XDG_DATA_HOME (default ~/.local/share) for data files, $XDG_CACHE_HOME (default ~/.cache) for cache. These conventions ensure applications don't clutter the user's home directory and that data can be easily backed up or migrated.A.4. What is the cdecl calling convention? Why is it necessary when calling C functions from Pascal?
Guidance
The `cdecl` calling convention specifies how function arguments are passed (right-to-left on the stack), who cleans up the stack (the caller), and how the return value is passed. It is the standard C calling convention. Pascal uses a different default convention (register or stdcall). Without specifying cdecl, the Pascal code would push arguments and clean up the stack differently from what the C library expects, causing stack corruption and crashes.A.5. Explain why {$IFDEF WINDOWS} blocks are evaluated at compile time, not runtime. What are the implications for the compiled executable?
Guidance
Conditional compilation directives are processed by the compiler before code generation. Code inside a false {$IFDEF} block is completely excluded — it does not appear in the compiled executable at all. Implications: (1) The executable contains only code for its target platform — no dead code. (2) You cannot detect the platform at runtime with IFDEF — it is a compile-time decision. (3) You must compile separately for each platform. (4) Syntax errors in excluded blocks may not be caught (the compiler never sees them).Part B: Applied Analysis
B.1. Design a cross-platform "system information" report that displays: OS name and version, CPU architecture, available memory, current user, home directory, and temporary directory. Show the Pascal code structure using conditional compilation.
Guidance
Use {$IFDEF WINDOWS/LINUX/DARWIN} blocks for each piece of information. Windows: GetEnvironmentVariable('USERNAME'), 'USERPROFILE', 'TEMP'; read OS version from registry or GetVersionEx API. Linux: read /proc/meminfo for memory, /proc/cpuinfo for CPU, GetEnvironmentVariable('USER'), 'HOME', $TMPDIR. macOS: similar to Linux but use 'sysctl' for hardware info. Wrap each in a function: GetOSName, GetCPUArch, GetAvailableMemory, etc. The main program calls these platform-agnostic functions.B.2. You need to integrate a third-party C library (libcrypto.so / libcrypto.dll) that provides an MD5 function. Design the Pascal interface. Show the type declarations, function declaration, and a usage example. Handle the case where the library is not installed.
Guidance
Declare the function signature matching the C API: type for MD5 context, functions for MD5_Init, MD5_Update, MD5_Final. Use cdecl external. For dynamic loading: LoadLibrary with platform-specific library name, GetProcAddress for each function, check for nil, provide meaningful error message if library not found. Wrap in a try-finally to ensure UnloadLibrary is called.Part C: Code Exercises
C.1. Write a program that lists all .pas files in the current directory and its subdirectories, showing each file's size and last modification date. Use FindFirst/FindNext with recursive directory traversal.
Guidance
Write a recursive procedure that takes a directory path. For each entry from FindFirst, if it's a directory (and not . or ..), recurse into it. If it's a .pas file, display its full path, size, and modification date (use FileDateToDateTime). Count and display the total number of files and total size at the end.C.2. Write a program that uses TProcess to run fpc -h and display the first 10 lines of the Free Pascal compiler's help output. Handle the case where fpc is not found in PATH.
Guidance
Create TProcess with Executable='fpc', Parameters.Add('-h'), Options=[poWaitOnExit, poUsePipes]. Execute in a try-except block. Read Output into a TStringList. Display the first 10 lines. If Execute raises an exception, display a helpful message about fpc not being installed or not in PATH.C.3. Create a cross-platform utility function GetSystemInfo that returns a record containing: platform name, user name, home directory, temp directory, and the number of command-line arguments. Test it on your platform.
Guidance
Define a TSystemInfo record. Use conditional compilation for platform-specific environment variable names. All functions should work on any platform without error — use fallback defaults if an environment variable is not set.C.4. Write a program that monitors a directory for new files. The program checks the directory every 2 seconds and prints a message when a new file appears. Use FindFirst/FindNext to track the file list, and compare it between checks.
Guidance
Maintain a TStringList of known filenames. Every 2 seconds, scan the directory. For each file found, check if it's in the known list. If not, print "New file: filename" and add it to the list. Also detect deleted files (in the list but not in the directory). Run until Ctrl+C or a configurable duration.Part D: Challenge Problems
D.1. Build a system monitor that displays CPU usage, memory usage, and disk space, updating every 3 seconds. On Windows, use WMI or performance counters. On Linux, read from /proc/stat, /proc/meminfo, and df output. Display in a formatted table.
Guidance
Linux approach: read /proc/stat twice (3 seconds apart), compute CPU usage from the delta in idle vs total jiffies. Read /proc/meminfo for total/free/available memory. Run 'df -h' via TProcess for disk space. Windows approach: use GetSystemInfo or read performance counters. Format output as a table with columns for metric, value, and percentage. Clear screen between updates for a dashboard effect.D.2. Write a Pascal wrapper for SQLite's C API. The wrapper should provide: Open/Close database, Execute SQL (with error handling), and a simple Query function that returns results as a TStringList (one string per row). Test by creating a table, inserting rows, and querying them.