See the previous iteration: A trivial command line utility for trimming whitespace from lines in C A trivial command line utility for trimming whitespace from lines in C
Note: see the next iteration at A trivial command line utility for trimming whitespace from lines in C - follow-up 2 A trivial command line utility for trimming whitespace from lines in C - follow-up 2
See the previous iteration: A trivial command line utility for trimming whitespace from lines in C
Note: see the next iteration at A trivial command line utility for trimming whitespace from lines in C - follow-up 2
See the previous iteration: A trivial command line utility for trimming whitespace from lines in C
Note: see the next iteration at A trivial command line utility for trimming whitespace from lines in C - follow-up 2
Note: see the next iteration at A trivial command line utility for trimming whitespace from lines in C - follow-up 2
Note: see the next iteration at A trivial command line utility for trimming whitespace from lines in C - follow-up 2
A trivial command line utility for trimming whitespace from lines in C - follow-up
See the previous iteration: A trivial command line utility for trimming whitespace from lines in C
Now my code looks like this:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define HELP_MESSAGE "Usage: trim [-h] [-v] [FILE1, [FILE2, [...]]]\n" \
" -h Print the help message and exit.\n" \
" -v Print the version message and exit.\n" \
" If no files specified, reads from standard input.\n"
#define VERSION_MESSAGE "trim 1.61\n" \
"By Rodion \"rodde\" Efremov 07.04.2015 Helsinki\n"
#define HELP_FLAG "-h"
#define VERSION_FLAG "-v"
#define NEWLINE_CHAR '\n'
/*******************************************************************************
* This routine removes all leading and trailing whitespace from a string, *
* doing that in-place. ( *
********************************************************************************/
static char* trim_inplace(char* start)
{
char* end;
for (end = &start[strlen(start) - 1]; isspace(*end); --end)
{
*end = '0円';
}
while (isspace(*start))
{
++start;
}
return start;
}
/*******************************************************************************
* Implements a (singly) linked list node holding a single character. *
*******************************************************************************/
typedef struct char_node_t {
char c;
struct char_node_t* p_next;
} char_node_t;
/*******************************************************************************
* Extracts a string from a linked list of characters, and frees the memory of *
* the list holding the characters. *
*******************************************************************************/
static char* build_string(char_node_t* p_head, size_t length)
{
char* string = (char*) malloc(sizeof(char) * length);
size_t i = 0;
char_node_t* p_node;
while (p_head)
{
string[i++] = p_head->c;
p_node = p_head;
p_head = p_head->p_next;
free(p_node);
}
string[i] = '0円';
return string;
}
/*******************************************************************************
* Gets a line from file of any feasible length (fitting into the RAM). *
* Returns NULL if file is exhausted. *
*******************************************************************************/
static char* my_getline(FILE* file)
{
char_node_t* p_head = NULL;
char_node_t* p_tail = NULL;
char_node_t* p_tmp;
size_t string_length = 0;
char current_character;
if (feof(file))
{
return NULL;
}
for(;;)
{
current_character = fgetc(file);
if (current_character == NEWLINE_CHAR || current_character == EOF)
{
if (string_length == 0)
{
// Otherwise a zero-length string will leak and produce a
// superfluous empty line after the end of a file.
return NULL;
}
// +1 for the NULL terminator.
return build_string(p_head, string_length + 1);
}
if (string_length == 0)
{
// Initialize list.
p_head = p_tail = (char_node_t*) malloc(sizeof(char_node_t));
p_head->c = current_character;
p_head->p_next = p_tail->p_next = NULL;
}
else
{
// Append one character node to the list.
p_tmp = (char_node_t*) malloc(sizeof(char_node_t));
p_tmp->c = current_character;
p_tmp->p_next = NULL;
p_tail->p_next = p_tmp;
p_tail = p_tmp;
}
++string_length;
}
}
/*******************************************************************************
* Processes a file. *
*******************************************************************************/
static void process_file(FILE* file)
{
char* line;
while ((line = my_getline(file)))
{
puts(trim_inplace(line));
free(line);
}
fclose(file);
}
/*******************************************************************************
* Prints the help message and exits. *
*******************************************************************************/
static void print_help()
{
printf(HELP_MESSAGE);
exit(EXIT_SUCCESS);
}
/*******************************************************************************
* Prints the version string. *
*******************************************************************************/
static void print_version()
{
printf(VERSION_MESSAGE);
exit(EXIT_SUCCESS);
}
/*******************************************************************************
* Checks the flags. *
*******************************************************************************/
static void check_flags(int argc, char** argv)
{
size_t i;
for (i = 1; i < argc; ++i)
{
if (strcmp(argv[i], HELP_FLAG) == 0)
{
print_help();
}
else if (strcmp(argv[i], VERSION_FLAG) == 0)
{
print_version();
}
}
}
/*******************************************************************************
* The entry point for a trivial line trimmer. *
*******************************************************************************/
int main(int argc, char** argv)
{
size_t i;
FILE* file;
check_flags(argc, argv);
if (argc < 2)
{
process_file(stdin);
return EXIT_SUCCESS;
}
for (i = 1; i < argc; ++i)
{
file = fopen(argv[i], "r");
if (!file)
{
perror("Error opening a file");
return (EXIT_FAILURE);
}
process_file(file);
}
}
I have fixed the following issues:
- File handles are closed as soon as possible.
trim_inplace
simplified.- No superfluous
const
s. - The program should handle lines of arbitrary length.
- No
return EXIT_SUCCESS
at the end ofmain
.
Is there anything else to improve?