ex_slowcat.c
#include "ex_utils.h"
#include <timer_q.h>
#include <getopt.h>
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#define EX_SLOWCAT_WRITE_BYTES 80
#define EX_SLOWCAT_WRITE_WAIT_SEC 1
#define EX_SLOWCAT_WRITE_WAIT_USEC 0
typedef struct ex_slowcat_vars
{
unsigned int opt_write_bytes;
unsigned int opt_write_wait_sec;
unsigned int opt_write_wait_usec;
int argc;
char **argv;
Vstr_base *str1;
int arg_count;
int fcntl_flags;
Timer_q_base *base;
Timer_q_node *node;
int fd;
unsigned int finished_reading_data : 1;
unsigned int finished_reading_file : 1;
} ex_slowcat_vars;
#undef MIN
#define MIN(x, y, z) ((((z) (x)) < ((z) (y))) ? ((z) (x)) : ((z) (y)))
static void ex_slowcat_timer_func(int type, void *data)
{
ex_slowcat_vars *v = data;
struct timeval s_tv;
int fin_data = v->finished_reading_data;
size_t len = 0;
if (type == TIMER_Q_TYPE_CALL_DEL)
return;
if (!v->finished_reading_data && (v->str1->len < v->opt_write_bytes))
{
if (!v->argc && !v->arg_count)
{
v->finished_reading_file = FALSE;
v->fd = 0;
}
else
{
if (v->finished_reading_file)
{
assert(v->arg_count < v->argc);
v->finished_reading_file = FALSE;
v->fd = open(v->argv[v->arg_count], O_RDONLY | O_LARGEFILE | O_NOCTTY);
if (v->fd == -1)
err(EXIT_FAILURE, "open(%s)", v->argv[v->arg_count]);
++v->arg_count;
if (vstr_sc_mmap_fd(v->str1, v->str1->len, v->fd, 0, 0, NULL))
{
if (v->arg_count >= v->argc)
v->finished_reading_data = TRUE;
v->finished_reading_file = TRUE;
}
else
io_fd_set_o_nonblock(v->fd);
}
}
if (!v->finished_reading_file)
do
{
int state = io_get(v->str1, v->fd);
if (state == IO_EOF)
{
if (close(v->fd) == -1)
err(EXIT_FAILURE, "close");
if (v->arg_count >= v->argc)
v->finished_reading_data = TRUE;
v->finished_reading_file = TRUE;
}
} while (v->opt_write_bytes > v->str1->len);
}
if (!fin_data && v->finished_reading_data)
{
if (v->str1->len)
if (fcntl(1, F_SETFL, v->fcntl_flags & ~O_NONBLOCK) == -1)
err(EXIT_FAILURE, "fcntl(SET BLOCK)");
}
len = MIN(v->opt_write_bytes, v->str1->len, size_t);
if (!vstr_sc_write_fd(v->str1, 1, len, STDOUT_FILENO, NULL))
{
if (errno != EAGAIN)
err(EXIT_FAILURE, "write");
if (v->str1->len > EX_MAX_W_DATA_INCORE)
io_block(-1, STDOUT_FILENO);
}
if (v->finished_reading_data && !v->str1->len)
return;
if (type == TIMER_Q_TYPE_CALL_RUN_ALL)
return;
gettimeofday(&s_tv, NULL);
TIMER_Q_TIMEVAL_ADD_SECS(&s_tv, v->opt_write_wait_sec, v->opt_write_wait_usec);
v->node = timer_q_add_node(v->base, v, &s_tv, TIMER_Q_FLAG_NODE_DEFAULT);
if (!v->node)
errno = ENOMEM, err(EXIT_FAILURE, "timer_q_add_node");
}
static int ex_slowcat_init_cmd_line(ex_slowcat_vars *v, int argc, char *argv[])
{
char optchar = 0;
const char *program_name = "talker";
struct option long_options[] =
{
{"bytes", required_argument, NULL, 'b'},
{"help", no_argument, NULL, 'h'},
{"seconds", required_argument, NULL, 's'},
{"useconds", required_argument, NULL, 'u'},
{"version", no_argument, NULL, 'V'},
{NULL, 0, NULL, 0}
};
FILE *help_stdout = NULL;
help_stdout = stdout;
if (argv[0])
{
if ((program_name = strrchr(argv[0], '/')))
++program_name;
else
program_name = argv[0];
}
while ((optchar = getopt_long(argc, argv, "b:hs:u:vHV",
long_options, NULL)) != EOF)
switch (optchar)
{
case 'b':
v->opt_write_bytes = atoi(optarg);
break;
case '?':
fprintf(stderr, " The option -- %c -- is not valid.\n", optchar);
help_stdout = stderr;
case 'H':
case 'h':
fprintf(help_stdout, "\n Format: %s [-bhsuvHV] [files]\n"
" --bytes -b - Number of bytes to write at once.\n"
" --help -h - Print this message.\n"
" --seconds -s - Number of seconds to wait between write calls.\n"
" --useconds -u - Number of micro seconds to wait between write calls.\n"
" --version -v - Print the version string.\n",
program_name);
if (optchar == '?')
exit (EXIT_FAILURE);
else
exit (EXIT_SUCCESS);
case 's':
v->opt_write_wait_sec = atoi(optarg);
break;
case 'u':
v->opt_write_wait_usec = atoi(optarg);
break;
case 'v':
case 'V':
printf(" %s is version 0.1, compiled on -- "
__DATE__ " -- at -- " __TIME__" --.\n",
program_name);
exit (EXIT_SUCCESS);
}
return (optind);
}
int main(int argc, char *argv[])
{
ex_slowcat_vars v;
struct timeval s_tv;
const struct timeval *tv = NULL;
v.opt_write_bytes = EX_SLOWCAT_WRITE_BYTES;
v.opt_write_wait_sec = EX_SLOWCAT_WRITE_WAIT_SEC;
v.opt_write_wait_usec = EX_SLOWCAT_WRITE_WAIT_USEC;
v.argc = argc;
v.argv = argv;
v.str1 = NULL;
v.arg_count = 0;
v.fcntl_flags = 0;
v.base = NULL;
v.node = NULL;
v.finished_reading_data = FALSE;
v.finished_reading_file = TRUE;
if (!vstr_init())
errno = ENOMEM, err(EXIT_FAILURE, "vstr_init");
ex_slowcat_init_cmd_line(&v, argc, argv);
v.argc -= optind;
v.argv += optind;
v.base = timer_q_add_base(ex_slowcat_timer_func, TIMER_Q_FLAG_BASE_DEFAULT);
if (!v.base)
errno = ENOMEM, err(EXIT_FAILURE, "timer_q_add_base");
gettimeofday(&s_tv, NULL);
TIMER_Q_TIMEVAL_ADD_SECS(&s_tv, 1, 500000);
v.node = timer_q_add_node(v.base, &v, &s_tv, TIMER_Q_FLAG_NODE_DEFAULT);
if (!v.node)
errno = ENOMEM, err(EXIT_FAILURE, "timer_q_add_node");
v.str1 = vstr_make_base(NULL);
if (!v.str1)
errno = ENOMEM, err(EXIT_FAILURE, "vstr_make_base");
if ((v.fcntl_flags = fcntl(1, F_GETFL)) == -1)
err(EXIT_FAILURE, "fcntl(GET NONBLOCK)");
if (!(v.fcntl_flags & O_NONBLOCK) &&
(fcntl(1, F_SETFL, v.fcntl_flags | O_NONBLOCK) == -1))
err(EXIT_FAILURE, "fcntl(SET NONBLOCK)");
while ((tv = timer_q_first_timeval()))
{
long wait_period = 0;
gettimeofday(&s_tv, NULL);
wait_period = timer_q_timeval_diff_usecs(tv, &s_tv);
if (wait_period > 0)
usleep(wait_period);
gettimeofday(&s_tv, NULL);
timer_q_run_norm(&s_tv);
}
timer_q_del_base(v.base);
vstr_free_base(v.str1);
vstr_exit();
exit (EXIT_SUCCESS);
}