/* annotated-file.c:
*
* vim:smartindent ts=8:sts=2:sta:et:ai:shiftwidth=2
****************************************************************
* Copyright (C) 2005 Canonical Limited
* Authors: Robert Collins <robert.collins@canonical.com>
*
* 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);
}
syntax highlighted by Code2HTML, v. 0.9.1