Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon. Entire thread

incomplete text editor in C

Name: Anonymous 2008-04-26 6:12

Supports buffers, with a few lines added supports regex, and pretty much any text manipulation as long as you provide the function to manipulate the text in some way.
It's in standard C so should compile everywhere.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>

#define MAXBUF    64

typedef struct _list {
    char buf[BUFSIZ];    /* text of line */
    size_t n;        /* sizeof text */
    struct _list *next;    /* next line */
} list;



typedef struct {

    list *lines;            /* actual lines in the file */
    size_t nlines;            /* number of lines in the file */
    FILE *stream;            /* stream we edit, if a stream is present */
    char name[FILENAME_MAX+1];    /* name of stream, or anonymous */

#define FBUF_A 0
#define FBUF_R 1
#define FBUF_W 2
    int mode;            /* read/write/anon buf */

    size_t curline;            /* current line we operate on */

} filebuf;

struct foo {

    filebuf *fbuf[MAXBUF];
    size_t nbuf;
    size_t curbuf;

};

typedef int cmdfunc(const char *, struct foo *);


#define funcname(x) (CMD_##x)

#define getname(x) ((x)->name[0] == 0 ? "[noname]" : (const char *)(x)->name)
void setname(filebuf *, const char *);
filebuf *newbuf(const char *);
int addbuf(struct foo *, const char *);
void killbuf(filebuf *);
void rembuf(struct foo *, size_t);
void destroylist(list *);
void destroyfiles(struct foo *);

int cmd_exec(const char *, struct foo *);
int cmd_result(FILE *, int);
void getword(char *, const char *);
int changebuf(struct foo *, size_t);
int changeline(filebuf *, size_t);
void printbufname(const struct foo *, size_t);

/* CMD commands */

cmdfunc funcname(ls);
cmdfunc funcname(b);

int main(int argc, char **argv) {

    size_t i = 0;
    struct foo files;
    int ret;
    char buf[BUFSIZ];
    char *p, *s;
    const char *prompt = "> ";

    if(argc < 2)
        return 0;

    memset(&files, 0, sizeof files);

    for(i = 1; i < (size_t)argc; i++) {
        ret = addbuf(&files, argv[i]);
        if(ret == -1)
            perror(argv[i]);
        else if(ret == 1)
            fprintf(stderr, "too many buffers. (%lu)\n", (unsigned long)MAXBUF);
        else printf("opened %s\n", argv[i][0] == 0 ? "[noname]" : argv[i]);

    }

    printf("%s", prompt);
    fflush(stdout);

    while(fgets(buf, sizeof buf, stdin) != NULL) {

        ret = 0;

        for(p = buf;  *p; p = s + 1) {
            s = strpbrk(p, ";\n");
            if(s != NULL)
                *s = 0;

            if((ret = cmd_exec(p, &files)) != 0)
                fprintf(stderr, "%lu %s: ", (unsigned long)files.curbuf, getname(files.fbuf[files.curbuf]));
           
            cmd_result(stderr, ret);
            printf("%s", prompt);
            fflush(stdout);
        }
    }
   
    destroyfiles(&files);
    putchar('\n');

    return 0;
}

int funcname(ls)(const char *str, struct foo *files) {

    size_t n;

    (void)str;

    for(n = 0; n < files->nbuf; n++)
        printbufname(files, n);

    return 0;
}


int funcname(b)(const char *str, struct foo *files) {

    const char *p;

    if(*str == 0) {
        printbufname(files, files->curbuf);
        return 0;
    }

    for(p = str; *p && isdigit((unsigned char)*p); p++)
        ;
    if(*p != 0 && !isspace((unsigned char)*p)) {
        /*
           EDIT HERE
           return bad buf id
         */
        return -1;
    }

    return    changebuf(files, atoi(str));
}

void printbufname(const struct foo *files, size_t id) {

    printf("%lu %s\n", (unsigned long)id, getname(files->fbuf[id]));
}


int changeline(filebuf *file, size_t id) {

    if(id >= file->nlines)
        return -1;

    file->curline = id;
    return 0;
}

int cmd_result(FILE *out , int ret) {

    if(ret != 0)
        fprintf(out, "some error\n");

    return 0;

}

int changebuf(struct foo *files, size_t id) {

    if(id < files->nbuf) {
        files->curbuf = id;
        return 0;
    }
    /* EDIT HERE
       return BADBUFID
       */
    else return -1;

}

