/* annotated-file.c: * * vim:smartindent ts=8:sts=2:sta:et:ai:shiftwidth=2 **************************************************************** * Copyright (C) 2005 Canonical Limited * Authors: Robert Collins * * See the file "COPYING" for further information about * the copyright and warranty status of this work. */ #include "hackerlab/bugs/panic.h" #include "hackerlab/char/str.h" #include "libarch/debug.h" #include "libarch/file-offset-mapper.h" void file_offset_map_entry_init (file_offset_map_entry_t * entry, int from, int to, int length) { entry->from = from; entry->to = to; entry->length = length; } void file_offset_mapper_init (file_offset_mapper_t *mapper, int lines) { file_offset_map_entry_t *entry; mapper->map = NULL; entry = ar_ref_file_offset_map_entry (&mapper->map, 0); file_offset_map_entry_init (entry, 0, 0, lines); } /** * \brief find the containing block */ static int find_from (file_offset_mapper_t *mapper, int line) { int position; for (position = 0; position < ar_size_file_offset_map_entry (mapper->map); ++position) if (mapper->map[position].from <= line && mapper->map[position].from + mapper->map[position].length > line) return position; return -1; } #include "hackerlab/vu/safe-printfmt.h" static void file_offset_map_entry_print (int fd, file_offset_map_entry_t entry) { safe_printfmt(2, "%d[-%d] %d[-%d] %d", entry.from, entry.from + entry.length - 1, entry.to, entry.to + entry.length - 1, entry.length); } void file_offset_mapper_print(int fd, file_offset_mapper_t *mapper) { int position; for (position = 0; position < ar_size_file_offset_map_entry (mapper->map); ++position) { safe_printfmt (2, "%d: ", position); file_offset_map_entry_print (fd, mapper->map[position]); safe_printfmt (2, "\n"); } } void file_offset_mapper_subtract (file_offset_mapper_t *mapper, int line) { int block_offset = find_from(mapper, line); file_offset_map_entry_t new_entry; debug(dbg_annotate, 8, "file_offset_mapper_subtract (&mapper, %d);\n", line); if (block_offset == -1) { int position; debug (dbg_annotate, 8, "file_offset_mapper_subtract non mapped line %d\n", line); block_offset = 0; while (block_offset < ar_size_file_offset_map_entry (mapper->map) && line > mapper->map[block_offset].from) ++block_offset; /* start of entry */ for (position = block_offset; position < ar_size_file_offset_map_entry (mapper->map); ++position) ++mapper->map[position].from; return; } if (mapper->map[block_offset].from == line) { int position; /* start of entry */ for (position = block_offset; position < ar_size_file_offset_map_entry (mapper->map); ++position) ++mapper->map[position].from; return; } /* split the block */ { int new_latter_length; int position; new_latter_length = line - mapper->map[block_offset].from; file_offset_map_entry_init (&new_entry, line, mapper->map[block_offset].to + new_latter_length, mapper->map[block_offset].length - line + mapper->map[block_offset].from); ar_insert_file_offset_map_entry (&mapper->map, block_offset + 1, new_entry); mapper->map[block_offset].length = new_latter_length; /* adjust the new block and all successors up one */ for (position = block_offset + 1; position < ar_size_file_offset_map_entry (mapper->map); ++position) ++mapper->map[position].from; //mapper->map[block_offset].length - mapper->map[block_offset + 1].length - 1; // line - mapper->map[block_offset].from); } } /** * \brief check if blocks block, block + 1 can be consolidated, * assumes block_offset is not the final offset. * \return non-zero if they can be consolidated. */ static int file_offset_mapper_can_consolidate (file_offset_mapper_t *mapper, int block_offset) { if (mapper->map[block_offset].from + mapper->map[block_offset].length != mapper->map[block_offset + 1].from) return 0; if (mapper->map[block_offset].to + mapper->map[block_offset].length != mapper->map[block_offset + 1].to) return 0; return -1; } /** * \brief consolidate two blocks. * assumes block_offset is not the final offset. */ static void file_offset_mapper_consolidate (file_offset_mapper_t *mapper, int block_offset) { if (!file_offset_mapper_can_consolidate (mapper, block_offset)) return; mapper->map[block_offset].length += mapper->map[block_offset + 1].length; ar_remove_file_offset_map_entry (&mapper->map, block_offset + 1); } /* * \brief * mark line as being set - its current target will be mapped an unreachable. * if line has no target (due to a prior subtract), then it gets given a new target * of the active target after it. * all existing source maps will map to the value the next up * valid source mapped to. */ void file_offset_mapper_add (file_offset_mapper_t *mapper, int line) { file_offset_map_entry_t new_entry; int block_offset = find_from(mapper, line); debug(dbg_annotate, 8, "file_offset_mapper_add (&mapper, %d);\n", line); if (line < 0) return; if (block_offset == -1) { /* currently maps to deleted */ /* * i.e. * line 1 * 0 - 0 * 1 - deleted * 2 - deleted * 3 - 1 * -> * 0 - 0 * 1 - deleted * 2 - 1 * : set block_offset->from -1. and block_offset one higher. * if there are no successive blocks, we do nothing. */ block_offset = 0; while (block_offset < ar_size_file_offset_map_entry (mapper->map) && line > mapper->map[block_offset].from) ++block_offset; if (block_offset == ar_size_file_offset_map_entry (mapper->map)) return; mapper->map[block_offset].from -= 1; block_offset += 1; } while (block_offset != -1) { if (block_offset >= ar_size_file_offset_map_entry (mapper->map)) { /* last block */ debug(dbg_annotate, 8, "Done on block: %d\n", block_offset); block_offset = -1; break; } if (line == mapper->map[block_offset].from) { debug(dbg_annotate, 8, "Shrinking (first block): %d\n", block_offset); mapper->map[block_offset].length -= 1; mapper->map[block_offset].to += 1; if (!mapper->map[block_offset].length) ar_remove_file_offset_map_entry (&mapper->map, block_offset); else block_offset +=1; } else if (line > mapper->map[block_offset].from) { /* first block - split with no adjustment. */ if (mapper->map[block_offset].length == 2) { debug(dbg_annotate, 8, "Shrinking (first block split): %d\n", block_offset); mapper->map[block_offset].length -= 1; if (!mapper->map[block_offset].length) ar_remove_file_offset_map_entry (&mapper->map, block_offset); else block_offset += 1; if (block_offset == ar_size_file_offset_map_entry (mapper->map)) block_offset = -1; } else { debug(dbg_annotate, 8, "Splitting (first block): %d\n", block_offset); file_offset_map_entry_init (&new_entry, mapper->map[block_offset].from, mapper->map[block_offset].to, line - mapper->map[block_offset].from); ar_insert_file_offset_map_entry (&mapper->map, block_offset, new_entry); mapper->map[block_offset + 1].from = line; mapper->map[block_offset + 1].to = mapper->map[block_offset].to + mapper->map[block_offset].length + 1; mapper->map[block_offset + 1].length -= mapper->map[block_offset].length; mapper->map[block_offset + 1].length -= 1; if (!mapper->map[block_offset + 1].length) ar_remove_file_offset_map_entry (&mapper->map, block_offset + 1); else block_offset += 1; block_offset += 1; } } else { /* adjust current block. */ if (mapper->map[block_offset].length == 1) { /* non contiguous, single length block */ debug(dbg_annotate, 8, "1 line non contigous block: %d: %d->%d\n", block_offset, mapper->map[block_offset].from, mapper->map[block_offset].to); mapper->map[block_offset].from -=1; /* move to next block */ block_offset += 1; } else { /* split this block */ debug(dbg_annotate, 8, "lowering later block: %d\n", block_offset); mapper->map[block_offset].from -=1; block_offset += 1; } } } /* note: if it ever matters, count down - more efficient */ block_offset = 0; while (block_offset + 1 < ar_size_file_offset_map_entry (mapper->map)) { if (file_offset_mapper_can_consolidate (mapper, block_offset)) file_offset_mapper_consolidate (mapper, block_offset); else ++block_offset; } return; } int file_offset_mapper_map (file_offset_mapper_t *mapper, int line) { /* find line in the map */ int block = find_from(mapper, line); int result; if (block == -1) return -1; result = mapper->map[block].to + line - mapper->map[block].from; if (block + 1 == ar_size_file_offset_map_entry (mapper->map)) /* cannot have dups at the end */ return result; // if (mapper->map[block + 1].from == line) // return mapper->map[block + 1].to; return result; } void file_offset_mapper_finalise (file_offset_mapper_t *mapper) { ar_free_file_offset_map_entry (&mapper->map); }