[prev] [up] [overview] [next]

Section 16. System Dependencies

16.1: How can I read a single character from the keyboard without waiting for a newline?

Contrary to popular belief and many people's wishes, this is not a C-related question.  (Nor are closely-related questions concerning the echo of keyboard input.)  The delivery of characters from a "keyboard" to a C program is a function of the operating system in use, and has not been standardized by the C language.  Some versions of curses have a cbreak() function which does what you want. If you're specifically trying to read a short password without echo, you might try getpass() Under Unix, 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). Under MS-DOS, use getch(). Under VMS, try the Screen Management (SMG$) routines, or curses, or issue low-level $QIO's with the IO$_READVBLK (and perhaps IO$M_NOECHO) function codes to ask for one character at a time. Under other operating systems, you're on your own. Beware that some operating systems make this sort of thing impossible, because character collection into input lines is done by peripheral processors not under direct control of the CPU running your program.

Operating system specific questions are not appropriate for comp.lang.c .  Many common questions are answered in frequently-asked questions postings in such groups as comp.unix.questions and comp.os.msdos.programmer .  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.

References: PCS Sec. 10 pp. 128-9, Sec. 10.1 pp. 130-1.

16.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?

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 the FIONREAD ioctl, or kbhit(), or rdchk(), or the O_NDELAY option to open() or fcntl().

16.3: How can I clear the screen?  How can I print things in inverse video?

Such things depend on the terminal type (or display) you're using.  You will have to use a library such as termcap or curses, or some system-specific routines, to perform these functions.

16.4: How do I read the mouse?

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, Macintosh, and probably every other system.

16.5: How can my program discover the complete pathname to the executable file from which it was invoked?

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 or portable solution.

16.6: How can a process change an environment variable in its caller?

In general, it cannot.  Different operating systems implement 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() and/or putenv() functions to do this), and the modified environment is usually passed on to any child processes, but it is not propagated back to the parent process.

16.7: How can I check whether a file exists?  I want to query the user before overwriting existing files.

On Unix-like systems, you can try the access() routine, although it's got a few problems.  (It isn't atomic with respect to the following action, and can have anomalies if used in setuid programs.)  Another option (perhaps preferable) is to call stat() on the file.  Otherwise, the only guaranteed and portable way to test for file existence is to try opening the file (which doesn't help if you're trying to avoid overwriting an existing file, unless you've got something like the BSD Unix O_EXCL open option available).

16.8: How can I find out the size of a file, prior to reading it in?

If the "size of a file" is the number of characters you'll be able to read from it in C, it is in general impossible to determine this number in advance.  Under Unix, the stat call will give you an exact answer, and several other systems supply a Unix-like stat which will give an approximate answer.  You can fseek to the end and then use ftell, but this usage is nonportable (it gives you an accurate answer only under Unix, and otherwise a quasi-accurate answer only for ANSI C "binary" files).  Some systems provide routines called filesize or filelength.

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.

16.9: How can a file be shortened in-place without completely clearing or rewriting it?

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 truly portable solution.

16.10: How can I implement a delay, or time a user's response, with sub-second resolution?

Unfortunately, there is no portable way.  V7 Unix, and derived systems, provided a fairly useful ftime() routine 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 nap(), setitimer(), msleep(), usleep(), clock(), and gettimeofday() 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.

16.11: How can I read in an object file and jump to routines in it?

You want a dynamic linker and/or loader.  It is 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 (most?) versions of SunOS and System V have the -ldl library which allows object files to be dynamically loaded. There is also a GNU package called "dld".  See also question 7.6.

16.12: How can I invoke an operating system command from within a program?

Use system().

References: K&R II Sec. B6 p. 253; ANSI Sec. 4.10.4.5; H&S Sec. 21.2; PCS Sec. 11 p. 179;

16.13: How can I invoke an operating system command and trap its output?

Unix and some other systems provide a popen() routine, 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).  Alternately, invoke the command simply (see question 16.12) in such a way that it writes its output to a file, then open and read that file.

References: PCS Sec. 11 p. 169 .

16.14: How can I read a directory in a C program?

See if you can use the opendir() and readdir() routines, which are available on most Unix systems.  Implementations also exist for MS-DOS, VMS, and other systems.  (MS-DOS also has FINDFIRST and FINDNEXT routines which do essentially the same thing.)

16.15: How can I do serial ("comm") port I/O?

It's system-dependent.  Under Unix, you typically open, read, and write a device in /dev, and use the facilities of the terminal driver to adjust its characteristics.  Under MS-DOS, you can either use some primitive BIOS interrupts, or (if you require decent performance) one of any number of interrupt-driven serial I/O packages.


[prev] [up] [overview] [next]