diff options
| author | Timo Savinen <tjsa@iki.fi> | 2005-09-22 15:39:00 +0000 |
|---|---|---|
| committer | Hadrien Dorio <hadrien.dorio@gmail.com> | 2017-12-16 00:23:56 +0100 |
| commit | 35d0e8a808dd1382d5236d1f6f8bfe62b2ebefee (patch) | |
| tree | e84242391375fab6b6e15963b4b1e0be5296b0bd /src/buffer.c | |
| download | binary-block-editor-35d0e8a808dd1382d5236d1f6f8bfe62b2ebefee.tar.gz binary-block-editor-35d0e8a808dd1382d5236d1f6f8bfe62b2ebefee.zip | |
0.1.0
Diffstat (limited to 'src/buffer.c')
| -rw-r--r-- | src/buffer.c | 490 |
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)); +} + |

