Code:
// ed.c
#include "list.h"
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <stdlib.h>
#define PATH_MAX 2000
typedef struct EdFile
{
List lines;
char *fname;
} EdFile;
/*
r [file] Read lines from a file
w [file] Write all the lines to a file
p [number, number] Print lines from number to number inclusive
q Quit
d [number, number Delete lines from number to number inclusive
a [number] Insert lines (from the user) at number
*/
const char *sep = " \t,";
void CleanUp(EdFile *file)
{
ListDeleteAll(&file->lines);
free(file->fname);
file->fname = 0;
}
char *GetLine(char *buffer, size_t size, FILE *f)
{
char *p;
size_t len;
p = fgets(buffer, (int)size, f);
if (p)
{
len = strlen(buffer);
if (buffer[len-1] == '\n')
{
buffer[len-1] = 0;
}
}
return p;
}
int GetFileNameOptional(char *buffer, char *fname, size_t len)
{
char *ptr = strtok(buffer+1, sep);
if (ptr != NULL && strlen(ptr) <= len)
{
strcpy(fname, ptr);
return 1;
}
return 0;
}
int GetFileName(char *buffer, char *fname, size_t len)
{
if (GetFileNameOptional(buffer, fname, len) > 0)
{
return 1;
}
printf("No filename given\n");
return 0;
}
int ArgToNum(const char *arg, int *num)
{
char *end;
if ((*num = strtol(arg, &end, 10)) == 0 || *end && !strchr(sep, *end))
{
printf("Invalid number (%s)\n", arg);
return 0;
}
return 1;
}
int GetNumArg(char *buffer, int *num1)
{
char *ptr;
ptr = strtok(buffer+1, sep);
if (ptr == NULL) return 0;
if (ArgToNum(ptr, num1))
{
return 1;
}
return 0;
}
int GetNumArgs(char *buffer, int *num1, int *num2)
{
char *ptr;
ptr = strtok(buffer+1, sep);
if (ptr == NULL || !ArgToNum(ptr, num1))
{
return 0;
}
ptr = strtok(NULL, sep);
if (ptr == NULL || !ArgToNum(ptr, num2))
{
return 1;
}
return 2;
}
void ReadFromFile(EdFile *file, const char *name)
{
FILE *f;
char buffer[BUFSIZ];
f = fopen(name, "r");
if (!f)
{
printf("Could not open %s\n", name);
return;
}
file->fname = strdup(name);
while(GetLine(buffer, sizeof buffer, f))
{
ListAppend(&file->lines, buffer);
}
fclose(f);
}
void WriteToFile(EdFile *file, const char *name)
{
FILE *f;
Node *p;
f = fopen(name, "w");
if (!f)
{
printf("Could not open %s\n", name);
return;
}
for(p = file->lines.head; p; p = p->next)
{
fputs(p->text, f);
fputs("\n", f);
}
fclose(f);
}
Node* LocateLine(EdFile *file, int lineNo)
{
Node *p;
int i;
for(p = file->lines.head, i = 0; p && i < lineNo-1; p = p->next, i++);
return p;
}
void Print(EdFile *file, int num1, int num2)
{
int i = num1;
Node *p = LocateLine(file, num1);
for(; p && i <= num2; p = p->next, i++)
{
puts(p->text);
}
}
void Append(EdFile *file, int num1)
{
char buffer[BUFSIZ];
Node *p = NULL;
if (num1 > 1)
{
p = LocateLine(file, num1-1);
}
while(GetLine(buffer, sizeof buffer, stdin) && strlen(buffer))
{
if (num1 > 1 || p)
{
p = ListInsertAfter(&file->lines, p, buffer);
}
else
{
ListInsertAtHead(&file->lines, buffer);
p = file->lines.head;
}
}
}
void Delete(EdFile *file, int num1, int num2)
{
Node *p = LocateLine(file, num1);
ListDeleteNodesFrom(&file->lines, p, num2-num1);
}
int main()
{
char buffer[BUFSIZ];
char fname[PATH_MAX];
int num1, num2;
EdFile file;
ListInit(&file.lines);
for(;;)
{
num1 = 0;
num2 = INT_MAX;
printf(">");
GetLine(buffer, sizeof(buffer), stdin);
switch(buffer[0])
{
case 'r':
if (GetFileName(buffer, fname, sizeof(fname)) > 0)
{
ReadFromFile(&file, fname);
}
break;
case 'w':
if (GetFileNameOptional(buffer, fname, sizeof(fname)) > 0)
{
WriteToFile(&file, fname);
}
else
{
WriteToFile(&file, file.fname);
}
break;
case 'p':
GetNumArgs(buffer, &num1, &num2);
Print(&file, num1, num2);
break;
case 'a':
num1 = INT_MAX;
GetNumArg(buffer, &num1);
Append(&file, num1);
break;
case 'd':
{
int n = GetNumArgs(buffer, &num1, &num2);
if (n != 2)
{
printf("Must specify first and last line to delete\n");
}
Delete(&file, num1, num2);
}
break;
case 'q':
CleanUp(&file);
return 0;
default:
printf("Invalid command\n");
break;
}
}
}
Code:
// list.c
#include "list.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
void ListInit(List *l)
{
l->tail = l->head = NULL;
}
static Node *NewNode(const char *t)
{
Node *p = malloc(sizeof(Node));
if (p)
{
p->text = malloc(strlen(t) + 1);
if (p->text)
{
strcpy(p->text, t);
p->next = NULL;
return p;
}
}
printf("Error: Out of memory\n");
return NULL;
}
void ListAppend(List *l, const char *t)
{
Node *p = NewNode(t);
if (!l->tail)
{
l->head = p;
}
else
{
l->tail->next = p;
}
l->tail = p;
}
Node *ListInsertAfter(List *l, Node *p, const char *t)
{
if (p == NULL)
{
ListAppend(l, t);
return p;
}
else
{
Node *n;
n = NewNode(t);
n->next = p->next;
p->next = n;
return n;
}
}
void ListInsertAtHead(List *l, const char *t)
{
Node *n;
n = NewNode(t);
n->next = l->head;
l->head = n;
}
Node *ListDeleteOneNode(List *l, Node *p)
{
Node *next = p->next;
if (l->head == p)
{
l->head = next;
}
else
{
Node *pp;
for(pp = l->head; pp && pp->next != p; pp = pp->next);
pp->next = next;
if (l->tail == p)
l->tail = pp;
}
free(p);
return next;
}
void ListDeleteNodesFrom(List *l, Node *p, int n)
{
int i;
for(i = 0; i <= n && p; i++)
{
p = ListDeleteOneNode(l, p);
}
}
void ListDeleteAll(List *l)
{
Node *p, *q;
for(p = l->head; p; p = q)
{
q = p->next;
free(p->text);
free(p);
}
l->head = l->tail = NULL;
}