A fairly complete implementation to provide another perspective on a seemingly simple program.
cat clone
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BLANK_LINES 1
#define ALL_LINES 2
static char **parse_options(char *argv[]);
static void read_file(FILE *in);
static void version(void);
static void help(void);
static int control; /* Show control characters as ^ */
static int show_count; /* Show line count */
static int show_end; /* End lines with $ */
static int show_tab; /* Show tabs as ^I */
static int squeeze; /* Change multiple blank lines into one */
static int line = 1;
int main(int argc, char *argv[])
{
argv = parse_options(argv);
if (*argv == NULL) {
read_file(stdin);
} else {
FILE *in;
for (; *argv != NULL; *++argv) {
if (**argv == '-') {
in = stdin;
} else {
if ((in = fopen(*argv, "r")) == NULL) {
continue;
}
}
read_file(in);
}
}
return 0;
}
char **parse_options(char *argv[])
{
while (*++argv != NULL && **argv == '-') {
/* Terminating options */
if (strcmp(*argv, "--version") == 0) {
version();
}
if (strcmp(*argv, "--help") == 0) {
help();
}
/* Behavioral switches */
while (*++(*argv) != '\0') {
switch (**argv) {
case 'b': show_count = BLANK_LINES; break;
case 'e': control = show_end = 1; break;
case 'n': show_count = ALL_LINES; break;
case 's': squeeze = 1; break;
case 't': control = show_tab = 1; break;
case 'u': /* No-op for Unix compatibility */ break;
case 'v': control = 1; break;
case 'A': control = show_end = show_tab = 1; break;
case 'E': show_end = 1; break;
case 'T': show_tab = 1; break;
default: /* Ignore unrecognized switches */ break;
}
}
}
return argv;
}
void read_file(FILE *in)
{
int ch, last;
for (last = '\n'; (ch = getc(in)) != EOF; last = ch) {
if (last == '\n') {
line_count:
if (show_count == ALL_LINES) {
printf("%-5d", line++);
} else if (show_count == BLANK_LINES && ch != '\n') {
printf("%-5d", line++);
}
if (squeeze && ch == '\n') {
if (show_end) {
putchar('$');
}
putchar('\n');
/* Ignore extra empty lines */
while ((ch = getc(in)) != EOF && ch == '\n') {
/* Do nothing */
}
if (ch == EOF) {
break;
} else {
goto line_count; /* Print line # first */
}
}
}
if (show_tab && ch == '\t') {
printf("^I");
} else if (control && iscntrl(ch)) {
putchar('^');
} else if (show_end && ch == '\n') {
printf("$\n");
} else {
putchar(ch);
}
}
}
void version(void)
{
printf("cat clone v1.0\n");
exit(EXIT_SUCCESS);
}
void help(void)
{
printf("cat [-benstuvAET] [--help] [--version] [file...]\n");
exit(EXIT_SUCCESS);
}
Be a part of the DaniWeb community
We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.