Change hed_expr_eval call signature
[hed.git] / libhed / file.h
blob05b63cff2de174e1e7331ca8e95ca4ccbdf4b049
1 /* The file handling */
3 /* This is a libhed PUBLIC file.
4 * This header file will be installed on the target system.
5 * When you add new things here, make sure they start with hed_.
6 */
8 /*
9 * hed - Hexadecimal editor
10 * Copyright (C) 2004 Petr Baudis <pasky@ucw.cz>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of version 2 of the GNU General Public License as
14 * published by the Free Software Foundation.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #ifndef LIBHED__FILE_H
27 #define LIBHED__FILE_H
29 #include <libhed/config.h>
31 #include <stdbool.h>
32 #include <string.h>
33 #include <sys/stat.h>
35 #include <libhed/types.h>
36 #include <libhed/expr.h>
38 /* The block cache is organized as follows:
40 * At the start, there are two virtual blocks:
41 * --
43 * The first block covers the edited file (and has a physical size
44 * equal to the size of the file), the second block covers all
45 * possible file offsets beyond EOF (and has zero physical size).
47 * Then we can do a read and turn the virtual block to two, or shift its
48 * start/end:
49 * -x-
51 * After a while...
52 * x-xxx-xx-x-xxxxxxx-x
54 * As you can see, virtual blocks can have any size and stretch variably
55 * and fill the gaps between real blocks which have a size limit.
57 * Now, we can dirty some blocks:
58 * x-xxX-xx-x-xxxxxxx-x
60 * Even if we insert anything to the block, other blocks aren't touched,
61 * except when the block size hits the limit - then, the block will spawn
62 * another one:
63 * x-xxXX-xx-x-xxxxxxx-x
65 * Again, we don't touch other blocks during deletion. Only when the block
66 * size hits zero, we kill it:
67 * x-xxXX-xx-x-xxxxxx-x
69 * Note that we still keep around blocks which have any counterpart in the
70 * file, even if they are already dead in our current file image. This is
71 * necessary when reading more file blocks to the cache and when commiting
72 * the changes, in order to maintain offset consistency.
74 * When can size != phys_size?
75 * * byte(s) have been INSERTED into this block: size > phys_size
76 * Special case is an entire new block:
77 * in case of virtual blocks, phys_size MUST == 0 (gap)
78 * * byte(s) have been ERASED from this block: size < phys_size
79 * Virtual blocks are not permitted
82 struct hed_block {
83 struct hed_tree_node t;
84 struct hed_list_head lru;
86 /* Flags - see HED_BLOCK_xxx below. */
87 long flags;
89 /* List of hed_cursor_t offsets which reference this
90 * structure. This is more flexible than refcounting,
91 * because you may actually do something to the file_block,
92 * as long as you update all the hed_cursor_t structs.
94 struct hed_list_head refs;
96 /* These are only valid for non-virtual blocks */
97 struct hed_block_data *dataobj;
98 size_t dataoff;
100 /* Physical position of this block. */
101 hed_uoff_t phys_pos;
104 #define HED_BLOCK_DIRTY 0x01 /* data has been modified */
105 #define HED_BLOCK_INSERTED 0x02 /* insert/delete block */
106 #define HED_BLOCK_EXCACHE 0x04 /* block is NOT in the cache[] array
107 and can be freed after it is
108 undirtied */
109 #define HED_BLOCK_VIRTUAL 0x08 /* "Virtual" block - must never be
110 dirty nor excache; data is not
111 valid - only size is meaningful. */
112 #define HED_BLOCK_EOF 0x10 /* Purely virtual block beyond EOF. */
113 #define HED_BLOCK_BAD 0x20 /* Block with read errors */
115 #define hed_block_is_dirty(b) ((b)->flags & HED_BLOCK_DIRTY)
116 #define hed_block_set_dirty(b) ((b)->flags |= HED_BLOCK_DIRTY)
117 #define hed_block_clear_dirty(b) ((b)->flags &= ~HED_BLOCK_DIRTY)
119 #define hed_block_is_inserted(b) ((b)->flags & HED_BLOCK_INSERTED)
120 #define hed_block_set_inserted(b) ((b)->flags |= HED_BLOCK_INSERTED)
121 #define hed_block_clear_inserted(b) ((b)->flags &= ~HED_BLOCK_INSERTED)
123 #define hed_block_is_excache(b) ((b)->flags & HED_BLOCK_EXCACHE)
124 #define hed_block_set_excache(b) ((b)->flags |= HED_BLOCK_EXCACHE)
125 #define hed_block_clear_excache(b) ((b)->flags &= ~HED_BLOCK_EXCACHE)
127 #define hed_block_is_virtual(b) ((b)->flags & HED_BLOCK_VIRTUAL)
128 #define hed_block_set_virtual(b) ((b)->flags |= HED_BLOCK_VIRTUAL)
129 #define hed_block_clear_virtual(b) ((b)->flags &= ~HED_BLOCK_VIRTUAL)
131 #define hed_block_is_eof(b) ((b)->flags & HED_BLOCK_EOF)
132 #define hed_block_set_eof(b) ((b)->flags |= HED_BLOCK_EOF)
133 #define hed_block_clear_eof(b) ((b)->flags &= ~HED_BLOCK_EOF)
135 #define hed_block_is_bad(b) ((b)->flags & HED_BLOCK_BAD)
136 #define hed_block_set_bad(b) ((b)->flags |= HED_BLOCK_BAD)
137 #define hed_block_clear_bad(b) ((b)->flags &= ~HED_BLOCK_BAD)
139 #define hed_block_is_inner_virtual(b) \
140 (((b)->flags & (HED_BLOCK_VIRTUAL | HED_BLOCK_EOF | HED_BLOCK_BAD)) \
141 == HED_BLOCK_VIRTUAL)
143 /* flags related to block allocation */
144 #define HED_BLOCK_ALLOCMASK (HED_BLOCK_EXCACHE)
146 /* flags related to block state */
147 #define HED_BLOCK_STATEMASK (HED_BLOCK_DIRTY | HED_BLOCK_INSERTED | \
148 HED_BLOCK_VIRTUAL)
150 static inline hed_uoff_t
151 hed_block_size(const struct hed_block *block)
153 return block->t.size;
156 static inline unsigned char *
157 hed_block_data(const struct hed_block *block)
159 return block->dataobj
160 ? block->dataobj->data + block->dataoff
161 : NULL;
164 /* Returns true iff the block follows a deletion */
165 bool hed_block_is_after_erase(struct hed_block *block);
167 /* Returns true iff the block follows an insertion */
168 bool hed_block_is_after_insert(struct hed_block *block);
170 /* A hed_cursor_t consists of file position, its corresponding
171 * block pointer and the offset within that block.
173 typedef struct {
174 hed_off_t pos;
175 struct hed_block *block;
176 hed_uoff_t off;
177 struct hed_list_head list;
178 } hed_cursor_t;
180 #define HED_NULL_CURSOR { 0, NULL, 0 }
182 #define hed_is_a_cursor(curs) (!!(curs)->block)
184 /* Return a pointer to the actual data at @curs, or NULL if none */
185 static inline void *
186 hed_cursor_data(const hed_cursor_t *curs)
188 return curs->block->dataobj
189 ? hed_block_data(curs->block) + curs->off
190 : NULL;
193 /* Returns the physical file position of the cursor */
194 static inline hed_uoff_t
195 hed_cursor_phys_pos(const hed_cursor_t *curs)
197 return hed_block_is_inserted(curs->block)
198 ? curs->block->phys_pos
199 : curs->block->phys_pos + curs->off;
202 /* Returns the number of contiguous bytes following @curs. */
203 static inline hed_uoff_t
204 hed_cursor_span(const hed_cursor_t *curs)
206 return hed_block_size(curs->block) - curs->off;
209 /* Returns the number of contiguous bytes following @curs,
210 * but at most @maxlen.
211 * The intended use of this function is to determine the next chunk
212 * length to read @maxlen bytes from the file.
214 static inline size_t
215 hed_cursor_chunk_len(const hed_cursor_t *curs, size_t maxlen)
217 hed_uoff_t ret = hed_cursor_span(curs);
218 return ret < maxlen ? (size_t)ret : maxlen;
221 /* File object */
223 #define HED_MARK_NR ('z' - 'a' + 1 + 'Z' - 'A' + 1)
225 struct hed_file {
226 /* The file blocks are sorted by the offset in this list. */
227 struct hed_tree blocks;
229 /* This list contains clean file-backed blocks.
230 * It is sorted from least recently used to most recently used. */
231 struct hed_list_head lru;
233 /* This cache holds the data for clean file-backed blocks. */
234 struct hed_cache *cache;
236 #ifdef HED_CONFIG_READAHEAD
237 enum {
238 HED_RA_NONE, /* No readahead */
239 HED_RA_FORWARD, /* Read-ahead forwards */
240 HED_RA_BACKWARD /* Read-ahead backwards */
241 } readahead;
242 #endif
244 int fd; /* file descriptor for read-only access */
245 hed_uoff_t phys_size; /* physical size on disk */
246 hed_uoff_t size; /* size after modifications */
248 const char *name; /* file name */
250 bool modified;
251 struct stat s;
253 #ifdef HED_CONFIG_SWAP
254 char *swpname; /* original swap file name */
255 char *newswpname; /* new swap file name */
256 struct swp_file *swp;
257 #endif
259 #ifdef HED_CONFIG_MMAP
260 struct hed_list_head fixup_list;
261 #endif
263 /* the always-present EOF block after the file's EOF */
264 struct hed_block eof_block;
266 hed_cursor_t marks[HED_MARK_NR];
269 #ifdef HED_CONFIG_READAHEAD
270 static inline void
271 hed_file_set_readahead(struct hed_file *file, int val)
273 file->readahead = val;
275 #else
276 # define hed_file_set_readahead(file,t) do {} while(0)
277 #endif
279 /*******************************************************************
280 * file object API
283 /* Global initialization */
284 int libhed_init(void);
286 /* Opens a file. */
287 struct hed_file *hed_open(const char *name);
289 /* Closes the file. */
290 void hed_close(struct hed_file *file);
292 /* Get the current file size */
293 static inline
294 hed_uoff_t hed_file_size(struct hed_file *file)
296 return file->size;
299 /* Get the blocks tree */
300 static inline struct hed_tree *
301 hed_file_blocks(struct hed_file *file)
303 return &file->blocks;
306 /* Returns true iff the file has been modified */
307 static inline bool
308 hed_file_is_modified(struct hed_file *file)
310 return file->modified;
313 /* Update the file size from the file system */
314 int hed_file_update_size(struct hed_file *file);
316 /* Commits dirty blocks to the file. */
317 int hed_file_commit(struct hed_file *file);
319 #ifdef HED_CONFIG_SWAP
321 /* Saves dump of internal structures to disk. */
322 int hed_file_write_swap(struct hed_file *file);
324 /* Loads dump of internal structures associated with given file from disk. */
325 int hed_file_read_swap(struct hed_file *file);
327 /* Checks whether a swap file is available. */
328 static inline int
329 hed_file_has_swap(struct hed_file *file)
331 return file->swpname != file->newswpname;
334 /* Remoes dump of internal structures associated with given file from disk. */
335 int hed_file_remove_swap(struct hed_file *file);
337 static inline char *
338 hed_file_swap_name(struct hed_file *file)
340 return file->swpname;
343 #else /* HED_CONFIG_SWAP */
345 static inline int
346 hed_file_write_swap(struct hed_file *file)
348 return 0;
351 static inline int
352 hed_file_read_swap(struct hed_file *file)
354 return -1;
357 static inline int
358 hed_file_has_swap(struct hed_file *file)
360 return 0;
363 static inline int
364 hed_file_remove_swap(struct hed_file *file)
366 return 0;
369 static inline char *
370 hed_file_swap_name(struct hed_file *file)
372 return NULL;
375 #endif /* HED_CONFIG_SWAP */
377 /* Converts a logical @offset to a cursor (@curs). */
378 void hed_get_cursor(struct hed_file *file, hed_uoff_t offset,
379 hed_cursor_t *curs);
381 /* Update the position of an initialized cursor to @offset. */
382 void hed_update_cursor(struct hed_file *file, hed_uoff_t offset,
383 hed_cursor_t *curs);
385 /* Mark @curs as no longer needed. In particular, this stops tracking
386 * file changes with this pointer.
388 void hed_put_cursor(hed_cursor_t *curs);
390 /* Duplicate into an empty hed_cursor_t */
391 void hed_dup_cursor(const hed_cursor_t *src, hed_cursor_t *dst);
393 /* Duplicate into an initialized hed_cursor_t */
394 void hed_dup2_cursor(const hed_cursor_t *src, hed_cursor_t *dst);
396 /* Relative move from a given block offset.
397 * If the resulting position is out of bounds (either < 0 or > OFF_MAX),
398 * the offset is adjusted to only move to 0 or OFF_MAX.
399 * Returns the actual offset which was used.
401 hed_off_t hed_move_relative(hed_cursor_t *curs, hed_off_t num);
403 /* Ensure reads are valid from a block offset.
404 * If @curs points to a virtual block (and not beyond EOF), the
405 * corresponding physical block is loaded from the file.
406 * Returns the number of bytes available in the next chunk
407 * (cf. hed_cursor_chunk_len), or ZERO on error.
409 size_t hed_prepare_read(struct hed_file *file, const hed_cursor_t *curs,
410 size_t len);
412 /* Given you know that offset is just one byte beyond the last span,
413 * get the block which contains byte at @curs.
414 * If the block is not available, it is loaded from disk, so do not
415 * use this function if you only want to iterate through virtual
416 * blocks.
417 * Returns non-zero on error, and the error code is available in @errno.
419 int hed_file_next_block(struct hed_file *file, hed_cursor_t *curs);
421 /* Copy in @count bytes from file @file at @pos to @buf.
422 * Returns number of bytes which were not copied, i.e. zero on success.
424 size_t hed_file_cpin(struct hed_file *file, void *buf, size_t count,
425 const hed_cursor_t *pos);
427 /* Find a given sequence of bytes in the file, starting at the @pos file
428 * offset and possibly wrapping around. @dir is +1 or -1. */
429 int hed_file_find_expr(struct hed_file *file, hed_cursor_t *pos, int dir,
430 struct hed_expr *expr,
431 hed_expr_reg_cb expr_cb, void *expr_cb_data);
432 #define HED_FINDOFF_NO_MATCH -1
433 #define HED_FINDOFF_ERROR -2
435 /* Sets a single byte in the file. */
436 int hed_file_set_byte(struct hed_file *file, hed_cursor_t *curs,
437 unsigned char byte);
438 /* Sets multiple bytes in the file. */
439 size_t hed_file_set_block(struct hed_file *file, hed_cursor_t *curs,
440 unsigned char *buf, size_t len);
441 hed_uoff_t hed_file_set_bytes(struct hed_file *file, hed_cursor_t *curs,
442 unsigned char byte, hed_uoff_t rep);
444 /* To insert bytes:
445 * 1. call file_insert_begin() with the cursor position and store the
446 * insert physical position.
447 * 2. call file_insert_byte() and/or file_insert_block() on the insert pos,
448 * possibly repeatedly
449 * 3. call file_insert_end() on the insert pos and forget all about it;
450 * be careful with aliases, because the insert might get merged/freed
452 int hed_file_insert_begin(struct hed_file *file,
453 const hed_cursor_t *curs, hed_cursor_t *curs_ins);
454 void hed_file_insert_end(struct hed_file *file, hed_cursor_t *curs_ins);
456 /* Inserts a single byte to the file. */
457 int hed_file_insert_byte(struct hed_file *file, hed_cursor_t *curs,
458 unsigned char byte);
459 /* Insert a block of bytes to the file. */
460 size_t hed_file_insert_block(struct hed_file *file, hed_cursor_t *curs,
461 unsigned char *buf, size_t len);
463 /* The following function is a shorthand for the usual
464 * file_insert_begin, file_insert_block, file_insert_end
465 * sequence.
467 size_t hed_file_insert_once(struct hed_file *file, hed_cursor_t *curs,
468 unsigned char *buf, size_t len);
470 /* Erases a single byte from the file. */
471 # define hed_file_erase_byte(file,curs) (hed_file_erase_block((file),(curs),1))
473 /* Erases a block of bytes from the file. */
474 size_t hed_file_erase_block(struct hed_file *file, hed_cursor_t *curs,
475 hed_uoff_t len);
477 /*******************************************************************
478 * MARK FUNCTIONS
481 /* Returns true iff @mark is a valid mark */
482 static inline bool
483 hed_file_has_mark(struct hed_file *file, int mark)
485 return hed_is_a_cursor(&file->marks[mark]);
488 /* Return pointer to a mark */
489 static inline hed_cursor_t*
490 hed_file_mark(struct hed_file *file, int mark)
492 return &file->marks[mark];
495 #endif