Section 19. System Dependencies 19.1: How can I read a single character from the keyboard without waiting for the RETURN key? How can I stop characters from being echoed on the screen as they're typed? A: Alas, there is no standard or portable way to do these things in C. Concepts such as screens and keyboards are not even mentioned in the Standard, which deals only with simple I/O "streams" of characters. At some level, interactive keyboard input is usually collected and presented to the requesting program a line at a time. This gives the operating system a chance to support input line editing (backspace/delete/rubout, etc.) in a consistent way, without requiring that it be built into every program. Only when the user is satisfied and presses the RETURN key (or equivalent) is the line made available to the calling program. Even if the calling program appears to be reading input a character at a time (with getchar() or the like), the first call blocks until the user has typed an entire line, at which point potentially many characters become available and many character requests (e.g. getchar() calls) are satisfied in quick succession. When a program wants to read each character immediately as it arrives, its course of action will depend on where in the input stream the line collection is happening and how it can be disabled. Under some systems (e.g. MS-DOS, VMS in some modes), a program can use a different or modified set of OS-level input calls to bypass line-at-a-time input processing. Under other systems (e.g. Unix, VMS in other modes), the part of the operating system responsible for serial input (often called the "terminal driver") must be placed in a mode which turns off line- at-a-time processing, after which all calls to the usual input routines (e.g. read(), getchar(), etc.) will return characters immediately. Finally, a few systems (particularly older, batch- oriented mainframes) perform input processing in peripheral processors which cannot be told to do anything other than line- at-a-time input. Therefore, when you need to do character-at-a-time input (or disable keyboard echo, which is an analogous problem), you will have to use a technique specific to the system you're using, assuming it provides one. Since comp.lang.c is oriented towards those topics that the C language has defined support for, you will usually get better answers to other questions by referring to a system-specific newsgroup such as comp.unix.questions or comp.os.msdos.programmer, and to the FAQ lists for these groups. Note that the answers are often not unique even across different variants of a system; bear in mind when answering system- specific questions that the answer that applies to your system may not apply to everyone else's. However, since these questions are frequently asked here, here are brief answers for some common situations. Some versions of curses have functions called cbreak(), noecho(), and getch() which do what you want. If you're specifically trying to read a short password without echo, you might try getpass(). Under Unix, you can use ioctl() to play with the terminal driver modes (CBREAK or RAW under "classic" versions; ICANON, c_cc[VMIN] and c_cc[VTIME] under System V or POSIX systems; ECHO under all versions), or in a pinch, system() and the stty command. (For more information, see and tty(4) under classic versions, and termio(4) under System V, or and termios(4) under POSIX.) Under MS-DOS, use getch() or getche(), or the corresponding BIOS interrupts. Under VMS, try the Screen Management (SMG$) routines, or curses, or issue low-level $QIO's with the IO$_READVBLK function code (and perhaps IO$M_NOECHO, and others) to ask for one character at a time. (It's also possible to set character-at-a-time or "pass through" modes in the VMS terminal driver.) Under other operating systems, you're on your own. (As an aside, note that simply using setbuf() or setvbuf() to set stdin to unbuffered will *not* generally serve to allow character-at-a-time input.) If you're trying to write a portable program, a good approach is to define your own suite of three functions to (1) set the terminal driver or input system into character-at-a-time mode (if necessary), (2) get characters, and (3) return the terminal driver to its initial state when the program is finished. (Ideally, such a set of functions might be part of the C Standard, some day.) The extended versions of this FAQ list (see question 20.40) contain examples of such functions for several popular systems. See also question 19.2. References: PCS Sec. 10 pp. 128-9, Sec. 10.1 pp. 130-1; POSIX Sec. 7. 19.2: How can I find out if there are characters available for reading (and if so, how many)? Alternatively, how can I do a read that will not block if there are no characters available? A: These, too, are entirely operating-system-specific. Some versions of curses have a nodelay() function. Depending on your system, you may also be able to use "nonblocking I/O", or a system call named "select" or "poll", or the FIONREAD ioctl, or c_cc[VTIME], or kbhit(), or rdchk(), or the O_NDELAY option to open() or fcntl(). See also question 19.1. 19.3: How can I display a percentage-done indication that updates itself in place, or show one of those "twirling baton" progress indicators? A: These simple things, at least, you can do fairly portably. Printing the character '\r' will usually give you a carriage return without a line feed, so that you can overwrite the current line. The character '\b' is a backspace, and will usually move the cursor one position to the left. References: ISO Sec. 5.2.2. 19.4: How can I clear the screen? How can I print text in color? How can I move the cursor to a specific x, y position? A: Such things depend on the terminal type (or display) you're using. You will have to use a library such as termcap, terminfo, or curses, or some system-specific routines, to perform these operations. On MS-DOS systems, two functions to look for are clrscr() and gotoxy(). For clearing the screen, a halfway portable solution is to print a form-feed character ('\f'), which will cause some displays to clear. Even more portable (albeit even more gunky) might be to print enough newlines to scroll everything away. As a last resort, you could use system() (see question 19.27) to invoke an operating system clear-screen command. References: PCS Sec. 5.1.4 pp. 54-60, Sec. 5.1.5 pp. 60-62. 19.5: How do I read the arrow keys? What about function keys? A: Terminfo, some versions of termcap, and some versions of curses have support for these non-ASCII keys. Typically, a special key sends a multicharacter sequence (usually beginning with ESC, '\033'); parsing these can be tricky. (curses will do the parsing for you, if you call keypad() first.) Under MS-DOS, if you receive a character with value 0 (*not* '0'!) while reading the keyboard, it's a flag indicating that the next character read will be a code indicating a special key. See any DOS programming guide for lists of keyboard scan codes. (Very briefly: the up, left, right, and down arrow keys are 72, 75, 77, and 80, and the function keys are 59 through 68.) References: PCS Sec. 5.1.4 pp. 56-7. 19.6: How do I read the mouse? A: Consult your system documentation, or ask on an appropriate system-specific newsgroup (but check its FAQ list first). Mouse handling is completely different under the X window system, MS- DOS, the Macintosh, and probably every other system. References: PCS Sec. 5.5 pp. 78-80. 19.7: How can I do serial ("comm") port I/O? A: It's system-dependent. Under Unix, you typically open, read, and write a device file in /dev, and use the facilities of the terminal driver to adjust its characteristics. (See also questions 19.1 and 19.2.) Under MS-DOS, you can use the predefined stream stdaux, or a special file like COM1, or some primitive BIOS interrupts, or (if you require decent performance) any number of interrupt-driven serial I/O packages. Several netters recommend the book _C Programmer's Guide to Serial Communications_, by Joe Campbell. 19.8: How can I direct output to the printer? A: Under Unix, either use popen() (see question 19.30) to write to the lp or lpr program, or perhaps open a special file like /dev/lp. Under MS-DOS, write to the (nonstandard) predefined stdio stream stdprn, or open the special files PRN or LPT1. References: PCS Sec. 5.3 pp. 72-74. 19.9: How do I send escape sequences to control a terminal or other device? A: If you can figure out how to send characters to the device at all (see question 19.8 above), it's easy enough to send escape sequences. In ASCII, the ESC code is 033 (27 decimal), so code like fprintf(ofd, "\033[J"); sends the sequence ESC [ J . 19.10: How can I do graphics? A: Once upon a time, Unix had a fairly nice little set of device- independent plot functions described in plot(3) and plot(5). The GNU libplot package maintains the same spirit and supports many modern plot devices; see http://www.gnu.org/software/plotutils/plotutils.html . If you're programming for MS-DOS, you'll probably want to use libraries conforming to the VESA or BGI standards. If you're trying to talk to a particular plotter, making it draw is usually a matter of sending it the appropriate escape sequences; see also question 19.9. The vendor may supply a C- callable library, or you may be able to find one on the net. If you're programming for a particular window system (Macintosh, X windows, Microsoft Windows), you will use its facilities; see the relevant documentation or newsgroup or FAQ list. References: PCS Sec. 5.4 pp. 75-77. 19.11: How can I check whether a file exists? I want to warn the user if a requested input file is missing. A: It's surprisingly difficult to make this determination reliably and portably. Any test you make can be invalidated if the file is created or deleted (i.e. by some other process) between the time you make the test and the time you try to open the file. Three possible test functions are stat(), access(), and fopen(). (To make an approximate test using fopen(), just open for reading and close immediately, although failure does not necessarily indicate nonexistence.) Of these, only fopen() is widely portable, and access(), where it exists, must be used carefully if the program uses the Unix set-UID feature. Rather than trying to predict in advance whether an operation such as opening a file will succeed, it's often better to try it, check the return value, and complain if it fails. (Obviously, this approach won't work if you're trying to avoid overwriting an existing file, unless you've got something like the O_EXCL file opening option available, which does just what you want in this case.) References: PCS Sec. 12 pp. 189,213; POSIX Sec. 5.3.1, Sec. 5.6.2, Sec. 5.6.3. 19.12: How can I find out the size of a file, prior to reading it in? A: If the "size of a file" is the number of characters you'll be able to read from it in C, it is difficult or impossible to determine this number exactly. Under Unix, the stat() call will give you an exact answer. Several other systems supply a Unix-like stat() which will give an approximate answer. You can fseek() to the end and then use ftell(), or maybe try fstat(), but these tend to have the same sorts of problems: fstat() is not portable, and generally tells you the same thing stat() tells you; ftell() is not guaranteed to return a byte count except for binary files. Some systems provide functions called filesize() or filelength(), but these are obviously not portable, either. Are you sure you have to determine the file's size in advance? Since the most accurate way of determining the size of a file as a C program will see it is to open the file and read it, perhaps you can rearrange the code to learn the size as it reads. References: ISO Sec. 7.9.9.4; H&S Sec. 15.5.1; PCS Sec. 12 p. 213; POSIX Sec. 5.6.2. 19.12b: How can I find the modification date and time of a file? A: The Unix and POSIX function is stat(), which several other systems supply as well. (See also question 19.12.) 19.13: How can a file be shortened in-place without completely clearing or rewriting it? A: BSD systems provide ftruncate(), several others supply chsize(), and a few may provide a (possibly undocumented) fcntl option F_FREESP. Under MS-DOS, you can sometimes use write(fd, "", 0). However, there is no portable solution, nor a way to delete blocks at the beginning. See also question 19.14. 19.14: How can I insert or delete a line (or record) in the middle of a file? A: Short of rewriting the file, you probably can't. The usual solution is simply to rewrite the file. (Instead of deleting records, you might consider simply marking them as deleted, to avoid rewriting.) Another possibility, of course, is to use a database instead of a flat file. See also questions 12.30 and 19.13. 19.15: How can I recover the file name given an open stream or file descriptor? A: This problem is, in general, insoluble. Under Unix, for instance, a scan of the entire disk (perhaps involving special permissions) would theoretically be required, and would fail if the descriptor were connected to a pipe or referred to a deleted file (and could give a misleading answer for a file with multiple links). It is best to remember the names of files yourself as you open them (perhaps with a wrapper function around fopen()). 19.16: How can I delete a file? A: The Standard C Library function is remove(). (This is therefore one of the few questions in this section for which the answer is *not* "It's system-dependent.") On older, pre-ANSI Unix systems, remove() may not exist, in which case you can try unlink(). References: K&R2 Sec. B1.1 p. 242; ISO Sec. 7.9.4.1; H&S Sec. 15.15 p. 382; PCS Sec. 12 pp. 208,220-221; POSIX Sec. 5.5.1, Sec. 8.2.4. 19.16b: How do I copy files? A: Either use system() to invoke your operating system's copy utility (see question 19.27), or open the source and destination files (using fopen() or some lower-level file-opening system call), read characters or blocks of characters from the source file, and write them to the destination file. References: K&R Sec. 1, Sec. 7. 19.17: Why can't I open a file by its explicit path? The call fopen("c:\newdir\file.dat", "r") is failing. A: The file you actually requested -- with the characters \n and \f in its name -- probably doesn't exist, and isn't what you thought you were trying to open. In character constants and string literals, the backslash \ is an escape character, giving special meaning to the character following it. In order for literal backslashes in a pathname to be passed through to fopen() (or any other function) correctly, they have to be doubled, so that the first backslash in each pair quotes the second one: fopen("c:\\newdir\\file.dat", "r") Alternatively, under MS-DOS, it turns out that forward slashes are also accepted as directory separators, so you could use fopen("c:/newdir/file.dat", "r") (Note, by the way, that header file names mentioned in preprocessor #include directives are *not* string literals, so you may not have to worry about backslashes there.) 19.18: I'm getting an error, "Too many open files". How can I increase the allowable number of simultaneously open files? A: There are typically at least two resource limitations on the number of simultaneously open files: the number of low-level "file descriptors" or "file handles" available in the operating system, and the number of FILE structures available in the stdio library. Both must be sufficient. Under MS-DOS systems, you can control the number of operating system file handles with a line in CONFIG.SYS. Some compilers come with instructions (and perhaps a source file or two) for increasing the number of stdio FILE structures. 19.20: How can I read a directory in a C program? A: See if you can use the opendir() and readdir() functions, which are part of the POSIX standard and are available on most Unix variants. Implementations also exist for MS-DOS, VMS, and other systems. (MS-DOS also has FINDFIRST and FINDNEXT routines which do essentially the same thing.) readdir() only returns file names; if you need more information about the file, try calling stat(). To match filenames to some wildcard pattern, see question 13.7. References: K&R2 Sec. 8.6 pp. 179-184; PCS Sec. 13 pp. 230-1; POSIX Sec. 5.1; Schumacher, ed., _Software Solutions in C_ Sec. 8. 19.22: How can I find out how much memory is available? A: Your operating system may provide a routine which returns this information, but it's quite system-dependent. 19.23: How can I allocate arrays or structures bigger than 64K? A: A reasonable computer ought to give you transparent access to all available memory. If you're not so lucky, you'll either have to rethink your program's use of memory, or use various system-specific techniques. 64K is (still) a pretty big chunk of memory. No matter how much memory your computer has available, it's asking a lot to be able to allocate huge amounts of it contiguously. (The C Standard does not guarantee that single objects can be 32K or larger, or 64K for C9X.) Often it's a good idea to use data structures which don't require that all memory be contiguous. For dynamically-allocated multidimensional arrays, you can use pointers to pointers, as illustrated in question 6.16. Instead of a large array of structures, you can use a linked list, or an array of pointers to structures. If you're using a PC-compatible (8086-based) system, and running up against a 64K or 640K limit, consider using "huge" memory model, or expanded or extended memory, or malloc variants such as halloc() or farmalloc(), or a 32-bit "flat" compiler (e.g. djgpp, see question 18.3), or some kind of a DOS extender, or another operating system. References: ISO Sec. 5.2.4.1; C9X Sec. 5.2.4.1. 19.24: What does the error message "DGROUP data allocation exceeds 64K" mean, and what can I do about it? I thought that using large model meant that I could use more than 64K of data! A: Even in large memory models, MS-DOS compilers apparently toss certain data (strings, some initialized global or static variables) into a default data segment, and it's this segment that is overflowing. Either use less global data, or, if you're already limiting yourself to reasonable amounts (and if the problem is due to something like the number of strings), you may be able to coax the compiler into not using the default data segment for so much. Some compilers place only "small" data objects in the default data segment, and give you a way (e.g. the /Gt option under Microsoft compilers) to configure the threshold for "small." 19.25: How can I access memory (a memory-mapped device, or graphics memory) located at a certain address? A: Set a pointer, of the appropriate type, to the right number (using an explicit cast to assure the compiler that you really do intend this nonportable conversion): unsigned int *magicloc = (unsigned int *)0x12345678; Then, *magicloc refers to the location you want. (Under MS-DOS, you may find a macro like MK_FP() handy for working with segments and offsets.) References: K&R1 Sec. A14.4 p. 210; K&R2 Sec. A6.6 p. 199; ISO Sec. 6.3.4; Rationale Sec. 3.3.4; H&S Sec. 6.2.7 pp. 171-2. 19.27: How can I invoke another program (a standalone executable, or an operating system command) from within a C program? A: Use the library function system(), which does exactly that. Note that system's return value is at best the command's exit status (although even that is not guaranteed), and usually has nothing to do with the output of the command. Note also that system() accepts a single string representing the command to be invoked; if you need to build up a complex command line, you can use sprintf(). See also question 19.30. References: K&R1 Sec. 7.9 p. 157; K&R2 Sec. 7.8.4 p. 167, Sec. B6 p. 253; ISO Sec. 7.10.4.5; H&S Sec. 19.2 p. 407; PCS Sec. 11 p. 179. 19.30: How can I invoke another program or command and trap its output? A: Unix and some other systems provide a popen() function, which sets up a stdio stream on a pipe connected to the process running a command, so that the output can be read (or the input supplied). (Also, remember to call pclose().) If you can't use popen(), you may be able to use system(), with the output going to a file which you then open and read. If you're using Unix and popen() isn't sufficient, you can learn about pipe(), dup(), fork(), and exec(). (One thing that probably would *not* work, by the way, would be to use freopen().) References: PCS Sec. 11 p. 169. 19.31: How can my program discover the complete pathname to the executable from which it was invoked? A: argv[0] may contain all or part of the pathname, or it may contain nothing. You may be able to duplicate the command language interpreter's search path logic to locate the executable if the name in argv[0] is present but incomplete. However, there is no guaranteed solution. References: K&R1 Sec. 5.11 p. 111; K&R2 Sec. 5.10 p. 115; ISO Sec. 5.1.2.2.1; H&S Sec. 20.1 p. 416. 19.32: How can I automatically locate a program's configuration files in the same directory as the executable? A: It's hard; see also question 19.31 above. Even if you can figure out a workable way to do it, you might want to consider making the program's auxiliary (library) directory configurable, perhaps with an environment variable. (It's especially important to allow variable placement of a program's configuration files when the program will be used by several people, e.g. on a multiuser system.) 19.33: How can a process change an environment variable in its caller? A: It may or may not be possible to do so at all. Different operating systems implement global name/value functionality similar to the Unix environment in different ways. Whether the "environment" can be usefully altered by a running program, and if so, how, is system-dependent. Under Unix, a process can modify its own environment (some systems provide setenv() or putenv() functions for the purpose), and the modified environment is generally passed on to child processes, but it is *not* propagated back to the parent process. Under MS-DOS, it's possible to manipulate the master copy of the environment, but the required techniques are arcane. (See an MS-DOS FAQ list.) 19.36: How can I read in an object file and jump to locations in it? A: You want a dynamic linker or loader. It may be possible to malloc some space and read in object files, but you have to know an awful lot about object file formats, relocation, etc. Under BSD Unix, you could use system() and ld -A to do the linking for you. Many versions of SunOS and System V have the -ldl library which allows object files to be dynamically loaded. Under VMS, use LIB$FIND_IMAGE_SYMBOL. GNU has a package called "dld". See also question 15.13. 19.37: How can I implement a delay, or time a user's response, with sub- second resolution? A: Unfortunately, there is no portable way. V7 Unix, and derived systems, provided a fairly useful ftime() function with resolution up to a millisecond, but it has disappeared from System V and POSIX. Other routines you might look for on your system include clock(), delay(), gettimeofday(), msleep(), nap(), napms(), nanosleep(), setitimer(), sleep(), times(), and usleep(). (A function called wait(), however, is at least under Unix *not* what you want.) The select() and poll() calls (if available) can be pressed into service to implement simple delays. On MS-DOS machines, it is possible to reprogram the system timer and timer interrupts. Of these, only clock() is part of the ANSI Standard. The difference between two calls to clock() gives elapsed execution time, and may even have subsecond resolution, if CLOCKS_PER_SEC is greater than 1. However, clock() gives elapsed processor time used by the current program, which on a multitasking system may differ considerably from real time. If you're trying to implement a delay and all you have available is a time-reporting function, you can implement a CPU-intensive busy-wait, but this is only an option on a single-user, single- tasking machine as it is terribly antisocial to any other processes. Under a multitasking operating system, be sure to use a call which puts your process to sleep for the duration, such as sleep() or select(), or pause() in conjunction with alarm() or setitimer(). For really brief delays, it's tempting to use a do-nothing loop like long int i; for(i = 0; i < 1000000; i++) ; but resist this temptation if at all possible! For one thing, your carefully-calculated delay loops will stop working properly next month when a faster processor comes out. Perhaps worse, a clever compiler may notice that the loop does nothing and optimize it away completely. References: H&S Sec. 18.1 pp. 398-9; PCS Sec. 12 pp. 197-8,215- 6; POSIX Sec. 4.5.2. 19.38: How can I trap or ignore keyboard interrupts like control-C? A: The basic step is to call signal(), either as #include signal(SIGINT, SIG_IGN); to ignore the interrupt signal, or as extern void func(int); signal(SIGINT, func); to cause control to transfer to function func() on receipt of an interrupt signal. On a multi-tasking system such as Unix, it's best to use a slightly more involved technique: extern void func(int); if(signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, func); The test and extra call ensure that a keyboard interrupt typed in the foreground won't inadvertently interrupt a program running in the background (and it doesn't hurt to code calls to signal() this way on any system). On some systems, keyboard interrupt handling is also a function of the mode of the terminal-input subsystem; see question 19.1. On some systems, checking for keyboard interrupts is only performed when the program is reading input, and keyboard interrupt handling may therefore depend on which input routines are being called (and *whether* any input routines are active at all). On MS-DOS systems, setcbrk() or ctrlbrk() functions may also be involved. References: ISO Secs. 7.7,7.7.1; H&S Sec. 19.6 pp. 411-3; PCS Sec. 12 pp. 210-2; POSIX Secs. 3.3.1,3.3.4. 19.39: How can I handle floating-point exceptions gracefully? A: On many systems, you can define a function matherr() which will be called when there are certain floating-point errors, such as errors in the math routines in . You may also be able to use signal() (see question 19.38 above) to catch SIGFPE. See also question 14.9. References: Rationale Sec. 4.5.1. 19.40: How do I... Use sockets? Do networking? Write client/server applications? A: All of these questions are outside of the scope of this list and have much more to do with the networking facilities which you have available than they do with C. Good books on the subject are Douglas Comer's three-volume _Internetworking with TCP/IP_ and W. R. Stevens's _UNIX Network Programming_. (There is also plenty of information out on the net itself, including the "Unix Socket FAQ" at http://kipper.york.ac.uk/~vic/sock-faq/ .) 19.40b: How do I... Use BIOS calls? Write ISR's? Create TSR's? A: These are very particular to specific systems (PC compatibles running MS-DOS, most likely). You'll get much better information in a specific newsgroup such as comp.os.msdos.programmer or its FAQ list; another excellent resource is Ralf Brown's interrupt list. 19.40c: I'm trying to compile this program, but the compiler is complaining that "union REGS" is undefined, and the linker is complaining that int86() is undefined. A: Those have to do with MS-DOS interrupt programming. They don't exist on other systems. 19.41: But I can't use all these nonstandard, system-dependent functions, because my program has to be ANSI compatible! A: You're out of luck. Either you misunderstood your requirement, or it's an impossible one to meet. ANSI/ISO Standard C simply does not define ways of doing these things; it is a language standard, not an operating system standard. An international standard which does address many of these issues is POSIX (IEEE 1003.1, ISO/IEC 9945-1), and many operating systems (not just Unix) now have POSIX-compatible programming interfaces. It is possible, and desirable, for *most* of a program to be ANSI-compatible, deferring the system-dependent functionality to a few routines in a few files which are rewritten for each system ported to.