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.
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;
}