[comp.os.minix] c.c for minix

wayne@csri.toronto.edu (Wayne Hayes) (07/12/90)

In article <m0hpkAL-00001QC@JUTS.ccc.amdahl.com> craig.mclaughlin@cccmvs.UUCP writes:
>  Is there something I'm missing when I read the manual pages for
>ls()?  Is there an equivalent to the -C or -F flags (to output in
>columns, and with executable/directory flags)?
>
>  HELP!  Because directories like /usr/bin are getting to be real
>difficult to look through...

There is a program called simply 'c' on our Sun system here.  I guess it
stands for "Column".  I re-wrote
it for DOS and then ported to Minix recently.  It's purpose is to read
a file, split it into white-space separated "words", find the longest
word, and make that (+ 1 space) the "column" width.  I then prints out
the words in columns.  However it's not quite the -C option because it
prints out the words in simple in-order fasshion, not down the page.  Ie,
the file

A.......................    B.... C.... D.....  E............... F..
G..

will come out as

A....................... B....                      C.....
D....                    E..............            F..
G..

rather than

A.......................  D....                     F..
B....                     E.............            G..
C.......

as the -C option does.  Anyway, until something better comes along,
I use ``ls | c''.  Of course it doesn't do anything about the -F option.
For that I just use "ls -l | grep '^d'".

    Also, the main program shows a simple "skeleton" for an arbitrary
Unix C utility: it checks for command line parameters, and if there
are any it takes them to be file names and loops through them calling
whatever function the program does (the c() function in this case),
else it calls the function once with the parameter stdin.  Pretty
simplistic, but it does the job usually...

    The c() function also shows some pretty fancy buffer handling to
avoid excessive malloc() calls, which on some systems can get very
slow and certainly wastes memory.  (one "malloc" call for each "word"
in this program.)  It even "free()'s" the memory properly before exitting!

---
"The number of programs that can be done with the HST has always greatly
exceeded the time available for their execution, and this remains true even
with the telescope in its current state." -- Hubble Space Telescope Science
Working Group and User's Commitee Report, 1990 June 29.

Wayne Hayes	INTERNET: wayne@csri.utoronto.ca	CompuServe: 72401,3525
---------------------------- cut here cut here cut here -----------------

/* c.c for Minix by Wayne Hayes                                        
** NOTE that for DOS and PC-MINIX the largest file it can handle is about
** ~55K since it has to read in the whole file to find the largest word
** before printing any output.  There are currently no options, but it
** accepts both files on the command line and standard input.
*/

#include <stdio.h>
#include <ctype.h>
#include <string.h>

#define off_stack static

char NL = '\n';

void bye(s)
char *s;
{	if(s) puts(s);
	exit(0);
}


char spaces[80];

int fgetword(S, fp)
char *S;
FILE *fp;
{
    char *s = S;
    while(isspace(*s = getc(fp))) ;
    if(*s == EOF) return EOF;
    while((*++s = getc(fp)) != EOF && !isspace(*s)) ;
    *s = '\0';
    return s - S;
}


#define BUFFSIZE 8192
#define NUMBUFFS 100

int columns;

void c(fp)
FILE *fp;
{	off_stack char *buf[NUMBUFFS], word[BUFFSIZE];
	off_stack int buffSize[NUMBUFFS], buffNum, i, j, maxLen,
		wordLen, wordsPerLine, wordNum;

	buf[0] = NULL;
	maxLen = 0;
	buffNum = -1;
	while(fgetword(word, fp) != EOF)
	{	wordLen = strlen(word) + 1;
		if(buffNum < 0 || wordLen + buffSize[buffNum] > BUFFSIZE)
		{	if(++buffNum >= NUMBUFFS ||
			(buf[buffNum] = malloc(BUFFSIZE)) == NULL)
				bye("out of memory");
			buffSize[buffNum] = 0;
		}
		strcpy(buf[buffNum] + buffSize[buffNum], word);
		buffSize[buffNum] += wordLen;
		if(wordLen > maxLen) maxLen = wordLen;
	}
	if(buffNum == -1)	/* there was no input */
		return;

	wordsPerLine = columns / maxLen;

	/* Now maxLen includes the trailing null. In the following, wordLen
	** does not.
	*/

	*word = wordNum = wordLen = 0;
	for(i = 0; i <= buffNum; i++)
	{	int len;
		for(j = 0; j < buffSize[i]; j += len + 1)
		{	len = strlen(buf[i] + j);
			if(wordNum == wordsPerLine)
			{	puts(word);
				*word = wordNum = wordLen = 0;
			}
			strcat(word /*+ wordLen*/, buf[i] +j);
			wordLen += len;
			if(wordNum < wordsPerLine - 1) /* all but last word on line */
			{	strncat(word /*+ wordLen*/, spaces, maxLen - len);
				wordLen += maxLen - len;
			}
			wordNum++;
		}
		free(buf[i]);
	}
	if(*word) puts(word);
}	


void main(argc, argv)
char *argv[];
{	FILE *in;
	int i;
	columns = 80; /* FOR NOW */
	for(i=0; i<sizeof(spaces); i++) spaces[i] = ' ';

	if(argc == 1) c(stdin);
	else for(i=1; i<argc; i++)
	{	if((in=fopen(argv[i], "r")) == NULL) perror(argv[i]);
		else
		{	c(in);
			fclose(in);
		}
	}
}