/* quark.c * A simple, line-oriented text editor * Written by Feky, 2008 */ #include #include #include #include #include #define VERSION "quark 0.2" #define LINE_LEN 255 typedef struct _list { struct _list *next; struct _list *prev; char line[LINE_LEN]; } LIST; typedef unsigned int uint; void help (char *); /* show help */ bool insert (void); /* insert a new node into the list */ bool erase (void); /* delete a node */ bool save (char *); /* save the buffer to a file */ void printall (uint); /* see 'p*' in help */ LIST list; LIST *head, *curr; void help (char *argv) { printf("%s\nUsage: %s [FILE]\n\n", VERSION, argv); puts("Command\tMeaning\n" "p\tPrint the current line.\n" "\t\'p*\' prints all lines until EOF is reached."); puts(">\tOverwrite the current line with some text."); puts("n\tInsert a new, blank line after the current."); puts("d\tDelete the current line."); puts("+\tGo forward for a number of lines."); puts("-\tGo backwards for a number of lines."); puts("s\tSave changes to file."); puts("q\tExit the program."); } bool insert (void) { LIST *node; node = calloc(1, sizeof(LIST)); if(node != NULL) { node->next = curr->next; node->prev = curr; if(curr->next != NULL) curr->next->prev = node; curr->next = node; curr = curr->next; return false; } /* not enough memory for a new node */ return true; } bool erase (void) { LIST *node; node = curr->prev; if(node == head) /* we're at the first node */ node = curr->next; if(node == NULL) /* there's nothing to delete anymore */ return true; if(curr->next != NULL) /* if it's not the last node */ curr->next->prev = curr->prev; curr->prev->next = curr->next; free(curr); curr = node; return false; } bool save (char *fn) { LIST *node; FILE *pf; pf = fopen(fn, "w"); if(pf == NULL) return true; node = curr; curr = head->next; while(curr != NULL) { fprintf(pf, "%s", curr->line); curr = curr->next; } curr = node; fclose(pf); return false; } void printall (uint line) { LIST *node; uint l = line; node = curr; while(curr != NULL) { printf("%d: %s", l, curr->line); curr = curr->next; l++; } putchar('\n'); curr = node; } int main (int argc, char **argv) { FILE *pf; char *line; char *filename; char *mode = "r"; uint ln = 0; int i; if(argc != 2) { help(argv[0]); return 0; } line = calloc(LINE_LEN, sizeof(char)); if(line == NULL) { perror("calloc"); return -1; } pf = fopen(argv[1], mode); /* if the file doesn't exist, it will be created */ if(pf == NULL) { mode = "w"; pf = fopen(argv[1], mode); if(pf == NULL) { perror("fopen"); return -1; } } filename = argv[1]; /* prepare the list */ curr = head = &list; head->prev = NULL; head->next = curr; curr->prev = head; curr->next = NULL; if(!strcmp(mode, "r")) { /* store the contents of the file in the list */ while(fgets(line, LINE_LEN, pf) != NULL) { if(insert()) { perror("calloc"); fclose(pf); goto die; } strcpy(curr->line, line); ln++; } curr = head->next; ln = 1; } else { strcpy(curr->line, "\n"); ln++; } fclose(pf); while(fgets(line, LINE_LEN, stdin) != NULL) { switch(*line) { case 'p': line++; if(*line == '*') printall(ln); else printf("%d: %s", ln, curr->line); break; case '+': line++; if(isdigit(*line)) { for(i = atoi(line); i > 0; i--) { if(curr->next == NULL) { puts("End of file."); break; } curr = curr->next; ln++; } } else puts("Bad use of \'+\'."); break; case '-': line++; if(isdigit(*line)) { for(i = atoi(line); i > 0; i--) { if(curr->prev == head) { puts("Start of file."); break; } curr = curr->prev; ln--; } } else puts("Bad use of \'-\'."); break; case 'q': goto die; break; case 'd': if(erase()) puts("Can't delete more."); else if(ln > 1) ln--; break; case 'n': if(insert()) { perror("calloc"); goto die; } else { strcpy(curr->line, "\n"); ln++; } break; case '>': line++; strcpy(curr->line, line); break; case 's': if(save(filename)) printf("Can't save to %s.\n", filename); else printf("Saved to %s.\n", filename); break; default: puts("Unknown command."); break; } } die: /* clean up and exit */ while(!erase()); return 0; }