In order to arrange the files in columns, you need to figure out the current width of the terminal window. On many unix-like systems (including Linux and OS X), you can indeed use ioctl
to get that information, using the TIOCGWINSZ
selector.
This is precisely what ls
does (on systems which support the ioctl
request), once it has determined that standard output is a terminal (unless single-column firmat is forced with the -1
flag). If it cannot figure out the terminal width, it uses 80.
Here's a quick example of how to get the information. (On Linux systems, you can probably find the details by typing man tty_ioctl
).
For simplicity, the following code assumes that stdout
is file descriptor 1. In retrospect, FILE_STDOUT
would have been better. If you wanted to check an arbitrary open file, you would need to use fileno
to get the fd number for the FILE*
.
/* This must come before any include, in order to see the
* declarations of Posix functions which are not in standard C
*/
#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
/* If stdout is a terminal and it is possible to find out how many
* columns its window has, return that number. Otherwise, return -1
*/
int window_get_columns(void) {
struct winsize sizes;
int cols = -1;
if (isatty(1)) {
/* Only try this if stdout is a terminal */
int status = ioctl(1, TIOCGWINSZ, &sizes);
if (status == 0) {
cols = sizes.ws_col;
}
}
return cols;
}
/* Example usage */
/* Print a line consisting of 'len' copies of the character 'ch' */
void print_row(int len, int ch) {
for (int i = 0; i < len; ++i) putchar(ch);
putchar('\n');
}
int main(int argc, char* argv[]) {
/* Print the first argument centred in the terminal window,
* if standard output is a terminal
*/
if (argc <= 1) return 1; /* No argument, nothing to do */
int width = window_get_columns();
/* If we can't figure out the width of the screen, just use the
* width of the string
*/
int arglen = strlen(argv[1]);
if (width < 0) width = arglen;
int indent = (width - arglen) / 2;
print_row(width - 1, '-');
printf("%*s\n", indent + arglen, argv[1]);
print_row(width - 1, '-');
return 0;
}
Since writing the above sample, I tracked down the source of the Gnu implementation of ls
; its (somewhat more careful) invocation of ioctl
will be seen here