void getword(char *buf, const char *str) {
   
    char *p;

    p = strchr(str, ' ');
    if(p == NULL)
        strcpy(buf, str);
    else {
        strncpy(buf, str, p - str);
        buf[p - str] = 0;
    }


}

int cmd_exec(const char *str, struct foo *files) {

    char buf[BUFSIZ];
    size_t n;

    /* EDIT HERE */

    struct {
        const char *cmd;
        cmdfunc *f;
    } commands[] = {
        { "ls", funcname(ls) },
        { "b", funcname(b) }
    };

    getword(buf, str);

    for(n = 0; n < sizeof commands / sizeof commands[0]; n++)
        if(strcmp(buf, commands[n].cmd) == 0)
            return commands[n].f(str + strlen(buf) + 1, files);

    /* EDIT HERE
       return BAD COMMAND
       */

    return -1;

}

void destroyfiles(struct foo *files) {
   
    size_t i;
   
    for(i = files->nbuf - 1; i != (size_t)-1; i--) {
#ifdef TED_DEBUG
        printf("filename: '%s'\n", getname(files->fbuf[i]));
        printf("mode opened: %d\n", files->fbuf[i]->mode);
        printf("%p\n", (void *)files->fbuf[i]->lines);
#endif
        rembuf(files, i);

    }

}
void setname(filebuf *file, const char *name) {

    memset(file->name, 0, sizeof file->name);
    if(name != NULL)
        strncpy(file->name, name, sizeof file->name - 1);
}

void rembuf(struct foo *ptr, size_t n) {

    if(n > ptr->nbuf)
        return;

    killbuf(ptr->fbuf[n]);

    if(n != ptr->nbuf)
        memmove(&ptr->fbuf[n], &ptr->fbuf[n + 1],
                (ptr->nbuf - n) * sizeof ptr->nbuf);
    ptr->nbuf--;


}


void killbuf(filebuf *file) {

    if(file->stream != NULL) {
        fflush(file->stream);
        fclose(file->stream);
    }

    destroylist(file->lines);

}

void destroylist(list *lines) {
    list *p = NULL;

    if(lines)
        p = lines->next;
    free(lines);

    while(p != NULL) {
        lines = p->next;
        free(p);
        p = lines;
    }

}

filebuf *newbuf(const char *path) {

    filebuf *ret;
    FILE *fp;
    int mode;
    char buf[BUFSIZ];
    list **p;

    if(path != NULL && *path != 0) {

        fp = fopen(path, "r+");
        mode = FBUF_W;
        if(fp == NULL) {
            fp = fopen(path, "r");
            mode = FBUF_R;
        }
        if(fp == NULL) {
            fp = fopen(path, "w");
            mode = FBUF_W;
        }
   
        if(fp == NULL)
            return NULL;
   
        ret = malloc(sizeof *ret);
        if(ret == NULL) {
            fclose(fp);
            return NULL;
        }
    }
    else {
        fp = NULL;
        mode = FBUF_A;
        ret = malloc(sizeof *ret);
        if(ret == NULL)
            return NULL;
    }

    memset(ret, 0, sizeof *ret);

    ret->mode = mode;
    ret->stream = fp;


    p = &ret->lines;

    /* in case of anonbuf
       curline = 0, nlines = 0
       which is the same with opening an empty file
       !FIX!
       */

    while(fp && fgets(buf, sizeof buf, fp) != NULL) {

        *p = malloc(sizeof **p);

        if(*p == NULL) {
            free(ret);
            fclose(fp);
            return NULL;
        }
       
        (*p)->next = NULL;
        strcpy((*p)->buf, buf);
        (*p)->n = strlen(buf);
        p = &(*p)->next;
        ret->nlines++;
    }

    return ret;

}

int addbuf(struct foo *files, const char *path) {


    if(files->nbuf != MAXBUF) {
        files->fbuf[files->nbuf] = newbuf(path);
        if(files->fbuf[files->nbuf] == NULL)
            return -1;
        setname(files->fbuf[files->nbuf], path);
        files->nbuf++;
        return 0;
    }
    return 1;
}

Name: Anonymous 2008-04-26 7:33

>>3
Why did you remove the space between return and the function?
Anyway, that's correct. atoi() will not produce unpredictable results because of the checks before on str with isdigit.

Newer Posts
Don't change these.
Name: Email:
Entire Thread Thread List