This article is from the Apple II GNO FAQ, by Devin Reade with numerous contributions by others.
A#9.2: The first thing to watch for is known compiler and library bugs. Soenke Behrens maintains the current ORCA/C bug report list. You should keep the contents of this list in mind when examining the target source code. The ORCA/C bug report list may be found at http://www.arrowweb.com/sbehrens/obugs.htm This list has been considerably shorted since the release of ORCA/C v2.1.0. If you have an earlier version of ORCA/C, you should seriously consider an upgrade. The following items should be watched for, in no particular order. Since UNIX source is usually in C, that language is assumed for the rest of this section, where relevant: sizeof(int) The size of the type "int" is implementation-defined. While most modern C compilers use 32 bits, ORCA/C still uses 16 bits since this is the "natural" integer size of the 65816. This also results in more effective code generation. While the size of an int shouldn't make a difference to any well-written code, there is some available source code that assumes that ints are 32 bits. You should watch for this in any code that does bit manipulations. You should also watch for code that freely converts between integers and pointers. GNU (Free Software Foundation) software is often bad for this. recursion When possible, recursion should be avoided when programming on the Apple IIgs. This is because recursion invariably causes stack growth and the stack can only exist in bank zero. This means that the maximum space available for the stack is 64k. In practise, it is much smaller. This problem is exacerbated under GNO where all processes must share the available stack space (each process has its own stack, though). Any program that uses recursion can be rewritten to use iteration instead. You should try to do this when possible. If you do use recursion, don't allocate a huge stack; this will keep other programs from executing. Also, you should leave in stack checking and stack repair (if programming with ORCA/C) to ensure that your recursion does not crash the machine if it goes too far. reference to absolute file descriptors True UNIX machines invariably use the file descriptors 0, 1, and 2 for standard input, standard output, and standard error, respectively. Under GNO, the file descriptors used are 1, 2, and 3. This causes a problem when source code is written to use these descriptors directly. You should search your code for references to these descriptors, typically in calls to open, close, read, write, dup, dup2, and fcntl. Instead of replacing these digits with other digits though, you should use the macros STDIN_FILENO, STDOUT_FILENO, and STDERR_FILENO defined in <unistd.h>. This will ensure that your source is kept portable. fork Because of problems that are discussed in the fork(2) man page and the kernel reference, the fork system call under GNO is different than other versions of UNIX. Besides having a different prototype, the parent and child process share the same address space. In this respect, GNO is less a multitasking environment than it is a multithreading environment. Search for calls to fork; you will have to rewrite these sections of code. See also the man page for fork2(2); it may be more suited to your purposes. Also note than when compiling routines that make a call to fork, you should turn off ORCA/C's stack repair code. This means that you should be using an optimization level of at least 8. read/write of newline character Most UNIX systems use LF (ASCII 0x0a) as the line delimiter. Both Apple II and Macintosh computers use CR (ASCII 0x0d) as the line delimiter. The C newline character is '\n'; ASCII 0x0a. While the stdio routines (fprintf(3), fread(3), etc) usually make this difference unnoticable by doing CR-->LF translation on input and LF-->CR translation on output, no such translation is done on files accessed through read(2) and write(2). Specifically, the GNO open(2) does not recognize the ORCA/C O_BINARY bit in it's second argument. Therefore, if the program you are porting makes calls to read(2) and write(2), watch for the '\n' character in your code. You may have to change this to '\r'. Don't do it blindly, because many programs will use both stdio and operations on the bare file descriptors. One suggestion is to modify your programs low-level I/O routines to modify the I/O buffer prior to calling write(2) and after calling read(2). variadic functions Some (poorly written) UNIX programs have variadic functions where the number of provided arguments don't match the number of arguments expected by the called routine. Even though this is in some cases legal ANSI/C, versions of ORCA/C prior to v2.1 would puke magnificently when encountering such code. Some of these cases are now handled in a more robust fashion by ORCA/C v2.1 and later. If you are defining (as opposed to using) variadic functions, you must turn off stack repair code around the definitions of those functions. The ORCA/C manual (and especially the release notes for v2.1) have important and detailed information on this topic. See the sections on the optimize and debug #pragmas. open, chmod, fchmod, creat, st_mode, stat, fstat, lstat In general, the bits in the mode parameter of these functions do not directly map between UNIX and GNO implementations. If your application is using macros such as S_IREAD or S_IWRITE for the mode parameters, and those macros are taken from the system header file <sys/stat.h>, then you probably don't need to modify your application. If, on the other hand, your application is using its own constants for the mode parameter, you should convert it to use the standard macros. Failure to do so may result in files with strange GS/OS flags set, or file tests failing in your program. /dev One of the UNIX philosophies is that "everything is a file". The /dev directory on UNIX systems contain device special files. Accessing these files is the way to access the relevant hardware. For GNO programs, you should not access devices in the /dev directory. For example, opening "/dev/console" for writing will not have the expected effect. Instead you should open the corresponding GS/OS device, ".ttyco". The portable (and suggested) method of handling these cases is not to change the value of the string (in this example) from "/dev/console" to ".ttyco". Instead, use the macros defined in the file <paths.h>. For this example, one would use the macro _PATH_CONSOLE. standard path assumptions This one is closely tied in with the "/dev" description above. The <paths.h> file contains macros for various standard paths. The macros, instead of the actual paths, should be used to maximize portability. signal handlers When a signal handler is called, the data bank register may not have an expected value. If your program references global scalars, it may crash. To avoid this, all functions used as signal handlers should have their definition preceded by #pragma databank 1 and followed by #pragma databank 0 validity of pathnames Most programs make assumptions about what constitutes a valid file name. For most modern Unices, a valid file name follows the POSIX portable filename character set: The characters a-z and A-Z, the digits 0-9, and '.', '_', and '-'. The '-' is not used as the first character of a file name, and '/' is the directory separator character. The maximum filename length is at least 14 characters, and the maximum pathname length is at least 255 characters. Now this is different from what is available under GNO. The ProDOS FST provides only a subset of the above. The HFS FST provides a superset, but HFS is too slow, too buggy, and too unmaintainable for many users. The problem is also compounded by the fact that under GS/OS, the ':' is a directory separator. '/' may be used but it is mapped internally to ':'. Unfortunately, there is no general consensus on how to handle pathnames under GNO. Here are some opinions, all of which refer to user code; the GNO kernel treats pathnames the same way that GS/OS does: - the ':' character should be mapped to '/'. This prohibits the use of '/' in file names. It also provides the highest degree of "UNIX compatibility"; or - the '/' character should be mapped to ':'. This is more in line with GS/OS, but can require extensive rewrites of ported UNIX programs; or - use dynamic directory delimiters. The ':' character is always considered to be a directory separator. The '/' character is considered to be a directory separator unless it was preceded at some point by a ':', in which case it is part of the file name. Having a '/' appear before ':' in a pathname is illegal. This is the closest to GS/OS, but also has some problems with POSIX compliance. For example, the PATH environment variable is supposed to be a list of pathnames delimited by the ':' character. This implies that one cannot use the ':' as a directory delimiter when defining PATH, and that directories in PATH must not contain '/' as a regular character. Regardless of which method you use to do filename, pathname, and directory separator mapping, you should verify that the pathname is legal for your target filesystem. GS/OS provides a mechanism to do this through the JudgeName system call. Also watch out for references to the root partition. For other UNIXs, this is the pathname "/", which is a not legal directory under GS/OS (and therefore GNO). Hopefully the context of your program will give you an idea how to handle such a directory reference in a sensible manner. unlink Many UNIX programs unlink (delete) files while they still have them open. Under true UNIX systems, this means that the file will be deleted as soon as it is closed. This is is not done under GNO, and attempting to unlink an open file will fail, and the file will remain on the file system after it is closed. If your program relies on this behavior, you will have to find a work-around. One partial solution is to register a clean-up function via atexit(3) that deletes your files for you. [This method is not suitable for daemons or other long-running programs.]
 
Continue to: