root/stream.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. save_err
  2. get_stream
  3. add_stream
  4. del_stream
  5. cmdStream
  6. stream_init
  7. streamOpen
  8. not_open
  9. streamClose
  10. streamGets
  11. streamPuts
  12. streamTell
  13. streamEof
  14. streamErr
  15. streamName
  16. streamSeek

/* stream commands for tcl */
#include <stdio.h>
#include <tcl.h>

#define STATIC

int streamOpen(),
    streamClose(),
    streamGets(),
    streamPuts(),
    streamEof(),
    streamName(),
    streamErr(),
    streamTell(),
    streamSeek();

static struct subcmd {
        int (*func)();
        char *name;
        int min;
        int max;
        char *args;
} commands[] = {
        { streamOpen, "open", 2, 2, "name mode" },
        { streamClose, "close", 0, 0, "" },
        { streamGets, "gets", 0, 0, "" },
        { streamPuts, "puts", 1, 1, "line" },
        { streamEof, "eof", 0, 0, "" },
        { streamErr, "error", 0, 0, "" },
        { streamName, "name", 0, 0, "" },
        { streamTell, "tell", 0, 0, "" },
        { streamSeek, "seek", 1, 2, "offset [whence]" },
};

static struct stream {
        struct stream *next;
        char *name;
        char *filename;
        char *error;
        FILE *fp;
} *streams = NULL;

save_err(s)
struct stream *s;
{
        char *strerror();
        extern int errno;
        char *name;

        name = strerror(errno);
        if(!name)
                return;

        if(s->error) ckfree(s->error);
        s->error = 0;
        s->error = ckalloc(strlen(name)+1);
        strcpy(s->error, name);
}

STATIC struct stream *get_stream(name)
char *name;
{
        struct stream *s;

        for(s = streams; s; s = s->next)
                if(strcmp(name, s->name) == 0)
                        break;
        return s;
}

STATIC struct stream *add_stream(name, filename, fp)
char *name;
char *filename;
FILE *fp;
{
        struct stream *s;

        s = (struct stream *)ckalloc(sizeof(struct stream)
                + strlen(name) + 1
                + (filename ? (strlen(filename)+1) : 0) );

        s->name = (char *)&s[1];
        strcpy(s->name, name);
        if(filename) {
                s->filename = s->name + strlen(name) + 1;
                strcpy(s->filename, filename);
        } else
                s->filename = NULL;
        s->fp = fp;
        s->error = NULL;
        s->next = streams;
        streams = s;
}

STATIC del_stream(name)
char *name;
{
        struct stream *p, *q;

        p = streams;
        q = NULL;
        while(p) {
                if(strcmp(p->name, name) == 0) {
                        if(q)
                                q->next = p->next;
                        else
                                streams = p->next;
                        if(p->error) ckfree(p->error);
                        ckfree(p);
                        return 1;
                }
                q = p;
                p = p->next;
        }
        return 0;
}

STATIC cmdStream(cmdname, interp, argc, argv)
char *cmdname;
Tcl_Interp *interp;
int argc;
char **argv;
{
        struct subcmd *cmdv = commands;
        int cmdc = sizeof commands / sizeof *commands;

        char *handle, *action;

        char *err;
        char *name;
        char *args;

        err = "wrong # args in";
        action = "stream";
        name = "command";
        args = "args...";

        if(argc < 3)
                goto error;

        argv++; --argc;
        handle = *argv++; --argc;
        action = *argv++; --argc;

        while(cmdc > 0) {
                if(strcmp(action, cmdv->name) == 0) {
                        int result;

                        name = cmdv->name;
                        args = cmdv->args;
                        if(argc < cmdv->min
                           || (cmdv->max != -1 && argc > cmdv->max))
                                goto error;
                        result = (*cmdv->func)(interp, handle, argc, argv);
                        return result;
                }
                cmdv++;
                cmdc--;
        }
        err = "unknown subcommand";
error:
        sprintf(interp->result, "%s %s:  should be \"%.50s handle %s %s\"",
                err, action, cmdname, name, args);
        return TCL_ERROR;
}

stream_init(interp)
Tcl_Interp *interp;
{
        Tcl_CreateCommand(interp, "stream",
                cmdStream, (ClientData) "stream", NULL);
        add_stream("stdin", (char *)NULL, stdin);
        add_stream("stdout", (char *)NULL, stdout);
        add_stream("stderr", (char *)NULL, stderr);
}

STATIC int streamOpen(interp, handle, argc, argv)
Tcl_Interp *interp;
char *handle;
int argc;
char **argv;
{
        FILE *fp;

        if(!(fp = fopen(argv[0], argv[1]))) {
                char *strerror();
                extern int errno;
                char *s = strerror(errno);
                if(s)
                        sprintf(interp->result, "%s: %s", argv[0], s);
                else
                        Tcl_Return(interp, (char *)NULL, TCL_STATIC);
                return TCL_ERROR;
        }

        add_stream(handle, argv[0], fp);
        return TCL_OK;
}

STATIC not_open(interp, name)
Tcl_Interp *interp;
char *name;
{
        sprintf(interp->result,
                "%.50s is not an open stream", name);
}

STATIC int streamClose(interp, handle, argc, argv)
Tcl_Interp *interp;
char *handle;
int argc;
char **argv;
{
        struct stream *s = get_stream(handle);

        if(!s) {
                not_open(interp, handle);
                return TCL_ERROR;
        }

        fclose(s->fp);
        del_stream(handle);
        return TCL_OK;
}

STATIC int streamGets(interp, handle, argc, argv)
Tcl_Interp *interp;
char *handle;
int argc;
char **argv;
{
        struct stream *s = get_stream(handle);
        char *buffer = ckalloc(BUFSIZ);
        char *ptr, *strchr();

        if(!s) {
                not_open(interp, handle);
                ckfree(buffer);
                return TCL_ERROR;
        }

        if(fgets(buffer, BUFSIZ, s->fp)) {
                ptr = strchr(buffer, '\n');
                if(ptr) 
                        *ptr = 0;
                Tcl_Return(interp, buffer, TCL_VOLATILE);
        }
        else
        {
                Tcl_Return(interp, (char *)NULL, TCL_STATIC);
        }
        ckfree(buffer);
        return TCL_OK;
}

STATIC int streamPuts(interp, handle, argc, argv)
Tcl_Interp *interp;
char *handle;
int argc;
char **argv;
{
        struct stream *s = get_stream(handle);
        char buffer[BUFSIZ];

        if(!s) {
                not_open(interp, handle);
                return TCL_ERROR;
        }

        if(fputs(argv[0], s->fp) == EOF) save_err(s);
        if(putc('\n', s->fp) == EOF) save_err(s);

        return TCL_OK;
}

STATIC int streamTell(interp, handle, argc, argv)
Tcl_Interp *interp;
char *handle;
int argc;
char **argv;
{
        struct stream *s = get_stream(handle);
        long offset, ftell();

        if(!s) {
                not_open(interp, handle);
                return TCL_ERROR;
        }

        sprintf(interp->result, "%ld", offset = ftell(s->fp));
        if(offset == -1) save_err(s);
        return TCL_OK;
}

STATIC int streamEof(interp, handle, argc, argv)
Tcl_Interp *interp;
char *handle;
int argc;
char **argv;
{
        struct stream *s = get_stream(handle);

        if(!s) {
                not_open(interp, handle);
                return TCL_ERROR;
        }

        sprintf(interp->result, "%d", !!feof(s->fp));
        return TCL_OK;
}

STATIC int streamErr(interp, handle, argc, argv)
Tcl_Interp *interp;
char *handle;
int argc;
char **argv;
{
        struct stream *s = get_stream(handle);

        if(!s) {
                not_open(interp, handle);
                return TCL_ERROR;
        }

        if(ferror(s->fp) && s->error)
                Tcl_Return(interp, s->error, TCL_VOLATILE);
        else
                Tcl_Return(interp, (char *)NULL, TCL_STATIC);

        return TCL_OK;
}

STATIC int streamName(interp, handle, argc, argv)
Tcl_Interp *interp;
char *handle;
int argc;
char **argv;
{
        struct stream *s = get_stream(handle);

        if(!s) {
                not_open(interp, handle);
                return TCL_ERROR;
        }

        if(s->filename)
                Tcl_Return(interp, s->filename, TCL_VOLATILE);
        else
                Tcl_Return(interp, (char *)NULL, TCL_STATIC);

        return TCL_OK;
}

STATIC int streamSeek(interp, handle, argc, argv)
Tcl_Interp *interp;
char *handle;
int argc;
char **argv;
{
        struct stream *s = get_stream(handle);
        int whence;
        long offset, fseek();
        long strtol();
        char *endptr;

        if(!s) {
                not_open(interp, handle);
                return TCL_ERROR;
        }

        if(argc > 1) whence = atoi(argv[1]);
        else whence = 0;

        offset = strtol(argv[0], &endptr, 0);

        offset = fseek(s->fp, offset, whence);
        sprintf(interp->result, "%ld", offset);
        if(offset == -1) save_err(s);

        return TCL_OK;
}

/* [<][>][^][v][top][bottom][index][help] */