added documentation, almost done with code

This commit is contained in:
FantasyPvP
2024-12-03 09:47:13 +00:00
parent af08485d27
commit ad96bcc0c8
6 changed files with 619 additions and 807 deletions
+78 -77
View File
@@ -7,36 +7,35 @@
#include <stdbool.h>
#include <stdint.h>
typedef struct {
typedef struct String {
uint32_t size, capacity;
char* data;
} String_t;
String_t str_with_capacity(int capacity) {
String_t s;
/// allocate memory for 'capacity' chars
s.data = (char*)calloc(capacity, sizeof(char));
s.size = 0;
s.capacity = capacity;
return s;
int str_len(String_t* s) {
return (int)s->size;
}
String_t str_from_chars(const char* string) {
String_t s;
char* to_chars(String_t* s) {
// allocate buffer with null terminator
char* buffer = (char*)calloc(s->size + 1, sizeof(char));
for (int i = 0; i < s->size; i++) {
buffer[i] = s->data[i];
}
buffer[s->size] = '\0';
return buffer;
}
s.data = (char*)calloc(strlen(string), sizeof(char));
strcpy(s.data, string);
s.size = strlen(string);
s.capacity = strlen(string);
String_t str_with_capacity(int capacity) {
String_t s;
s.data = (char*)calloc(capacity, sizeof(char));
s.size = 0;
s.capacity = capacity;
return s;
}
String_t str_from_slice(const char* string, int len) {
String_t s;
s.data = (char*)calloc(len, sizeof(char));
strncpy(s.data, string, len);
s.size = len;
@@ -44,27 +43,26 @@ String_t str_from_slice(const char* string, int len) {
return s;
}
String_t str_from_chars(const char* string) {
return str_from_slice(string, strlen(string));
}
String_t str_new() {
return str_with_capacity(1);
}
int str_dealloc(String_t* self) {
free(self->data);
return 0;
}
int str_push(String_t* self, char c) {
// check size < capacity
if (self->size < self->capacity) {
self->data[self->size] = c;
self->size++;
return 0;
}
// reallocate to add capacity for an extra char
int newcap = self->capacity + sizeof(char);
self->data = (char*)realloc(self->data, newcap);
self->data[self->size] = c;
@@ -77,39 +75,55 @@ int str_push_str(String_t* self, char* c) {
if (self->size + strlen(c) >= self->capacity) {
self->capacity = (self->size + strlen(c)) * sizeof(char);
self->data = (char*)realloc(self->data, self->capacity);
}
for (int i = 0; i < strlen(c); i++) {
self->data[self->size + i] = c[i];
}
self->size = self->capacity;
}
return 0;
}
String_t str_from_file(FILE* file) {
if (file == NULL) {
return str_new();
}
char buffer[64];
String_t string = str_new();
while (fgets(buffer, sizeof(buffer), file) != NULL) {
str_push_str(&string, buffer);
}
fclose(file);
return string;
}
int str_to_file(String_t* self, FILE* file) {
char* data = to_chars(self);
if (fprintf(file, "%s\n", data) == -1) {
free(data);
return -1;
}
free(data);
return 0;
}
String_t str_clone(String_t* self) {
String_t clone;
clone.size = self->size;
clone.capacity = self->capacity;
clone.data = (char*)malloc(clone.capacity);
memcpy(clone.data, self->data, clone.capacity);
return clone;
}
char str_pop(String_t* self) {
if (self->size == 0) {
return '\0';
}
self->size--;
char c = self->data[self->size];
return c;
return self->data[self->size];
}
int str_insert(String_t* self, int index, char c) {
@@ -117,6 +131,10 @@ int str_insert(String_t* self, int index, char c) {
return -1;
}
self->size++;
if (self->size > self->capacity) {
self->capacity = (self->size) * sizeof(char);
self->data = (char*)realloc(self->data, self->capacity);
}
for (int i = self->size - 1; i > index; i--) {
self->data[i] = self->data[i - 1];
}
@@ -135,22 +153,16 @@ int str_remove(String_t* self, int index) {
return 0;
}
/// splits a string into an array of strings based on a delimiter
String_t* str_split(String_t* self, int* res_len, char c) {
char* string = self->data;
String_t* elements = NULL;
// find the number of lines in the file
bool flag = false;
*res_len = 0;
for (int i = 0; i < strlen(string); i++) {
// Count number of splits
for (int i = 0; i < self->size; i++) {
if (string[i] == c) {
// if (flag) { // this condition was here so that empty strings would be ignore
(*res_len)++;
flag = false;
// }
} else {
flag = true;
}
@@ -159,20 +171,17 @@ String_t* str_split(String_t* self, int* res_len, char c) {
(*res_len)++;
}
// allocate memory for an array of pointers to each line
elements = (String_t*)malloc((*res_len) * sizeof(String_t));
String_t* elements = (String_t*)malloc((*res_len) * sizeof(String_t));
int i = 0;
flag = false;
char* start = string;
char* end = string;
char* string_end = string + self->size;
while (*end != '\0') {
while (end < string_end) {
if (*end == c) {
// if (flag) {
elements[i] = str_from_slice(start, end - start);
i++;
// }
end++;
start = end;
flag = false;
@@ -180,12 +189,10 @@ String_t* str_split(String_t* self, int* res_len, char c) {
end++;
flag = true;
}
} if (flag) {
}
if (flag) {
elements[i] = str_from_slice(start, end - start);
}
// returns an array of String_t
return elements;
}
@@ -209,38 +216,32 @@ String_t* str_lines(String_t* self, int* numlines) {
String_t str_slice(String_t* s, int start, int end) {
String_t s2;
if (start < 0) start = 0;
if (end > s->size) end = s->size;
// if the range is invalid, we return an empty string
if (start >= end || start >= s->size) {
s2.size = 0;
s2.capacity = 1;
s2.data = (char*)calloc(1, sizeof(char));
return s2;
}
s2.size = end - start;
s2.capacity = s2.size;
s2.data = (char*)calloc(s2.size, sizeof(char));
// if the allocation fails we return a zero sized string
if (s2.data == NULL) {
s2.size = 0;
s2.capacity = 0;
return s2;
}
for (int i = 0; i < s2.size; i++) {
s2.data[i] = s->data[start + i];
}
return s2;
}
int str_len(String_t* s) {
return s->size;
}
char* to_chars(String_t* s) {
return s->data;
}
// int main() {
// String_t s = str_from_chars("hello\nworld\neeeee\notherline\n");
// str_remove(&s, 10);
// str_insert(&s, 10, 'h');
// printf("%s\n", to_chars(&s));
// int linen = 0;
// String_t* lines = str_lines(&s, &linen);
// for (int i=0; i < linen; i++) {
// printf("%s", to_chars(&lines[i]));
// }
// str_dealloc(&s);
// return 0;
// }
+161 -14
View File
@@ -2,44 +2,191 @@
#define DYNSTR_H
#include <stdio.h>
typedef struct {
int size;
int capacity;
/**
* Custom String type that stores an array of characters
*/
typedef struct String {
uint32_t size, capacity;
char* data;
} String_t;
/**
* Creates a new string with the specified initial capacity.
* The string will be empty but can hold up to capacity characters
* without requiring reallocation.
*
* @param capacity Initial capacity in bytes
* @return A new String_t structure with allocated memory
*/
String_t str_with_capacity(int capacity);
/**
* Creates a new string from a null-terminated character array.
*
* @param string Null-terminated source string
* @return A new String_t containing a copy of the input string
*/
String_t str_from_chars(char* string);
/**
* Creates a new string from a character array slice.
* Allocates new memory and copies the specified number of characters.
*
* @param string Source character array
* @param len Number of characters to copy
* @return A new String_t containing the copied characters
*/
String_t str_from_slice(char* string, int len);
/**
* Merges two strings into a new string.
* The resulting string contains s1's contents followed by s2's contents.
*
* @param s1 Pointer to the first String_t
* @param s2 Pointer to the second String_t
* @return A new String_t containing the merged contents
*/
String_t str_merge(String_t* s1, String_t* s2);
/**
* Creates a new string by reading from a file.
* Reads the file line by line and concatenates all lines.
*
* @param file Pointer to an open FILE
* @return A new String_t containing the file's contents
*/
String_t str_from_file(FILE* file);
int str_push_str(String_t* string, char* other);
/**
* Creates a new empty string with minimal capacity.
*
* @return A new empty String_t with capacity of 1 byte
*/
String_t str_new();
String_t* str_lines(String_t* self, int* numlines);
/**
* Returns a clone of the string.
* This allocates new memory that must be freed
* @param self Pointer to the String_t to clone
*/
String_t str_clone();
/**
* Creates a new string containing a slice of an existing string.
* The slice includes characters from start index up to (but not including) end index.
*
* @param s Pointer to the source String_t
* @param start Starting index (inclusive)
* @param end Ending index (exclusive)
* @return A new String_t containing the specified slice
*/
String_t str_slice(String_t* s, int start, int end);
// String_t* str_split(String_t* self, int* res_len, char c);
/**
* Splits a string into lines based on newline characters.
* Convenience wrapper around str_split that uses '\n' as delimiter.
*
* @param self Pointer to the String_t to split
* @param numlines Pointer to store the number of resulting lines
* @return Array of String_t structures, one per line
*/
String_t* str_lines(String_t* self, int* numlines);
void str_push(String_t* s, char c);
/**
* Splits a string into an array of strings based on a delimiter.
* Each occurrence of the delimiter creates a new string.
*
* @param self Pointer to the String_t to split
* @param res_len Pointer to store the number of resulting strings
* @param c Delimiter character
* @return Array of String_t structures, must be freed by caller
*/
String_t* str_split(String_t* self, int* res_len, char c);
/**
* Removes and returns the last character in the string.
*
* @param self Pointer to the String_t to modify
* @return The removed character, or '\0' if string is empty
*/
char str_pop(String_t* s);
void str_insert(String_t* s, int index, char c);
void str_remove(String_t* s, int index);
int str_dealloc(String_t* s);
/**
* Returns a pointer to the underlying character array.
* Note: The returned pointer is still owned by the String_t structure.
*
* @param s Pointer to the String_t structure
* @return Pointer to the null-terminated character array
*/
char* to_chars(String_t* s);
/**
* Writes the string's contents to a file.
* Appends a newline character after writing the string.
*
* @param self Pointer to the String_t to write
* @param file Pointer to an open FILE
* @return 0 on success, -1 on failure
*/
int str_to_file(String_t* self, FILE* file);
/**
* Appends a null-terminated string to the end of the string.
* Automatically reallocates if more capacity is needed.
*
* @param self Pointer to the String_t to modify
* @param c Null-terminated string to append
* @return 0 on success
*/
int str_push_str(String_t* string, char* other);
/**
* Deallocates the memory used by a string.
* Must be called when the string is no longer needed to prevent memory leaks.
*
* @param self Pointer to the String_t to deallocate
* @return 0 on success
*/
int str_dealloc(String_t* s);
/**
* Returns the current length of the string.
*
* @param s Pointer to the String_t structure
* @return The number of characters in the string
*/
int str_len(String_t* s);
/**
* Inserts a character at the specified index.
* Shifts existing characters right to make room.
* Automatically reallocates if more capacity is needed.
*
* @param self Pointer to the String_t to modify
* @param index Position to insert the character
* @param c Character to insert
* @return 0 on success, -1 if index is out of bounds
*/
void str_insert(String_t* s, int index, char c);
/**
* Removes the character at the specified index.
* Shifts remaining characters left to fill the gap.
*
* @param self Pointer to the String_t to modify
* @param index Position of character to remove
* @return 0 on success, -1 if index is out of bounds
*/
void str_remove(String_t* s, int index);
/**
* Appends a single character to the end of the string.
* Automatically reallocates if more capacity is needed.
*
* @param self Pointer to the String_t to modify
* @param c Character to append
* @return 0 on success
*/
void str_push(String_t* s, char c);
#endif
+125 -52
View File
@@ -3,8 +3,12 @@
#include "dynstr.h"
#include <ncurses.h>
#define min(x, y) ((x) < (y) ? (x) : (y))
#define max(x, y) ((x) > (y) ? (x) : (y))
typedef struct {
uint32_t lines;
uint32_t capacity;
uint32_t buffer_line;
uint32_t buffer_col;
uint32_t y_offset;
@@ -12,6 +16,8 @@ typedef struct {
bool unsaved_changes;
bool editmode;
String_t* buffer;
String_t* original;
String_t filename;
} Editor;
void add_toolbar(Editor* self) {
@@ -22,7 +28,7 @@ void add_toolbar(Editor* self) {
// add an entry for the current mode
move(max_y - 1, 0);
char mode[8];
char mode[9];
snprintf(mode, 9, "[%6s]", self->editmode ? "Insert" : "Normal");
addstr(mode);
@@ -40,82 +46,96 @@ void add_toolbar(Editor* self) {
attroff(COLOR_PAIR(1));
}
#define min(x, y) ((x) < (y) ? (x) : (y))
void refresh_buffer(Editor* self) {
move(0, 0);
clear();
// get the screen size so we can figure out where to place characters
int max_x, max_y;
getmaxyx(stdscr, max_y, max_x);
max_y--; // Reserve bottom line for toolbar
// Ensure y_offset is valid
if (self->buffer_line >= self->y_offset + max_y) {
self->y_offset = self->buffer_line - max_y + 1;
}
if (self->buffer_line < self->y_offset) {
self->y_offset = self->buffer_line;
}
// Display visible lines
for (size_t i = self->y_offset; i < self->lines && i < self->y_offset + max_y; i++) {
// adding the line number
move(i - self->y_offset, 0);
// adding the line number
attron(COLOR_PAIR(1));
char line_no[6];
snprintf(line_no, 6, "%-6d", i + 1);
snprintf(line_no, 6, "%-4d]", i + 1);
addstr(line_no);
attroff(COLOR_PAIR(1));
// refreshing the text for the line
// Only try to display the line if it's within bounds
if (i < self->lines) {
// Calculate visible portion of line
int visible_start = self->x_offset;
int line_len = str_len(&self->buffer[i]);
int visible_end = min(line_len, self->x_offset + max_x - 5);
if (visible_start < line_len) {
String_t line_segment = str_slice(
&self->buffer[i],
self->x_offset,
min(str_len(&self->buffer[i]), self->x_offset + max_x - 5)
visible_start,
visible_end
);
addstr(to_chars(&line_segment));
str_dealloc(&line_segment);
char* data = to_chars(&line_segment);
addstr("\n");
addstr(data);
str_dealloc(&line_segment);
free(data);
}
}
}
add_toolbar(self);
move(self->buffer_line - self->y_offset, self->buffer_col + 5 - self->x_offset);
// Ensure cursor position is valid
int cursor_y = self->buffer_line - self->y_offset;
int cursor_x = self->buffer_col - self->x_offset + 5;
// Clamp cursor position to screen bounds
cursor_y = min(max(cursor_y, 0), max_y - 1);
cursor_x = min(max(cursor_x, 5), max_x - 1);
move(cursor_y, cursor_x);
}
void move_cursor_on_screen(Editor* editor, int x, int y) {
add_toolbar(editor);
int newx = x + 5; // account for the line number
int max_x, max_y;
getmaxyx(stdscr, max_y, max_x);
max_y--; // Reserve bottom line for toolbar
max_x -= 5; // Account for line number margin
bool flag = false;
while (newx + 3 > max_x + editor->x_offset) {
editor->x_offset += 1;
flag = true;
// Adjust x_offset if cursor would be off screen
if (x + 5 >= max_x + editor->x_offset) {
editor->x_offset = x - max_x + 6;
}
if (x < editor->x_offset) {
editor->x_offset = x;
}
while (newx - 3 < editor->x_offset) {
editor->x_offset -= 1;
flag = true;
// Adjust y_offset if cursor would be off screen
if (y >= max_y + editor->y_offset) {
editor->y_offset = y - max_y + 1;
}
if (y < editor->y_offset) {
editor->y_offset = y;
}
while (y + 3 > max_y + editor->y_offset) {
editor->y_offset += 1;
flag = true;
}
while (y - 3 < editor->y_offset) {
editor->y_offset -= 1;
flag = true;
}
if (flag) {
refresh_buffer(editor);
}
move(y - editor->y_offset, newx - editor->x_offset);
}
void switch_mode(Editor* self) {
self->editmode = !self->editmode;
refresh_buffer(self);
@@ -125,7 +145,6 @@ void newline(Editor* self) {
move(self->buffer_line, 0);
char line_no[6];
snprintf(line_no, 6, "%-6d", self->buffer_line + 1);
fprintf(stderr, "ln: %d, col: %d", self->buffer_line, self->buffer_col);
// add the line number
attron(COLOR_PAIR(1));
@@ -134,7 +153,7 @@ void newline(Editor* self) {
move_cursor_on_screen(self, self->buffer_col, self->buffer_line);
}
Editor editor_from(String_t input_string) {
Editor editor_from(String_t input_string, String_t filename) {
Editor e;
e.lines = 0;
e.buffer_line = 0;
@@ -143,24 +162,46 @@ Editor editor_from(String_t input_string) {
e.x_offset = 0;
e.editmode = false;
e.unsaved_changes = false;
e.filename = filename;
int linenum = 0;
e.buffer = str_lines(&input_string, &linenum);
e.lines = (size_t)linenum;
e.lines = (uint32_t)linenum;
e.capacity = e.lines;
str_dealloc(&input_string);
refresh_buffer(&e);
return e;
}
Editor new_editor() {
return editor_from(str_new());
Editor new_editor(String_t filename) {
return editor_from(str_new(), filename);
}
int save_file(Editor* self) {
char* name = to_chars(&self->filename);
// writes the content line by line to the file
FILE* file = fopen(name, "w");
for (size_t i = 0; i < self->lines; i++) {
if (str_to_file(&self->buffer[i], file) == -1) {
free(name);
fprintf(stderr, "Error writing to file\n");
return -1;
}
}
free(name);
fclose(file);
return 0;
}
void move_cursor(Editor* self, int x, int y) {
if (y != 0
&& (int)(self->buffer_line) + y >= 0
&& self->buffer_line + y <= self->lines)
&& self->buffer_line + y < self->lines)
{
// move the cursor up or down
self->buffer_line += y;
@@ -174,17 +215,19 @@ void move_cursor(Editor* self, int x, int y) {
self->buffer_line -= 1;
self->buffer_col = str_len(&self->buffer[self->buffer_line]);
}
} else if (self->buffer_col + x > str_len(&self->buffer[self->buffer_line])) {
} else if (x != 0 && self->buffer_line < self->lines) {
int line_width = str_len(&self->buffer[self->buffer_line]);
if (self->buffer_col + x > line_width) {
// moving the cursor off the right hand side of the line
if (self->buffer_line < self->lines) {
if (self->buffer_line + 1 < self->lines) {
self->buffer_col = 0;
self->buffer_line += 1;
}
} else if (x != 0) {
} else {
// moving the cursor left or right in any other case
self->buffer_col += x;
}
fprintf(stderr, "ln: %d, col: %d xoff: %d yoff: %d\n", self->buffer_line, self->buffer_col, self->x_offset, self->y_offset);
}
move_cursor_on_screen(self, self->buffer_col, self->buffer_line);
}
@@ -197,12 +240,22 @@ void delchar(Editor* self) {
return;
}
// obtain string objects that reference the old lines.
String_t old_curr_line = self->buffer[self->buffer_line];
String_t old_next_line = self->buffer[self->buffer_line + 1];
// assign the new line
self->buffer[self->buffer_line] = str_merge(&self->buffer[self->buffer_line], &self->buffer[self->buffer_line + 1]);
// deallocate the memory for the old lines
str_dealloc(&old_curr_line);
str_dealloc(&old_next_line);
for (size_t i = self->buffer_line + 2; i < self->lines; i++) {
self->buffer[i - 1] = self->buffer[i];
}
// replace the last line
self->buffer[self->lines - 1] = str_new();
self->lines--;
refresh_buffer(self);
@@ -219,7 +272,11 @@ void pressed_enter(Editor* self) {
// allocate memory immediately since we know a new line is being added
self->lines++;
self->buffer = realloc(self->buffer, sizeof(String_t) * (self->lines));
while (self->lines > self->capacity) {
self->capacity++;
}
self->buffer = (String_t*)realloc(self->buffer, sizeof(String_t) * (self->capacity));
if (self->buffer_line == self->lines -1) {
// if at end of file add an empty line
@@ -230,6 +287,8 @@ void pressed_enter(Editor* self) {
self->buffer[i] = self->buffer[i - 1];
}
String_t old_line = self->buffer[self->buffer_line];
self->buffer[self->buffer_line + 1] = str_slice(
&self->buffer[self->buffer_line],
self->buffer_col,
@@ -241,6 +300,8 @@ void pressed_enter(Editor* self) {
0,
self->buffer_col
);
str_dealloc(&old_line);
}
// refresh the screen with the new data
refresh_buffer(self);
@@ -257,7 +318,12 @@ void addchar(Editor* self, char c) {
// reallocate self->buffer to be 1 larger
self->lines++;
self->buffer = realloc(self->buffer, sizeof(String_t) * (self->lines));
while (self->lines > self->capacity) {
self->capacity++;
}
self->buffer = (String_t*)realloc(self->buffer, sizeof(String_t) * (self->capacity));
// allocate the memory space for the new line and add it to the buffer
self->buffer[self->buffer_line] = str_new();
@@ -269,7 +335,14 @@ void addchar(Editor* self, char c) {
move_cursor(self, 1, 0);
}
void shutdown_editor(Editor* self) {
for (size_t i = 0; i < self->capacity; i++) {
str_dealloc(&self->buffer[i]);
}
str_dealloc(&self->filename);
free(self->buffer);
}
String_t* to_string(Editor* self) {
}
+75 -2
View File
@@ -1,8 +1,13 @@
#include "dynstr.h"
#include <stdint.h>
/**
* maintains the state of a text editor, including the text buffer,
* cursor position, and various editor settings.
*/
typedef struct {
uint32_t lines;
uint32_t capacity;
uint32_t buffer_line;
uint32_t buffer_col;
uint32_t y_offset;
@@ -10,16 +15,84 @@ typedef struct {
bool unsaved_changes;
bool editmode;
String_t* buffer;
String_t* original;
String_t filename;
} Editor;
Editor new_editor();
/**
* Creates a new editor instance from a filename
*
* @param filename The name of the file to open
* @return Editor A new editor instance initialized with the file's content
*/
Editor new_editor(String_t filename);
Editor editor_from(String_t input_string);
/**
* Creates a new editor instance from an input string
*
* @param input_string initial editor content
* @param filename name of the file being edited
* @return an instance of the editor
*/
Editor editor_from(String_t input_string, String_t filename);
/**
* Moves the cursor in the editor (relative to it's current position)
*
* @param self Pointer to the editor instance
* @param x Horizontal movement (negative for left, positive for right)
* @param y Vertical movement (negative for up, positive for down)
*/
void move_cursor(Editor* self, int x, int y);
/**
* Deletes the character before the cursor
*
* @param self Pointer to the editor instance
*/
void delchar(Editor* self);
/**
* Adds a character at the cursor position
*
* @param self Pointer to the editor instance
* @param c The character to add
*/
void addchar(Editor* self, char c);
/**
* Handles the enter key press, creating a new line
*
* @param self Pointer to the editor instance
*/
void pressed_enter(Editor* self);
/**
* Toggles between edit and command mode
*
* @param self Pointer to the editor instance
*/
void switch_mode(Editor* self);
/**
* Cleans up and frees resources used by the editor
*
* @param self Pointer to the editor instance
*/
void shutdown_editor(Editor* self);
/**
* Saves the current buffer content to the file
*
* @param self Pointer to the editor instance
* @return int Returns 0 on success, non-zero on failure
*/
int save_file(Editor* self);
/**
* Converts the editor's buffer content to a String_t type
*
* @param self Pointer to the editor instance
* @return String_t* Pointer to a string containing the buffer content
*/
String_t* to_string(Editor* self);
-630
View File
@@ -1,630 +0,0 @@
starting editor openiing file somecode.cln: 1, col: 0 xoff: 0 yoff: 0
ln: 2, col: 0 xoff: 0 yoff: 0
ln: 3, col: 0 xoff: 0 yoff: 0
ln: 4, col: 0 xoff: 0 yoff: 0
ln: 5, col: 0 xoff: 0 yoff: 0
ln: 6, col: 0 xoff: 0 yoff: 0
ln: 7, col: 0 xoff: 0 yoff: 0
ln: 8, col: 0 xoff: 0 yoff: 0
ln: 9, col: 0 xoff: 0 yoff: 0
ln: 10, col: 0 xoff: 0 yoff: 0
ln: 11, col: 0 xoff: 0 yoff: 0
ln: 12, col: 0 xoff: 0 yoff: 0
ln: 13, col: 0 xoff: 0 yoff: 0
ln: 14, col: 0 xoff: 0 yoff: 0
ln: 15, col: 0 xoff: 0 yoff: 0
ln: 16, col: 0 xoff: 0 yoff: 0
ln: 17, col: 0 xoff: 0 yoff: 0
ln: 18, col: 0 xoff: 0 yoff: 0
ln: 19, col: 0 xoff: 0 yoff: 0
ln: 20, col: 0 xoff: 0 yoff: 0
ln: 21, col: 0 xoff: 0 yoff: 0
ln: 22, col: 0 xoff: 0 yoff: 0
ln: 23, col: 0 xoff: 0 yoff: 0
ln: 24, col: 0 xoff: 0 yoff: 0
ln: 25, col: 0 xoff: 0 yoff: 0
ln: 26, col: 0 xoff: 0 yoff: 0
ln: 27, col: 0 xoff: 0 yoff: 0
ln: 28, col: 0 xoff: 0 yoff: 0
ln: 29, col: 0 xoff: 0 yoff: 0
ln: 30, col: 0 xoff: 0 yoff: 0
ln: 31, col: 0 xoff: 0 yoff: 0
ln: 32, col: 0 xoff: 0 yoff: 0
ln: 33, col: 0 xoff: 0 yoff: 0
ln: 34, col: 0 xoff: 0 yoff: 0
ln: 35, col: 0 xoff: 0 yoff: 0
ln: 36, col: 0 xoff: 0 yoff: 0
ln: 37, col: 0 xoff: 0 yoff: 0
ln: 38, col: 0 xoff: 0 yoff: 0
ln: 39, col: 0 xoff: 0 yoff: 0
ln: 40, col: 0 xoff: 0 yoff: 0
ln: 41, col: 0 xoff: 0 yoff: 0
ln: 42, col: 0 xoff: 0 yoff: 0
ln: 43, col: 0 xoff: 0 yoff: 0
ln: 44, col: 0 xoff: 0 yoff: 0
ln: 45, col: 0 xoff: 0 yoff: 0
ln: 46, col: 0 xoff: 0 yoff: 0
ln: 47, col: 0 xoff: 0 yoff: 0
ln: 48, col: 0 xoff: 0 yoff: 0
ln: 49, col: 0 xoff: 0 yoff: 0
ln: 50, col: 0 xoff: 0 yoff: 0
ln: 51, col: 0 xoff: 0 yoff: 0
ln: 52, col: 0 xoff: 0 yoff: 0
ln: 53, col: 0 xoff: 0 yoff: 0
ln: 54, col: 0 xoff: 0 yoff: 0
ln: 55, col: 0 xoff: 0 yoff: 0
ln: 56, col: 0 xoff: 0 yoff: 0
ln: 57, col: 0 xoff: 0 yoff: 0
ln: 58, col: 0 xoff: 0 yoff: 0
ln: 59, col: 0 xoff: 0 yoff: 0
ln: 60, col: 0 xoff: 0 yoff: 0
ln: 61, col: 0 xoff: 0 yoff: 0
ln: 62, col: 0 xoff: 0 yoff: 0
ln: 63, col: 0 xoff: 0 yoff: 1
ln: 64, col: 0 xoff: 0 yoff: 2
ln: 65, col: 0 xoff: 0 yoff: 3
ln: 66, col: 0 xoff: 0 yoff: 4
ln: 67, col: 0 xoff: 0 yoff: 5
ln: 68, col: 0 xoff: 0 yoff: 6
ln: 69, col: 0 xoff: 0 yoff: 7
ln: 70, col: 0 xoff: 0 yoff: 8
ln: 71, col: 0 xoff: 0 yoff: 9
ln: 72, col: 0 xoff: 0 yoff: 10
ln: 73, col: 0 xoff: 0 yoff: 11
ln: 74, col: 0 xoff: 0 yoff: 12
ln: 75, col: 0 xoff: 0 yoff: 13
ln: 76, col: 0 xoff: 0 yoff: 14
ln: 77, col: 0 xoff: 0 yoff: 15
ln: 78, col: 0 xoff: 0 yoff: 16
ln: 79, col: 0 xoff: 0 yoff: 17
ln: 80, col: 0 xoff: 0 yoff: 18
ln: 81, col: 0 xoff: 0 yoff: 19
ln: 82, col: 0 xoff: 0 yoff: 20
ln: 83, col: 0 xoff: 0 yoff: 21
ln: 84, col: 0 xoff: 0 yoff: 22
ln: 85, col: 0 xoff: 0 yoff: 23
ln: 86, col: 0 xoff: 0 yoff: 24
ln: 87, col: 0 xoff: 0 yoff: 25
ln: 88, col: 0 xoff: 0 yoff: 26
ln: 89, col: 0 xoff: 0 yoff: 27
ln: 90, col: 0 xoff: 0 yoff: 28
ln: 91, col: 0 xoff: 0 yoff: 29
ln: 92, col: 0 xoff: 0 yoff: 30
ln: 93, col: 0 xoff: 0 yoff: 31
ln: 94, col: 0 xoff: 0 yoff: 32
ln: 95, col: 0 xoff: 0 yoff: 33
ln: 96, col: 0 xoff: 0 yoff: 34
ln: 97, col: 0 xoff: 0 yoff: 35
ln: 98, col: 0 xoff: 0 yoff: 36
ln: 99, col: 0 xoff: 0 yoff: 37
ln: 100, col: 0 xoff: 0 yoff: 38
ln: 101, col: 0 xoff: 0 yoff: 39
ln: 102, col: 0 xoff: 0 yoff: 40
ln: 103, col: 0 xoff: 0 yoff: 41
ln: 104, col: 0 xoff: 0 yoff: 42
ln: 105, col: 0 xoff: 0 yoff: 43
ln: 106, col: 0 xoff: 0 yoff: 44
ln: 107, col: 0 xoff: 0 yoff: 45
ln: 108, col: 0 xoff: 0 yoff: 46
ln: 109, col: 0 xoff: 0 yoff: 47
ln: 110, col: 0 xoff: 0 yoff: 48
ln: 111, col: 0 xoff: 0 yoff: 49
ln: 112, col: 0 xoff: 0 yoff: 50
ln: 113, col: 0 xoff: 0 yoff: 51
ln: 114, col: 0 xoff: 0 yoff: 52
ln: 115, col: 0 xoff: 0 yoff: 53
ln: 116, col: 0 xoff: 0 yoff: 54
ln: 117, col: 0 xoff: 0 yoff: 55
ln: 118, col: 0 xoff: 0 yoff: 56
ln: 119, col: 0 xoff: 0 yoff: 57
ln: 120, col: 0 xoff: 0 yoff: 58
ln: 121, col: 0 xoff: 0 yoff: 59
ln: 122, col: 0 xoff: 0 yoff: 60
ln: 123, col: 0 xoff: 0 yoff: 61
ln: 124, col: 0 xoff: 0 yoff: 62
ln: 125, col: 0 xoff: 0 yoff: 63
ln: 126, col: 0 xoff: 0 yoff: 64
ln: 127, col: 0 xoff: 0 yoff: 65
ln: 128, col: 0 xoff: 0 yoff: 66
ln: 129, col: 0 xoff: 0 yoff: 67
ln: 130, col: 0 xoff: 0 yoff: 68
ln: 131, col: 0 xoff: 0 yoff: 69
ln: 132, col: 0 xoff: 0 yoff: 70
ln: 133, col: 0 xoff: 0 yoff: 71
ln: 134, col: 0 xoff: 0 yoff: 72
ln: 135, col: 0 xoff: 0 yoff: 73
ln: 136, col: 0 xoff: 0 yoff: 74
ln: 137, col: 0 xoff: 0 yoff: 75
ln: 138, col: 0 xoff: 0 yoff: 76
ln: 139, col: 0 xoff: 0 yoff: 77
ln: 140, col: 0 xoff: 0 yoff: 78
ln: 141, col: 0 xoff: 0 yoff: 79
ln: 142, col: 0 xoff: 0 yoff: 80
ln: 143, col: 0 xoff: 0 yoff: 81
ln: 144, col: 0 xoff: 0 yoff: 82
ln: 145, col: 0 xoff: 0 yoff: 83
ln: 146, col: 0 xoff: 0 yoff: 84
ln: 147, col: 0 xoff: 0 yoff: 85
ln: 148, col: 0 xoff: 0 yoff: 86
ln: 149, col: 0 xoff: 0 yoff: 87
ln: 150, col: 0 xoff: 0 yoff: 88
ln: 151, col: 0 xoff: 0 yoff: 89
ln: 152, col: 0 xoff: 0 yoff: 90
ln: 153, col: 0 xoff: 0 yoff: 91
ln: 154, col: 0 xoff: 0 yoff: 92
ln: 155, col: 0 xoff: 0 yoff: 93
ln: 156, col: 0 xoff: 0 yoff: 94
ln: 157, col: 0 xoff: 0 yoff: 95
ln: 158, col: 0 xoff: 0 yoff: 96
ln: 159, col: 0 xoff: 0 yoff: 97
ln: 160, col: 0 xoff: 0 yoff: 98
ln: 161, col: 0 xoff: 0 yoff: 99
ln: 162, col: 0 xoff: 0 yoff: 100
ln: 163, col: 0 xoff: 0 yoff: 101
ln: 164, col: 0 xoff: 0 yoff: 102
ln: 165, col: 0 xoff: 0 yoff: 103
ln: 164, col: 0 xoff: 0 yoff: 104
ln: 163, col: 0 xoff: 0 yoff: 104
ln: 162, col: 0 xoff: 0 yoff: 104
ln: 161, col: 0 xoff: 0 yoff: 104
ln: 160, col: 0 xoff: 0 yoff: 104
ln: 159, col: 0 xoff: 0 yoff: 104
ln: 158, col: 0 xoff: 0 yoff: 104
ln: 157, col: 0 xoff: 0 yoff: 104
ln: 156, col: 0 xoff: 0 yoff: 104
ln: 155, col: 0 xoff: 0 yoff: 104
ln: 154, col: 0 xoff: 0 yoff: 104
ln: 153, col: 0 xoff: 0 yoff: 104
ln: 152, col: 0 xoff: 0 yoff: 104
ln: 151, col: 0 xoff: 0 yoff: 104
ln: 150, col: 0 xoff: 0 yoff: 104
ln: 149, col: 0 xoff: 0 yoff: 104
ln: 148, col: 0 xoff: 0 yoff: 104
ln: 147, col: 0 xoff: 0 yoff: 104
ln: 146, col: 0 xoff: 0 yoff: 104
ln: 145, col: 0 xoff: 0 yoff: 104
ln: 144, col: 0 xoff: 0 yoff: 104
ln: 143, col: 0 xoff: 0 yoff: 104
ln: 142, col: 0 xoff: 0 yoff: 104
ln: 141, col: 0 xoff: 0 yoff: 104
ln: 140, col: 0 xoff: 0 yoff: 104
ln: 139, col: 0 xoff: 0 yoff: 104
ln: 138, col: 0 xoff: 0 yoff: 104
ln: 137, col: 0 xoff: 0 yoff: 104
ln: 136, col: 0 xoff: 0 yoff: 104
ln: 135, col: 0 xoff: 0 yoff: 104
ln: 134, col: 0 xoff: 0 yoff: 104
ln: 133, col: 0 xoff: 0 yoff: 104
ln: 132, col: 0 xoff: 0 yoff: 104
ln: 131, col: 0 xoff: 0 yoff: 104
ln: 130, col: 0 xoff: 0 yoff: 104
ln: 129, col: 0 xoff: 0 yoff: 104
ln: 128, col: 0 xoff: 0 yoff: 104
ln: 127, col: 0 xoff: 0 yoff: 104
ln: 126, col: 0 xoff: 0 yoff: 104
ln: 125, col: 0 xoff: 0 yoff: 104
ln: 124, col: 0 xoff: 0 yoff: 104
ln: 123, col: 0 xoff: 0 yoff: 104
ln: 122, col: 0 xoff: 0 yoff: 104
ln: 121, col: 0 xoff: 0 yoff: 104
ln: 120, col: 0 xoff: 0 yoff: 104
ln: 119, col: 0 xoff: 0 yoff: 104
ln: 118, col: 0 xoff: 0 yoff: 104
ln: 117, col: 0 xoff: 0 yoff: 104
ln: 116, col: 0 xoff: 0 yoff: 104
ln: 115, col: 0 xoff: 0 yoff: 104
ln: 114, col: 0 xoff: 0 yoff: 104
ln: 113, col: 0 xoff: 0 yoff: 104
ln: 112, col: 0 xoff: 0 yoff: 104
ln: 111, col: 0 xoff: 0 yoff: 104
ln: 110, col: 0 xoff: 0 yoff: 104
ln: 109, col: 0 xoff: 0 yoff: 104
ln: 108, col: 0 xoff: 0 yoff: 104
ln: 107, col: 0 xoff: 0 yoff: 104
ln: 106, col: 0 xoff: 0 yoff: 104
ln: 105, col: 0 xoff: 0 yoff: 103
ln: 104, col: 0 xoff: 0 yoff: 102
ln: 103, col: 0 xoff: 0 yoff: 101
ln: 102, col: 0 xoff: 0 yoff: 100
ln: 101, col: 0 xoff: 0 yoff: 99
ln: 100, col: 0 xoff: 0 yoff: 98
ln: 99, col: 0 xoff: 0 yoff: 97
ln: 98, col: 0 xoff: 0 yoff: 96
ln: 97, col: 0 xoff: 0 yoff: 95
ln: 96, col: 0 xoff: 0 yoff: 94
ln: 97, col: 0 xoff: 0 yoff: 93
ln: 98, col: 0 xoff: 0 yoff: 93
ln: 99, col: 0 xoff: 0 yoff: 93
ln: 100, col: 0 xoff: 0 yoff: 93
ln: 101, col: 0 xoff: 0 yoff: 93
ln: 102, col: 0 xoff: 0 yoff: 93
ln: 103, col: 0 xoff: 0 yoff: 93
ln: 104, col: 0 xoff: 0 yoff: 93
ln: 105, col: 0 xoff: 0 yoff: 93
ln: 106, col: 0 xoff: 0 yoff: 93
ln: 107, col: 0 xoff: 0 yoff: 93
ln: 108, col: 0 xoff: 0 yoff: 93
ln: 109, col: 0 xoff: 0 yoff: 93
ln: 110, col: 0 xoff: 0 yoff: 93
ln: 111, col: 0 xoff: 0 yoff: 93
ln: 112, col: 0 xoff: 0 yoff: 93
ln: 113, col: 0 xoff: 0 yoff: 93
ln: 114, col: 0 xoff: 0 yoff: 93
ln: 115, col: 0 xoff: 0 yoff: 93
ln: 116, col: 0 xoff: 0 yoff: 93
ln: 117, col: 0 xoff: 0 yoff: 93
ln: 118, col: 0 xoff: 0 yoff: 93
ln: 119, col: 0 xoff: 0 yoff: 93
ln: 120, col: 0 xoff: 0 yoff: 93
ln: 121, col: 0 xoff: 0 yoff: 93
ln: 122, col: 0 xoff: 0 yoff: 93
ln: 123, col: 0 xoff: 0 yoff: 93
ln: 124, col: 0 xoff: 0 yoff: 93
ln: 125, col: 0 xoff: 0 yoff: 93
ln: 126, col: 0 xoff: 0 yoff: 93
ln: 127, col: 0 xoff: 0 yoff: 93
ln: 128, col: 0 xoff: 0 yoff: 93
ln: 129, col: 0 xoff: 0 yoff: 93
ln: 130, col: 0 xoff: 0 yoff: 93
ln: 131, col: 0 xoff: 0 yoff: 93
ln: 132, col: 0 xoff: 0 yoff: 93
ln: 133, col: 0 xoff: 0 yoff: 93
ln: 134, col: 0 xoff: 0 yoff: 93
ln: 135, col: 0 xoff: 0 yoff: 93
ln: 136, col: 0 xoff: 0 yoff: 93
ln: 137, col: 0 xoff: 0 yoff: 93
ln: 138, col: 0 xoff: 0 yoff: 93
ln: 139, col: 0 xoff: 0 yoff: 93
ln: 140, col: 0 xoff: 0 yoff: 93
ln: 141, col: 0 xoff: 0 yoff: 93
ln: 142, col: 0 xoff: 0 yoff: 93
ln: 143, col: 0 xoff: 0 yoff: 93
ln: 144, col: 0 xoff: 0 yoff: 93
ln: 145, col: 0 xoff: 0 yoff: 93
ln: 146, col: 0 xoff: 0 yoff: 93
ln: 147, col: 0 xoff: 0 yoff: 93
ln: 148, col: 0 xoff: 0 yoff: 93
ln: 149, col: 0 xoff: 0 yoff: 93
ln: 150, col: 0 xoff: 0 yoff: 93
ln: 151, col: 0 xoff: 0 yoff: 93
ln: 152, col: 0 xoff: 0 yoff: 93
ln: 153, col: 0 xoff: 0 yoff: 93
ln: 154, col: 0 xoff: 0 yoff: 93
ln: 155, col: 0 xoff: 0 yoff: 93
ln: 156, col: 0 xoff: 0 yoff: 94
ln: 157, col: 0 xoff: 0 yoff: 95
ln: 158, col: 0 xoff: 0 yoff: 96
ln: 159, col: 0 xoff: 0 yoff: 97
ln: 160, col: 0 xoff: 0 yoff: 98
ln: 161, col: 0 xoff: 0 yoff: 99
ln: 162, col: 0 xoff: 0 yoff: 100
ln: 163, col: 0 xoff: 0 yoff: 101
ln: 164, col: 0 xoff: 0 yoff: 102
ln: 165, col: 0 xoff: 0 yoff: 103
ln: 166, col: 0 xoff: 0 yoff: 104
ln: 167, col: 0 xoff: 0 yoff: 105
ln: 168, col: 0 xoff: 0 yoff: 106
ln: 169, col: 0 xoff: 0 yoff: 107
ln: 170, col: 0 xoff: 0 yoff: 108
ln: 171, col: 0 xoff: 0 yoff: 109
ln: 172, col: 0 xoff: 0 yoff: 110
ln: 173, col: 0 xoff: 0 yoff: 111
ln: 174, col: 0 xoff: 0 yoff: 112
ln: 175, col: 0 xoff: 0 yoff: 113
ln: 176, col: 0 xoff: 0 yoff: 114
ln: 177, col: 0 xoff: 0 yoff: 115
ln: 178, col: 0 xoff: 0 yoff: 116
ln: 179, col: 0 xoff: 0 yoff: 117
ln: 180, col: 0 xoff: 0 yoff: 118
ln: 181, col: 0 xoff: 0 yoff: 119
ln: 182, col: 0 xoff: 0 yoff: 120
ln: 183, col: 0 xoff: 0 yoff: 121
ln: 184, col: 0 xoff: 0 yoff: 122
ln: 185, col: 0 xoff: 0 yoff: 123
ln: 186, col: 0 xoff: 0 yoff: 124
ln: 187, col: 0 xoff: 0 yoff: 125
ln: 188, col: 0 xoff: 0 yoff: 126
ln: 189, col: 0 xoff: 0 yoff: 127
ln: 190, col: 0 xoff: 0 yoff: 128
ln: 191, col: 0 xoff: 0 yoff: 129
ln: 192, col: 0 xoff: 0 yoff: 130
ln: 193, col: 0 xoff: 0 yoff: 131
ln: 194, col: 0 xoff: 0 yoff: 132
ln: 195, col: 0 xoff: 0 yoff: 133
ln: 196, col: 0 xoff: 0 yoff: 134
ln: 197, col: 0 xoff: 0 yoff: 135
ln: 198, col: 0 xoff: 0 yoff: 136
ln: 199, col: 0 xoff: 0 yoff: 137
ln: 200, col: 0 xoff: 0 yoff: 138
ln: 201, col: 0 xoff: 0 yoff: 139
ln: 202, col: 0 xoff: 0 yoff: 140
ln: 203, col: 0 xoff: 0 yoff: 141
ln: 204, col: 0 xoff: 0 yoff: 142
ln: 205, col: 0 xoff: 0 yoff: 143
ln: 206, col: 0 xoff: 0 yoff: 144
ln: 207, col: 0 xoff: 0 yoff: 145
ln: 208, col: 0 xoff: 0 yoff: 146
ln: 209, col: 0 xoff: 0 yoff: 147
ln: 210, col: 0 xoff: 0 yoff: 148
ln: 211, col: 0 xoff: 0 yoff: 149
ln: 212, col: 0 xoff: 0 yoff: 150
ln: 213, col: 0 xoff: 0 yoff: 151
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 212, col: 0 xoff: 0 yoff: 152
ln: 211, col: 0 xoff: 0 yoff: 152
ln: 210, col: 0 xoff: 0 yoff: 152
ln: 211, col: 0 xoff: 0 yoff: 152
ln: 212, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 212, col: 0 xoff: 0 yoff: 152
ln: 211, col: 0 xoff: 0 yoff: 152
ln: 210, col: 0 xoff: 0 yoff: 152
ln: 209, col: 0 xoff: 0 yoff: 152
ln: 208, col: 0 xoff: 0 yoff: 152
ln: 207, col: 0 xoff: 0 yoff: 152
ln: 208, col: 0 xoff: 0 yoff: 152
ln: 209, col: 0 xoff: 0 yoff: 152
ln: 210, col: 0 xoff: 0 yoff: 152
ln: 209, col: 0 xoff: 0 yoff: 152
ln: 208, col: 0 xoff: 0 yoff: 152
ln: 207, col: 0 xoff: 0 yoff: 152
ln: 208, col: 0 xoff: 0 yoff: 152
ln: 209, col: 0 xoff: 0 yoff: 152
ln: 210, col: 0 xoff: 0 yoff: 152
ln: 209, col: 0 xoff: 0 yoff: 152
ln: 208, col: 0 xoff: 0 yoff: 152
ln: 207, col: 0 xoff: 0 yoff: 152
ln: 208, col: 0 xoff: 0 yoff: 152
ln: 209, col: 0 xoff: 0 yoff: 152
ln: 210, col: 0 xoff: 0 yoff: 152
ln: 211, col: 0 xoff: 0 yoff: 152
ln: 212, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 213, col: 0 xoff: 0 yoff: 152
ln: 212, col: 0 xoff: 0 yoff: 152
ln: 211, col: 0 xoff: 0 yoff: 152
ln: 210, col: 0 xoff: 0 yoff: 152
ln: 209, col: 0 xoff: 0 yoff: 152
ln: 208, col: 0 xoff: 0 yoff: 152
ln: 207, col: 0 xoff: 0 yoff: 152
ln: 206, col: 0 xoff: 0 yoff: 152
ln: 205, col: 0 xoff: 0 yoff: 152
ln: 204, col: 0 xoff: 0 yoff: 152
ln: 203, col: 0 xoff: 0 yoff: 152
ln: 202, col: 0 xoff: 0 yoff: 152
ln: 201, col: 0 xoff: 0 yoff: 152
ln: 200, col: 0 xoff: 0 yoff: 152
ln: 199, col: 0 xoff: 0 yoff: 152
ln: 198, col: 0 xoff: 0 yoff: 152
ln: 197, col: 0 xoff: 0 yoff: 152
ln: 196, col: 0 xoff: 0 yoff: 152
ln: 195, col: 0 xoff: 0 yoff: 152
ln: 194, col: 0 xoff: 0 yoff: 152
ln: 193, col: 0 xoff: 0 yoff: 152
ln: 192, col: 0 xoff: 0 yoff: 152
ln: 191, col: 0 xoff: 0 yoff: 152
ln: 190, col: 0 xoff: 0 yoff: 152
ln: 189, col: 0 xoff: 0 yoff: 152
ln: 188, col: 0 xoff: 0 yoff: 152
ln: 187, col: 0 xoff: 0 yoff: 152
ln: 186, col: 0 xoff: 0 yoff: 152
ln: 185, col: 0 xoff: 0 yoff: 152
ln: 184, col: 0 xoff: 0 yoff: 152
ln: 183, col: 0 xoff: 0 yoff: 152
ln: 182, col: 0 xoff: 0 yoff: 152
ln: 181, col: 0 xoff: 0 yoff: 152
ln: 180, col: 0 xoff: 0 yoff: 152
ln: 179, col: 0 xoff: 0 yoff: 152
ln: 178, col: 0 xoff: 0 yoff: 152
ln: 177, col: 0 xoff: 0 yoff: 152
ln: 176, col: 0 xoff: 0 yoff: 152
ln: 175, col: 0 xoff: 0 yoff: 152
ln: 174, col: 0 xoff: 0 yoff: 152
ln: 173, col: 0 xoff: 0 yoff: 152
ln: 172, col: 0 xoff: 0 yoff: 152
ln: 171, col: 0 xoff: 0 yoff: 152
ln: 170, col: 0 xoff: 0 yoff: 152
ln: 169, col: 0 xoff: 0 yoff: 152
ln: 168, col: 0 xoff: 0 yoff: 152
ln: 167, col: 0 xoff: 0 yoff: 152
ln: 166, col: 0 xoff: 0 yoff: 152
ln: 165, col: 0 xoff: 0 yoff: 152
ln: 164, col: 0 xoff: 0 yoff: 152
ln: 163, col: 0 xoff: 0 yoff: 152
ln: 162, col: 0 xoff: 0 yoff: 152
ln: 161, col: 0 xoff: 0 yoff: 152
ln: 160, col: 0 xoff: 0 yoff: 152
ln: 159, col: 0 xoff: 0 yoff: 152
ln: 158, col: 0 xoff: 0 yoff: 152
ln: 157, col: 0 xoff: 0 yoff: 152
ln: 156, col: 0 xoff: 0 yoff: 152
ln: 155, col: 0 xoff: 0 yoff: 152
ln: 154, col: 0 xoff: 0 yoff: 152
ln: 153, col: 0 xoff: 0 yoff: 151
ln: 152, col: 0 xoff: 0 yoff: 150
ln: 151, col: 0 xoff: 0 yoff: 149
ln: 150, col: 0 xoff: 0 yoff: 148
ln: 149, col: 0 xoff: 0 yoff: 147
ln: 148, col: 0 xoff: 0 yoff: 146
ln: 147, col: 0 xoff: 0 yoff: 145
ln: 146, col: 0 xoff: 0 yoff: 144
ln: 145, col: 0 xoff: 0 yoff: 143
ln: 144, col: 0 xoff: 0 yoff: 142
ln: 143, col: 0 xoff: 0 yoff: 141
ln: 142, col: 0 xoff: 0 yoff: 140
ln: 141, col: 0 xoff: 0 yoff: 139
ln: 140, col: 0 xoff: 0 yoff: 138
ln: 139, col: 0 xoff: 0 yoff: 137
ln: 138, col: 0 xoff: 0 yoff: 136
ln: 137, col: 0 xoff: 0 yoff: 135
ln: 136, col: 0 xoff: 0 yoff: 134
ln: 135, col: 0 xoff: 0 yoff: 133
ln: 134, col: 0 xoff: 0 yoff: 132
ln: 133, col: 0 xoff: 0 yoff: 131
ln: 132, col: 0 xoff: 0 yoff: 130
ln: 131, col: 0 xoff: 0 yoff: 129
ln: 130, col: 0 xoff: 0 yoff: 128
ln: 129, col: 0 xoff: 0 yoff: 127
ln: 128, col: 0 xoff: 0 yoff: 126
ln: 127, col: 0 xoff: 0 yoff: 125
ln: 126, col: 0 xoff: 0 yoff: 124
ln: 125, col: 0 xoff: 0 yoff: 123
ln: 124, col: 0 xoff: 0 yoff: 122
ln: 123, col: 0 xoff: 0 yoff: 121
ln: 122, col: 0 xoff: 0 yoff: 120
ln: 121, col: 0 xoff: 0 yoff: 119
ln: 120, col: 0 xoff: 0 yoff: 118
ln: 119, col: 0 xoff: 0 yoff: 117
ln: 118, col: 0 xoff: 0 yoff: 116
ln: 117, col: 0 xoff: 0 yoff: 115
ln: 116, col: 0 xoff: 0 yoff: 114
ln: 115, col: 0 xoff: 0 yoff: 113
ln: 114, col: 0 xoff: 0 yoff: 112
ln: 113, col: 0 xoff: 0 yoff: 111
ln: 112, col: 0 xoff: 0 yoff: 110
ln: 111, col: 0 xoff: 0 yoff: 109
ln: 110, col: 0 xoff: 0 yoff: 108
ln: 109, col: 0 xoff: 0 yoff: 107
ln: 108, col: 0 xoff: 0 yoff: 106
ln: 107, col: 0 xoff: 0 yoff: 105
ln: 106, col: 0 xoff: 0 yoff: 104
ln: 105, col: 0 xoff: 0 yoff: 103
ln: 104, col: 0 xoff: 0 yoff: 102
ln: 103, col: 0 xoff: 0 yoff: 101
ln: 102, col: 0 xoff: 0 yoff: 100
ln: 101, col: 0 xoff: 0 yoff: 99
ln: 100, col: 0 xoff: 0 yoff: 98
ln: 99, col: 0 xoff: 0 yoff: 97
ln: 98, col: 0 xoff: 0 yoff: 96
ln: 97, col: 0 xoff: 0 yoff: 95
ln: 96, col: 0 xoff: 0 yoff: 94
ln: 95, col: 0 xoff: 0 yoff: 93
ln: 94, col: 0 xoff: 0 yoff: 92
ln: 93, col: 0 xoff: 0 yoff: 91
ln: 92, col: 0 xoff: 0 yoff: 90
ln: 91, col: 0 xoff: 0 yoff: 89
ln: 90, col: 0 xoff: 0 yoff: 88
ln: 89, col: 0 xoff: 0 yoff: 87
ln: 88, col: 0 xoff: 0 yoff: 86
ln: 87, col: 0 xoff: 0 yoff: 85
ln: 86, col: 0 xoff: 0 yoff: 84
ln: 85, col: 0 xoff: 0 yoff: 83
ln: 84, col: 0 xoff: 0 yoff: 82
ln: 83, col: 0 xoff: 0 yoff: 81
ln: 82, col: 0 xoff: 0 yoff: 80
ln: 81, col: 0 xoff: 0 yoff: 79
ln: 80, col: 0 xoff: 0 yoff: 78
ln: 79, col: 0 xoff: 0 yoff: 77
ln: 78, col: 0 xoff: 0 yoff: 76
ln: 77, col: 0 xoff: 0 yoff: 75
ln: 76, col: 0 xoff: 0 yoff: 74
ln: 75, col: 0 xoff: 0 yoff: 73
ln: 74, col: 0 xoff: 0 yoff: 72
ln: 73, col: 0 xoff: 0 yoff: 71
ln: 72, col: 0 xoff: 0 yoff: 70
ln: 71, col: 0 xoff: 0 yoff: 69
ln: 70, col: 0 xoff: 0 yoff: 68
ln: 69, col: 0 xoff: 0 yoff: 67
ln: 68, col: 0 xoff: 0 yoff: 66
ln: 67, col: 0 xoff: 0 yoff: 65
ln: 66, col: 0 xoff: 0 yoff: 64
ln: 65, col: 0 xoff: 0 yoff: 63
ln: 64, col: 0 xoff: 0 yoff: 62
ln: 63, col: 0 xoff: 0 yoff: 61
ln: 62, col: 0 xoff: 0 yoff: 60
ln: 61, col: 0 xoff: 0 yoff: 59
ln: 60, col: 0 xoff: 0 yoff: 58
ln: 59, col: 0 xoff: 0 yoff: 57
ln: 58, col: 0 xoff: 0 yoff: 56
ln: 57, col: 0 xoff: 0 yoff: 55
ln: 56, col: 0 xoff: 0 yoff: 54
ln: 55, col: 0 xoff: 0 yoff: 53
ln: 54, col: 0 xoff: 0 yoff: 52
ln: 53, col: 0 xoff: 0 yoff: 51
ln: 52, col: 0 xoff: 0 yoff: 50
ln: 51, col: 0 xoff: 0 yoff: 49
ln: 50, col: 0 xoff: 0 yoff: 48
ln: 49, col: 0 xoff: 0 yoff: 47
ln: 48, col: 0 xoff: 0 yoff: 46
ln: 47, col: 0 xoff: 0 yoff: 45
ln: 46, col: 0 xoff: 0 yoff: 44
ln: 45, col: 0 xoff: 0 yoff: 43
ln: 44, col: 0 xoff: 0 yoff: 42
ln: 43, col: 0 xoff: 0 yoff: 41
ln: 42, col: 0 xoff: 0 yoff: 40
ln: 41, col: 0 xoff: 0 yoff: 39
ln: 40, col: 0 xoff: 0 yoff: 38
ln: 39, col: 0 xoff: 0 yoff: 37
ln: 38, col: 0 xoff: 0 yoff: 36
ln: 37, col: 0 xoff: 0 yoff: 35
ln: 36, col: 0 xoff: 0 yoff: 34
ln: 35, col: 0 xoff: 0 yoff: 33
ln: 34, col: 0 xoff: 0 yoff: 32
ln: 33, col: 0 xoff: 0 yoff: 31
ln: 32, col: 0 xoff: 0 yoff: 30
ln: 31, col: 0 xoff: 0 yoff: 29
ln: 30, col: 0 xoff: 0 yoff: 28
ln: 29, col: 0 xoff: 0 yoff: 27
ln: 28, col: 0 xoff: 0 yoff: 26
ln: 27, col: 0 xoff: 0 yoff: 25
ln: 26, col: 0 xoff: 0 yoff: 24
ln: 25, col: 0 xoff: 0 yoff: 23
ln: 24, col: 0 xoff: 0 yoff: 22
ln: 23, col: 0 xoff: 0 yoff: 21
ln: 22, col: 0 xoff: 0 yoff: 20
ln: 21, col: 0 xoff: 0 yoff: 19
ln: 20, col: 0 xoff: 0 yoff: 18
ln: 19, col: 0 xoff: 0 yoff: 17
ln: 18, col: 0 xoff: 0 yoff: 16
ln: 17, col: 0 xoff: 0 yoff: 15
ln: 16, col: 0 xoff: 0 yoff: 14
ln: 15, col: 0 xoff: 0 yoff: 13
ln: 14, col: 0 xoff: 0 yoff: 12
ln: 13, col: 0 xoff: 0 yoff: 11
ln: 12, col: 0 xoff: 0 yoff: 10
ln: 11, col: 0 xoff: 0 yoff: 9
ln: 10, col: 0 xoff: 0 yoff: 8
ln: 9, col: 0 xoff: 0 yoff: 7
ln: 8, col: 0 xoff: 0 yoff: 6
ln: 7, col: 0 xoff: 0 yoff: 5
ln: 6, col: 0 xoff: 0 yoff: 4
ln: 5, col: 0 xoff: 0 yoff: 3
+165 -17
View File
@@ -6,12 +6,13 @@
void help() {
printf("Usage:\n");
printf(" cmd open <path/to/file> // opens the specified file\n");
printf(" cmd rm <path/to/file> // deletes the specified file\n");
printf(" cmd new <path/to/file> // creates a new empty file at the specified path\n");
printf(" cmd mv <path/to/file> <new/path> // moves the specified file to the new path\n");
printf(" cmd cp <path/to/file> <new/path> // copies the specified file to the new path\n");
printf(" cmd len <path/to/file> // returns the length of the specified file\n");
printf(" cmd open <file/path> // opens the specified file\n");
printf(" cmd rm <file/path> // deletes the specified file\n");
printf(" cmd new <file/path> // creates a new empty file at the specified path\n");
printf(" cmd mv <old/path> <new/path> // moves the specified file to the new path\n");
printf(" cmd cp <old/path> <new/path> // copies the specified file to the new path\n");
printf(" cmd lenl <file/path> // returns the length of the specified file in lines\n");
printf(" cmd lenc <file/path> // returns the length of the specified file in chars\n");
printf(" cmd log // prints a list of all changes made to the file\n");
}
@@ -33,9 +34,9 @@ int open_editor(char* filename) {
Editor editor;
if (strcmp(filename, "") == 0) {
editor = new_editor();
editor = new_editor(str_from_chars(filename));
} else {
editor = editor_from(str_from_file(fopen(filename, "r")));
editor = editor_from(str_from_file(fopen(filename, "r")), str_from_chars(filename));
}
while (true) {
refresh();
@@ -68,7 +69,6 @@ int open_editor(char* filename) {
move_cursor(&editor, 1, 0);
break;
default:
fprintf(stderr, "%d\n", c);
addchar(&editor, c);
break;
}
@@ -76,12 +76,15 @@ int open_editor(char* filename) {
switch (c) {
case 'q':
endwin();
shutdown_editor(&editor);
return 0;
case 'i':
switch_mode(&editor);
break;
case 'w':
editor.unsaved_changes = false;
save_file(&editor);
// TODO: write function to save the data to a file
break;
default:
@@ -91,16 +94,161 @@ int open_editor(char* filename) {
}
}
int main(int argc, char* argv[]) {
if (argc == 1) {
Editor e = new_editor();
open_editor("");
} else if (argc == 3) {
if (strcmp(argv[1], "open") == 0) {
fprintf(stderr, "starting editor openiing file %s", argv[2]);
open_editor(argv[2]);
// Copies a file from source to destination
int copy_file(const char* source, const char* dest) {
FILE* src = fopen(source, "rb");
if (src == NULL) {
fprintf(stderr, "Error: Could not open source file %s\n", source);
return -1;
}
FILE* dst = fopen(dest, "wb");
if (dst == NULL) {
fclose(src);
fprintf(stderr, "Error: Could not create destination file %s\n", dest);
return -1;
}
char buffer[8192];
size_t bytes;
while ((bytes = fread(buffer, 1, sizeof(buffer), src)) > 0) {
if (fwrite(buffer, 1, bytes, dst) != bytes) {
fclose(src);
fclose(dst);
fprintf(stderr, "Error: Write failed to %s\n", dest);
return -1;
}
}
fclose(src);
fclose(dst);
return 0;
}
// Counts the number of characters in a file
int count_chars(const char* filename) {
FILE* file = fopen(filename, "r");
if (file == NULL) {
fprintf(stderr, "Error: Could not open file %s\n", filename);
return -1;
}
int count = 0;
int ch;
while ((ch = fgetc(file)) != EOF) {
count++;
}
fclose(file);
return count;
}
// Counts the number of lines in a file
int count_lines(const char* filename) {
FILE* file = fopen(filename, "r");
if (file == NULL) {
fprintf(stderr, "Error: Could not open file %s\n", filename);
return -1;
}
int count = 0;
int ch;
int last_char = '\n'; // Handle empty files as 0 lines
while ((ch = fgetc(file)) != EOF) {
if (ch == '\n') {
count++;
}
last_char = ch;
}
// Count last line if it doesn't end with newline
if (last_char != '\n' && last_char != EOF) {
count++;
}
fclose(file);
return count;
}
// Command types
typedef enum {
CMD_OPEN,
CMD_RM,
CMD_NEW,
CMD_MV,
CMD_CP,
CMD_LENL,
CMD_LENC,
CMD_LOG,
CMD_UNKNOWN
} CommandType;
// Convert string to command type
CommandType str_to_cmd(const char* cmd) {
if (strcmp(cmd, "open") == 0) return CMD_OPEN;
if (strcmp(cmd, "rm") == 0) return CMD_RM;
if (strcmp(cmd, "new") == 0) return CMD_NEW;
if (strcmp(cmd, "mv") == 0) return CMD_MV;
if (strcmp(cmd, "cp") == 0) return CMD_CP;
if (strcmp(cmd, "lenl") == 0) return CMD_LENL;
if (strcmp(cmd, "lenc") == 0) return CMD_LENC;
if (strcmp(cmd, "log") == 0) return CMD_LOG;
return CMD_UNKNOWN;
}
int main(int argc, char* argv[]) {
if (argc < 2) {
help();
return 1;
}
CommandType cmd = str_to_cmd(argv[1]);
if (argc == 3) {
switch (cmd) {
case CMD_OPEN:
open_editor(argv[2]);
break;
case CMD_RM:
remove(argv[2]);
break;
case CMD_NEW:
open_editor(argv[2]);
break;
case CMD_LENC:
printf("%d\n", count_chars(argv[2]));
break;
case CMD_LENL:
printf("%d\n", count_lines(argv[2]));
break;
default:
help();
}
}
else if (argc == 4) {
switch (cmd) {
case CMD_MV:
if (rename(argv[2], argv[3]) != 0) {
fprintf(stderr, "Error: Failed to move file %s to %s\n", argv[2], argv[3]);
}
break;
case CMD_CP:
if (copy_file(argv[2], argv[3]) != 0) {
fprintf(stderr, "Error: Failed to copy file %s to %s\n", argv[2], argv[3]);
}
break;
default:
help();
}
}
else {
printf("invalid options\n");
help();
}
return 0;
}