/********************************************
files.c
libmawk changes (C) 2009-2013, Tibor 'Igor2' Palinkas;
based on mawk code coming with the below copyright:
copyright 1991-94. Michael D. Brennan
This is a source file for mawk, an implementation of
the AWK programming language.
Mawk is distributed without warranty under the terms of
the GNU General Public License, version 2, 1991.
********************************************/
#include "conf.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "mawk.h"
#include "files.h"
#include "memory.h"
#include "fin.h"
#include "vio.h"
#ifdef PATH_MAX
#define PATH_BUFF_SIZE PATH_MAX
#else
#define PATH_BUFF_SIZE 1024
#endif
/* mawk_find a file on file_list */
FILE_NODE *mawk_file_find(mawk_state_t *MAWK, mawk_string_t *sval, int type, int create)
{
register FILE_NODE *p = MAWK->file_list;
FILE_NODE *q = (FILE_NODE *) 0;
const char *name_orig = sval->str;
const char *name;
char name_buff[PATH_BUFF_SIZE];
mawk_vio_t *vf;
if (MAWK->file_name_rewrite != NULL)
name = MAWK->file_name_rewrite(name_orig, name_buff, sizeof(name_buff), type);
else
name = name_orig;
if (name == NULL)
goto out_failure;
/* rewrite - to be /dev/stdin so we never have 2 names for the same thing */
if ((name[0] == '-') && (name[1] == '\0'))
name = "/dev/stdin";
while (1) {
if (!p) {
if (!create)
goto nocreate_failure;
/* open a new one */
p = MAWK_ZMALLOC(MAWK, FILE_NODE);
p->vf = NULL;
p->fin = NULL;
switch (p->type = type) {
case F_TRUNC:
p->vf = mawk_vio_open(MAWK, name, MAWK_VIO_O_TRUNC);
if (p->vf == NULL)
goto out_failure;
p->vf->refco = 1;
break;
case F_APPEND:
p->vf = mawk_vio_open(MAWK, name, MAWK_VIO_O_APPEND);
if (p->vf == NULL)
goto out_failure;
p->vf->refco = 1;
break;
case F_IN:
if ((p->fin = (PTR) mawk_fin_alloc(MAWK, p)) == NULL) {
mawk_zfree(MAWK, p, sizeof(FILE_NODE));
return (PTR) 0;
}
p->vf = mawk_vio_open(MAWK, name, MAWK_VIO_I);
if (p->vf == NULL) {
mawk_fin_free(MAWK, p->fin);
mawk_zfree(MAWK, p, sizeof(FILE_NODE));
return (PTR) 0;
}
p->vf->refco = 1;
break;
case PIPE_OUT:
case PIPE_IN:
vf = mawk_vio_open_pipe(MAWK, name, type);
if (vf == NULL) {
if (type == PIPE_OUT) {
goto out_failure;
}
else {
mawk_zfree(MAWK, p, sizeof(FILE_NODE));
return (PTR) 0;
}
}
if (type == PIPE_IN)
p->fin = mawk_fin_alloc(MAWK, p);
p->vf = vf;
p->vf->refco = 1;
break;
#ifdef DEBUG
default:
mawk_bozo(MAWK, "bad file type");
#endif
}
/* successful open */
if (name != name_orig) {
/* name has been rewritten, have to alloc a new string */
p->name = mawk_new_STRING(MAWK, name);
}
else
p->name = sval;
sval->ref_cnt++;
break; /* while loop */
}
/* search is by name and type */
if ((strcmp(name, p->name->str) == 0 && ((p->type == type) ||
/* no distinction between F_APPEND and F_TRUNC here */
(p->type >= F_APPEND && type >= F_APPEND))))
{
/* found */
if (!q) /*at front of list */
return p;
/* delete from list for move to front */
q->link = p->link;
break; /* while loop */
}
q = p;
p = p->link;
} /* end while loop */
/* put p at the front of the list */
p->link = MAWK->file_list;
return (MAWK->file_list = p);
out_failure:;
mawk_errmsg(MAWK, errno, "cannot open \"%s\" for output", name);
mawk_exitval(MAWK, 2, NULL);
return NULL;
nocreate_failure:;
mawk_errmsg(MAWK, errno, "cannot open \"%s\" - it does not exist in current context and should not be created now", name);
mawk_exitval(MAWK, 2, NULL);
return NULL;
}
FILE_NODE *mawk_file_find_(mawk_state_t *MAWK, const char *name, int type, int create)
{
FILE_NODE *f;
mawk_string_t *sval = mawk_new_STRING(MAWK, name);
f = mawk_file_find(MAWK, sval, type, create);
free_STRING(sval);
return f;
}
static int mawk_file_close_lowlev(mawk_state_t *MAWK, FILE_NODE *p)
{
if (p->fin != NULL) {
mawk_fin_free(MAWK, p->fin);
p->fin = NULL;
}
if (p->vf != NULL) {
p->vf->refco--;
if (p->vf->refco == 0)
mawk_vio_close(MAWK, p->vf);
p->vf = NULL;
}
if (p->name != NULL) {
free_STRING(p->name);
}
return 0;
}
/* Close a file and delete it's node from the file_list.
Walk the whole list, in case a name has two nodes,
e.g. < "/dev/tty" and > "/dev/tty"
*/
int mawk_file_close(mawk_state_t *MAWK, mawk_string_t *sval)
{
FILE_NODE dummy;
register FILE_NODE *p;
FILE_NODE *q = &dummy; /* trails p */
FILE_NODE *hold;
char *name = sval->str;
int retval = -1;
dummy.link = p = MAWK->file_list;
while (p) {
if (strcmp(name, p->name->str) == 0) {
/* found */
retval = mawk_file_close_lowlev(MAWK, p);
hold = p;
q->link = p = p->link;
MAWK_ZFREE(MAWK, hold);
}
else {
q = p;
p = p->link;
}
}
MAWK->file_list = dummy.link;
return retval;
}
/* Close a file_node and delete it's node from the file_list. */
int mawk_file_close_(mawk_state_t *MAWK, FILE_NODE *f)
{
FILE_NODE dummy;
register FILE_NODE *p;
FILE_NODE *q = &dummy; /* trails p */
FILE_NODE *hold;
int retval = -1;
dummy.link = p = MAWK->file_list;
while (p) {
if (p == f) {
/* found */
retval = mawk_file_close_lowlev(MAWK, p);
hold = p;
q->link = p = p->link;
MAWK_ZFREE(MAWK, hold);
}
else {
q = p;
p = p->link;
}
}
MAWK->file_list = dummy.link;
return retval;
}
/*
mawk_find an output file with name == sval and fflush it
*/
int mawk_file_flush(mawk_state_t *MAWK, mawk_string_t *sval)
{
int ret = -1;
register FILE_NODE *p = MAWK->file_list;
unsigned len = sval->len;
char *str = sval->str;
if (len == 0) {
/* for consistency with gawk */
mawk_flush_all_output(MAWK);
return 0;
}
while (p) {
if (IS_OUTPUT(p->type) && len == p->name->len && strcmp(str, p->name->str) == 0) {
ret = 0;
mawk_vio_flush(MAWK, p->vf);
/* it's possible for a command and a file to have the same
name -- so keep looking */
}
p = p->link;
}
return ret;
}
void mawk_flush_all_output(mawk_state_t * MAWK)
{
FILE_NODE *p;
for (p = MAWK->file_list; p; p = p->link)
if (IS_OUTPUT(p->type))
mawk_vio_flush(MAWK, p->vf);
}
FILE_NODE *mawk_file_register_nofin(mawk_state_t *MAWK, const char *name, int type, mawk_vio_t *vf)
{
FILE_NODE *p;
p = MAWK_ZMALLOC(MAWK, FILE_NODE);
p->link = MAWK->file_list;
p->type = type;
p->name = mawk_new_STRING(MAWK, name);
p->vf = vf;
p->fin = NULL;
if (vf != NULL)
vf->refco++;
MAWK->file_list = p;
/* update hardwireds */
if (strcmp(name, "/dev/stdin") == 0)
MAWK->fnode_stdin = p;
else if (strcmp(name, "/dev/stdout") == 0)
MAWK->fnode_stdout = p;
else if (strcmp(name, "/dev/stderr") == 0)
MAWK->fnode_stderr = p;
return p;
}
FILE_NODE *mawk_file_register(mawk_state_t *MAWK, const char *name, int type, mawk_vio_t *vf)
{
FILE_NODE *fn;
fn = mawk_file_register_nofin(MAWK, name, type, vf);
if ((type == F_IN) || (type == PIPE_IN))
fn->fin = mawk_fin_alloc(MAWK, fn);
return fn;
}
void mawk_file_uninit(mawk_state_t * MAWK)
{
FILE_NODE *p, *next;
for (p = MAWK->file_list; p; p = next) {
next = p->link;
mawk_file_close_lowlev(MAWK, p);
MAWK_ZFREE(MAWK, p);
}
}