summaryrefslogtreecommitdiffstats
path: root/src/buffer.c
diff options
context:
space:
mode:
authorTimo Savinen <tjsa@iki.fi>2005-09-22 15:39:00 +0000
committerHadrien Dorio <hadrien.dorio@gmail.com>2017-12-16 00:23:56 +0100
commit35d0e8a808dd1382d5236d1f6f8bfe62b2ebefee (patch)
treee84242391375fab6b6e15963b4b1e0be5296b0bd /src/buffer.c
downloadbinary-block-editor-35d0e8a808dd1382d5236d1f6f8bfe62b2ebefee.tar.gz
binary-block-editor-35d0e8a808dd1382d5236d1f6f8bfe62b2ebefee.zip
0.1.0
Diffstat (limited to 'src/buffer.c')
-rw-r--r--src/buffer.c490
1 files changed, 490 insertions, 0 deletions
diff --git a/src/buffer.c b/src/buffer.c
new file mode 100644
index 0000000..f9b45eb
--- /dev/null
+++ b/src/buffer.c
@@ -0,0 +1,490 @@
+/*
+ * bbe - Binary block editor
+ *
+ * Copyright (C) 2005 Timo Savinen
+ * This file is part of bbe.
+ *
+ * bbe is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * bbe is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with bbe; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+/* $Id: buffer.c,v 1.19 2005/09/14 15:48:52 timo Exp $ */
+
+#include "bbe.h"
+#include <stdlib.h>
+#include <error.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+
+/* output file */
+struct io_file out_stream;
+
+/* list of input files, points to current file */
+struct io_file *in_stream = NULL;
+
+/* input buffer */
+struct input_buffer in_buffer;
+
+/* output buffer */
+struct output_buffer out_buffer;
+
+/* open the output file */
+void
+set_output_file(char *file)
+{
+ if (out_stream.file != NULL) panic("Only one output file can be defined",NULL,NULL);
+
+ if(file == NULL)
+ {
+ out_stream.fd = STDOUT_FILENO;
+ out_stream.file = "stdout";
+ } else
+ {
+ out_stream.fd = open(file,O_WRONLY | O_CREAT | O_TRUNC,S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
+ if(out_stream.fd == -1) panic("Cannot open for writing",file,strerror(errno));
+ out_stream.file = strdup(file);
+ if (out_stream.file == NULL) panic("Out of memory",NULL,NULL);
+ }
+}
+
+/* write to output stream from arbitrary buffer */
+void
+write_output_stream(unsigned char *buffer, ssize_t length)
+{
+ if(write(out_stream.fd,buffer,length) == -1) panic("Error writing to",out_stream.file,strerror(errno));
+}
+
+
+/* open a input file and put it in input file list */
+void
+set_input_file(char *file)
+{
+ struct io_file *new,*curr;
+
+ new = xmalloc(sizeof(struct io_file));
+ new->next = NULL;
+
+ if(in_stream == NULL)
+ {
+ in_stream = new;
+ } else
+ {
+ curr = in_stream;
+ while(curr->next != NULL)
+ {
+ curr = curr->next;
+ }
+ curr->next = new;
+ }
+
+ if(file == NULL)
+ {
+ new->fd = STDIN_FILENO;
+ new->file = "stdin";
+ } else
+ {
+ new->fd = open(file,O_RDONLY);
+ if(new->fd == -1) panic("Cannot open file for reading",file,strerror(errno));
+ new->file = strdup(file);
+ if (new->file == NULL) panic("Out of menory",NULL,NULL);
+ }
+}
+
+/* initialize in and out buffers */
+void
+init_buffer()
+{
+ in_buffer.buffer = xmalloc(INPUT_BUFFER_SIZE);
+ in_buffer.read_pos = NULL;
+ in_buffer.stream_end = NULL;
+ in_buffer.low_pos = in_buffer.buffer + INPUT_BUFFER_SAFE;
+ in_buffer.block_num = 0;
+
+ out_buffer.buffer = xmalloc(OUTPUT_BUFFER_SIZE);
+ out_buffer.write_pos = out_buffer.buffer;
+ out_buffer.low_pos = out_buffer.buffer + OUTPUT_BUFFER_SAFE;
+}
+
+ssize_t
+read_input_stream()
+{
+ ssize_t read_count,last_read,to_be_read,to_be_saved;
+ unsigned char *buffer_write_pos;
+
+ if(in_buffer.stream_end != NULL) return (ssize_t) 0; // can't read more
+
+ if(in_buffer.read_pos == NULL) // first read, so just fill buffer
+ {
+ to_be_read = INPUT_BUFFER_SIZE;
+ buffer_write_pos = in_buffer.buffer;
+ in_buffer.stream_offset = (off_t) 0;
+ } else //we have allready read something
+ {
+ to_be_read = in_buffer.read_pos - in_buffer.buffer;
+ to_be_saved = (ssize_t) INPUT_BUFFER_SIZE - to_be_read;
+ if (to_be_saved > INPUT_BUFFER_SIZE / 2) panic("buffer error: reading to half full buffer",NULL,NULL);
+ memcpy(in_buffer.buffer,in_buffer.read_pos,to_be_saved); // move "low water" part to beginning of buffer
+ buffer_write_pos = in_buffer.buffer + to_be_saved;
+ in_buffer.stream_offset += (off_t) to_be_read;
+ if(in_buffer.block_end != NULL) in_buffer.block_end -= to_be_read;
+ }
+
+ in_buffer.read_pos = in_buffer.buffer;
+
+ read_count = 0;
+ do
+ {
+ last_read = read(in_stream->fd,buffer_write_pos + read_count,(size_t) (to_be_read - read_count));
+ if (last_read == -1) panic("Error reading file",in_stream->file,strerror(errno));
+ if (last_read == 0)
+ {
+ if (close(in_stream->fd) == -1) panic("Error in closing file",in_stream->file,strerror(errno));
+ in_stream = in_stream->next;
+ }
+ read_count += last_read;
+ } while (in_stream != NULL && read_count < to_be_read);
+
+ if (read_count < to_be_read) in_buffer.stream_end = buffer_write_pos + read_count - 1;
+
+ return read_count;
+}
+
+/* reads byte from the buffer */
+inline unsigned char
+read_byte()
+{
+ return *in_buffer.read_pos;
+}
+
+/* advances the read pointer, if buffer has reached low water, get more from stream to buffer */
+/* returns false in case of end of stream */
+
+inline int
+get_next_byte()
+{
+ if(in_buffer.read_pos >= in_buffer.low_pos)
+ {
+ if(read_input_stream() && in_buffer.block_end == NULL) mark_block_end();
+ }
+
+ if(in_buffer.stream_end != NULL)
+ {
+ if(in_buffer.read_pos >= in_buffer.stream_end)
+ {
+ return 0;
+ }
+ }
+
+ in_buffer.read_pos++;
+ in_buffer.block_offset++;
+ return 1;
+}
+
+/* check if the eof current block is in buffer and mark it in_buffer.block_end */
+void
+mark_block_end()
+{
+ unsigned char *safe_search,*scan;
+ int i;
+
+ if(in_buffer.stream_end != NULL)
+ {
+ safe_search = in_buffer.stream_end;
+ } else
+ {
+ safe_search = in_buffer.buffer + INPUT_BUFFER_SIZE;
+ }
+
+ in_buffer.block_end = NULL;
+
+ if(block.type & BLOCK_STOP_M)
+ {
+ in_buffer.block_end = in_buffer.read_pos + (block.stop.M - in_buffer.block_offset - 1);
+ if(in_buffer.block_end > safe_search) in_buffer.block_end = NULL;
+ }
+
+
+ if(block.type & BLOCK_STOP_S)
+ {
+ scan = in_buffer.read_pos;
+ if(block.stop.S.length)
+ {
+ if(block.type & BLOCK_START_S && in_buffer.block_offset < block.start.S.length)
+ scan += block.start.S.length - in_buffer.block_offset;
+ i = 0;
+ while(scan <= safe_search - block.stop.S.length + 1 && i < block.stop.S.length)
+ {
+ i = 0;
+ while(*scan == block.stop.S.string[i] && i < block.stop.S.length)
+ {
+ scan++;
+ i++;
+ }
+ if(i)
+ {
+ scan -= i - 1;
+ } else
+ {
+ scan++;
+ }
+ }
+
+ if (i == block.stop.S.length)
+ {
+ scan += i - 2;
+ in_buffer.block_end = scan;
+ }
+ } else
+ {
+ if(block.type & BLOCK_START_S)
+ {
+ if(block.start.S.length)
+ {
+ if(in_buffer.block_offset < block.start.S.length) // to skip block start
+ scan += block.start.S.length - in_buffer.block_offset;
+
+ i = 0;
+
+ while(scan <= safe_search - block.start.S.length + 1 && i < block.start.S.length)
+ {
+ i = 0;
+ while(*scan == block.start.S.string[i] && i < block.start.S.length)
+ {
+ scan++;
+ i++;
+ }
+ if(i)
+ {
+ scan -= i;
+ } else
+ {
+ scan++;
+ }
+ }
+
+ if (i == block.start.S.length)
+ {
+ in_buffer.block_end = scan - 1;
+ }
+ } else
+ {
+ panic("Both block start and stop zero size",NULL,NULL);
+ }
+ }
+ }
+ }
+
+ if(in_buffer.block_end == NULL && in_buffer.stream_end != NULL)
+ in_buffer.block_end = in_buffer.stream_end;
+}
+
+/* returns true if current byte is last in block */
+inline int
+last_byte()
+{
+ return in_buffer.block_end == in_buffer.read_pos;
+}
+
+/* returns true if end of stream has been reached */
+inline int
+end_of_stream()
+{
+ if(in_buffer.stream_end != NULL && in_buffer.stream_end == in_buffer.read_pos)
+ {
+ return 1;
+ } else
+ {
+ return 0;
+ }
+}
+
+/* read for stream to input buffer and advance the read_pos to the start of the buffer */
+/* in_buffer.read_pos should point to last byte of previous block */
+int
+find_block()
+{
+ unsigned char *safe_search,*scan_start;
+ register int i;
+ int found;
+
+ found = 0;
+
+ if(end_of_stream() && last_byte()) return 0;
+ in_buffer.block_offset = 0;
+
+ do
+ {
+ if(in_buffer.read_pos >= in_buffer.low_pos || in_buffer.read_pos == NULL) read_input_stream();
+
+ if(last_byte()) in_buffer.read_pos++;
+ in_buffer.block_end = NULL;
+
+ scan_start = in_buffer.read_pos;
+
+ if(in_buffer.stream_end != NULL)
+ {
+ safe_search = in_buffer.stream_end;
+ } else
+ {
+ safe_search = in_buffer.low_pos;
+ }
+
+ if (in_buffer.read_pos <= safe_search)
+ {
+ if(block.type & BLOCK_START_M)
+ {
+ if(block.start.N >= in_buffer.stream_offset + (off_t) (in_buffer.read_pos-in_buffer.buffer) &&
+ block.start.N <= in_buffer.stream_offset + (off_t) (safe_search-in_buffer.buffer))
+ {
+ in_buffer.read_pos = in_buffer.buffer + (block.start.N-in_buffer.stream_offset);
+ found = 1;
+ } else
+ {
+ in_buffer.read_pos = safe_search;
+ }
+ }
+
+ if(block.type & BLOCK_START_S)
+ {
+ if(block.start.S.length > 0)
+ {
+ i = 0;
+ while(in_buffer.read_pos <= safe_search - block.start.S.length + 1 && i < block.start.S.length)
+ {
+ i = 0;
+ while(*in_buffer.read_pos == block.start.S.string[i] && i < block.start.S.length)
+ {
+ in_buffer.read_pos++;
+ i++;
+ }
+ if(i)
+ {
+ in_buffer.read_pos -= i - 1;
+ } else
+ {
+ in_buffer.read_pos++;
+ }
+ }
+
+ if(i == block.start.S.length)
+ {
+ in_buffer.read_pos--;
+ found = 1;
+ } else if(scan_start == in_buffer.read_pos)
+ {
+ in_buffer.read_pos++;
+ }
+
+ if(in_buffer.read_pos > in_buffer.stream_end && in_buffer.stream_end != NULL) in_buffer.read_pos--;
+
+ } else
+ {
+ found = 1;
+ }
+ }
+ if(in_buffer.read_pos > scan_start)
+ write_output_stream(scan_start,in_buffer.read_pos - scan_start);
+ if(found) mark_block_end();
+ }
+ } while (!found && !end_of_stream());
+ if(end_of_stream() && !found) write_output_stream(in_buffer.read_pos,1);
+ if(found) in_buffer.block_num++;
+ return found;
+}
+
+/* write_buffer at the current write position */
+void
+write_buffer(unsigned char *buf,off_t length)
+{
+ unsigned char *save_pos;
+
+ if(length > (off_t) (OUTPUT_BUFFER_SIZE - (out_buffer.write_pos - out_buffer.buffer)))
+ {
+ save_pos = out_buffer.cycle_start < out_buffer.low_pos ? out_buffer.cycle_start : out_buffer.low_pos;
+ if(save_pos == out_buffer.buffer)
+ panic("Write buffer too small",NULL,NULL);
+ write_output_stream(out_buffer.buffer,save_pos - out_buffer.buffer);
+ write_w_command(out_buffer.buffer,save_pos - out_buffer.buffer);
+ memmove(out_buffer.buffer,save_pos,out_buffer.write_pos - save_pos);
+ out_buffer.write_pos = out_buffer.buffer + (out_buffer.write_pos - save_pos);
+ out_buffer.cycle_start = out_buffer.buffer + (out_buffer.cycle_start - save_pos);
+ }
+ memcpy(out_buffer.write_pos,buf,length);
+ out_buffer.write_pos += length;
+ out_buffer.block_offset += length;
+}
+
+/* put_byte, put one byte att current write position */
+inline void
+put_byte(unsigned char byte)
+{
+ *out_buffer.write_pos = byte;
+}
+
+/* next_byte, advance the write pointer by one */
+/* if buffer full write it to disk */
+inline void
+write_next_byte()
+{
+ unsigned char *save_pos;
+
+ out_buffer.write_pos++;
+ out_buffer.block_offset++;
+ if(out_buffer.write_pos > out_buffer.buffer + OUTPUT_BUFFER_SIZE)
+ {
+ save_pos = out_buffer.cycle_start < out_buffer.low_pos ? out_buffer.cycle_start : out_buffer.low_pos;
+ if(save_pos == out_buffer.buffer)
+ panic("Write buffer too small",NULL,NULL);
+ write_output_stream(out_buffer.buffer,save_pos - out_buffer.buffer);
+ write_w_command(out_buffer.buffer,save_pos - out_buffer.buffer);
+ memmove(out_buffer.buffer,save_pos,out_buffer.write_pos - save_pos);
+ out_buffer.write_pos = out_buffer.buffer + (out_buffer.write_pos - save_pos);
+ out_buffer.cycle_start = out_buffer.buffer + (out_buffer.cycle_start - save_pos);
+ }
+}
+
+/* reverse_bytes, reverse the write position (for replace etc.) */
+inline void
+reverse_bytes(size_t count)
+{
+ out_buffer.write_pos -= count;
+ out_buffer.block_offset -= count;
+ if(out_buffer.write_pos < out_buffer.buffer) panic("Too many bytes reversed, should not happen",NULL,NULL);
+}
+
+/* set editing cycle start position */
+inline void
+set_cycle_start()
+{
+ out_buffer.cycle_start = out_buffer.write_pos;
+}
+
+/* write unwritten data from buffer to disk */
+void
+flush_buffer()
+{
+ write_output_stream(out_buffer.buffer,out_buffer.write_pos - out_buffer.buffer);
+ write_w_command(out_buffer.buffer,out_buffer.write_pos - out_buffer.buffer);
+ out_buffer.write_pos = out_buffer.buffer;
+}
+
+/* close_output_stream */
+void
+close_output_stream()
+{
+ if(close(out_stream.fd) == -1) panic("Error closing output stream",out_stream.file,strerror(errno));
+}
+
OpenPOWER on IntegriCloud