blob: 07d1dd754d458767380aabbba4f00740c4149046 [file] [log] [blame]
/**
* @file chunk_list.cpp
* Manages and navigates the list of chunks.
*
* @author Ben Gardner
* @license GPL v2+
*/
#include "chunk_list.h"
#include <cstring>
#include <cstdlib>
#include "ListManager.h"
#include "prototypes.h"
typedef ListManager<chunk_t> ChunkList;
ChunkList g_cl;
chunk_t *chunk_get_head(void)
{
return(g_cl.GetHead());
}
chunk_t *chunk_get_tail(void)
{
return(g_cl.GetTail());
}
chunk_t *chunk_get_next(chunk_t *cur, chunk_nav_t nav)
{
if (cur == NULL)
{
return(NULL);
}
chunk_t *pc = g_cl.GetNext(cur);
if ((pc == NULL) || (nav == CNAV_ALL))
{
return(pc);
}
if (cur->flags & PCF_IN_PREPROC)
{
/* If in a preproc, return NULL if trying to leave */
if ((pc->flags & PCF_IN_PREPROC) == 0)
{
return(NULL);
}
return(pc);
}
/* Not in a preproc, skip any preproc */
while ((pc != NULL) && (pc->flags & PCF_IN_PREPROC))
{
pc = g_cl.GetNext(pc);
}
return(pc);
}
chunk_t *chunk_get_prev(chunk_t *cur, chunk_nav_t nav)
{
if (cur == NULL)
{
return(NULL);
}
chunk_t *pc = g_cl.GetPrev(cur);
if ((pc == NULL) || (nav == CNAV_ALL))
{
return(pc);
}
if (cur->flags & PCF_IN_PREPROC)
{
/* If in a preproc, return NULL if trying to leave */
if ((pc->flags & PCF_IN_PREPROC) == 0)
{
return(NULL);
}
return(pc);
}
/* Not in a preproc, skip any proproc */
while ((pc != NULL) && (pc->flags & PCF_IN_PREPROC))
{
pc = g_cl.GetPrev(pc);
}
return(pc);
}
chunk_t *chunk_dup(const chunk_t *pc_in)
{
chunk_t *pc;
/* Allocate the entry */
pc = new chunk_t;
if (pc == NULL)
{
exit(1);
}
/* Copy all fields and then init the entry */
*pc = *pc_in;
g_cl.InitEntry(pc);
return(pc);
}
/**
* Add to the tail of the list
*/
chunk_t *chunk_add(const chunk_t *pc_in)
{
chunk_t *pc;
if ((pc = chunk_dup(pc_in)) != NULL)
{
g_cl.AddTail(pc);
}
return(pc);
}
/**
* Add a copy after the given chunk.
* If ref is NULL, add at the head.
*/
chunk_t *chunk_add_after(const chunk_t *pc_in, chunk_t *ref)
{
chunk_t *pc;
if ((pc = chunk_dup(pc_in)) != NULL)
{
if (ref != NULL)
{
g_cl.AddAfter(pc, ref);
}
else
{
g_cl.AddHead(pc);
}
}
return(pc);
}
/**
* Add a copy before the given chunk.
* If ref is NULL, add at the head.
*/
chunk_t *chunk_add_before(const chunk_t *pc_in, chunk_t *ref)
{
chunk_t *pc;
if ((pc = chunk_dup(pc_in)) != NULL)
{
if (ref != NULL)
{
g_cl.AddBefore(pc, ref);
}
else
{
g_cl.AddTail(pc);
}
}
return(pc);
}
void chunk_del(chunk_t *pc)
{
g_cl.Pop(pc);
//if ((pc->flags & PCF_OWN_STR) && (pc->str != NULL))
//{
// delete[] (char *)pc->str;
// pc->str = NULL;
//}
delete pc;
}
void chunk_move_after(chunk_t *pc_in, chunk_t *ref)
{
LOG_FUNC_ENTRY();
g_cl.Pop(pc_in);
g_cl.AddAfter(pc_in, ref);
/* HACK: Adjust the original column */
pc_in->column = ref->column + space_col_align(ref, pc_in);
pc_in->orig_col = pc_in->column;
pc_in->orig_col_end = pc_in->orig_col + pc_in->len();
}
/**
* Gets the next NEWLINE chunk
*/
chunk_t *chunk_get_next_nl(chunk_t *cur, chunk_nav_t nav)
{
chunk_t *pc = cur;
do
{
pc = chunk_get_next(pc, nav);
} while ((pc != NULL) && !chunk_is_newline(pc));
return(pc);
}
/**
* Gets the prev NEWLINE chunk
*/
chunk_t *chunk_get_prev_nl(chunk_t *cur, chunk_nav_t nav)
{
chunk_t *pc = cur;
do
{
pc = chunk_get_prev(pc, nav);
} while ((pc != NULL) && !chunk_is_newline(pc));
return(pc);
}
/**
* Gets the next non-NEWLINE chunk
*/
chunk_t *chunk_get_next_nnl(chunk_t *cur, chunk_nav_t nav)
{
chunk_t *pc = cur;
do
{
pc = chunk_get_next(pc, nav);
} while (chunk_is_newline(pc));
return(pc);
}
/**
* Gets the prev non-NEWLINE chunk
*/
chunk_t *chunk_get_prev_nnl(chunk_t *cur, chunk_nav_t nav)
{
chunk_t *pc = cur;
do
{
pc = chunk_get_prev(pc, nav);
} while ((pc != NULL) && chunk_is_newline(pc));
return(pc);
}
/**
* Gets the next non-NEWLINE and non-comment chunk
*/
chunk_t *chunk_get_next_ncnl(chunk_t *cur, chunk_nav_t nav)
{
chunk_t *pc = cur;
do
{
pc = chunk_get_next(pc, nav);
} while ((pc != NULL) && (chunk_is_comment(pc) || chunk_is_newline(pc)));
return(pc);
}
/**
* Gets the next non-NEWLINE and non-comment chunk, non-preprocessor chunk
*/
chunk_t *chunk_get_next_ncnlnp(chunk_t *cur, chunk_nav_t nav)
{
chunk_t *pc = cur;
if (chunk_is_preproc(cur))
{
do
{
pc = chunk_get_next(pc, nav);
} while ((pc != NULL) && chunk_is_preproc(pc) &&
(chunk_is_comment(pc) || chunk_is_newline(pc)));
}
else
{
do
{
pc = chunk_get_next(pc, nav);
} while ((pc != NULL) && (chunk_is_comment(pc) ||
chunk_is_newline(pc) ||
chunk_is_preproc(pc)));
}
return(pc);
}
/**
* Gets the prev non-NEWLINE and non-comment chunk, non-preprocessor chunk
*/
chunk_t *chunk_get_prev_ncnlnp(chunk_t *cur, chunk_nav_t nav)
{
chunk_t *pc = cur;
if (chunk_is_preproc(cur))
{
do
{
pc = chunk_get_prev(pc, nav);
} while ((pc != NULL) && chunk_is_preproc(pc) &&
(chunk_is_comment(pc) || chunk_is_newline(pc)));
}
else
{
do
{
pc = chunk_get_prev(pc, nav);
} while ((pc != NULL) && (chunk_is_comment(pc) ||
chunk_is_newline(pc) ||
chunk_is_preproc(pc)));
}
return(pc);
}
/**
* Gets the next non-blank chunk
*/
chunk_t *chunk_get_next_nblank(chunk_t *cur, chunk_nav_t nav)
{
chunk_t *pc = cur;
do
{
pc = chunk_get_next(pc, nav);
} while ((pc != NULL) && (chunk_is_comment(pc) ||
chunk_is_newline(pc) ||
chunk_is_blank(pc)));
return(pc);
}
/**
* Gets the prev non-blank chunk
*/
chunk_t *chunk_get_prev_nblank(chunk_t *cur, chunk_nav_t nav)
{
chunk_t *pc = cur;
do
{
pc = chunk_get_prev(pc, nav);
} while ((pc != NULL) && (chunk_is_comment(pc) || chunk_is_newline(pc) ||
chunk_is_blank(pc)));
return(pc);
}
/**
* Gets the next non-comment chunk
*/
chunk_t *chunk_get_next_nc(chunk_t *cur, chunk_nav_t nav)
{
chunk_t *pc = cur;
do
{
pc = chunk_get_next(pc, nav);
} while ((pc != NULL) && chunk_is_comment(pc));
return(pc);
}
/**
* Gets the next chunk not in or part of balanced square
* brackets. This handles stacked [] instances to acommodate
* multi-dimensional array declarations
*
* @param cur Starting chunk
* @return NULL or the next chunk not in or part of
* square brackets
*/
chunk_t *chunk_get_next_nisq(chunk_t *cur, chunk_nav_t nav)
{
chunk_t *pc = cur;
do
{
pc = chunk_get_next(pc, nav);
} while (pc && ((pc->type == CT_SQUARE_OPEN) ||
(pc->type == CT_TSQUARE) ||
(pc->type == CT_SQUARE_CLOSE)));
return(pc);
}
/**
* Gets the prev non-NEWLINE and non-comment chunk
*/
chunk_t *chunk_get_prev_ncnl(chunk_t *cur, chunk_nav_t nav)
{
chunk_t *pc = cur;
do
{
pc = chunk_get_prev(pc, nav);
} while ((pc != NULL) && (chunk_is_comment(pc) || chunk_is_newline(pc)));
return(pc);
}
/**
* Gets the prev non-comment chunk
*/
chunk_t *chunk_get_prev_nc(chunk_t *cur, chunk_nav_t nav)
{
chunk_t *pc = cur;
do
{
pc = chunk_get_prev(pc, nav);
} while ((pc != NULL) && chunk_is_comment(pc));
return(pc);
}
/**
* Grabs the next chunk of the given type at the level.
*
* @param cur Starting chunk
* @param type The type to look for
* @param level -1 (any level) or the level to match
* @return NULL or the match
*/
chunk_t *chunk_get_next_type(chunk_t *cur, c_token_t type,
int level, chunk_nav_t nav)
{
chunk_t *pc = cur;
do
{
pc = chunk_get_next(pc, nav);
if ((pc == NULL) ||
((pc->type == type) && ((pc->level == level) || (level < 0))))
{
break;
}
} while (pc != NULL);
return(pc);
}
chunk_t *chunk_get_next_str(chunk_t *cur, const char *str, int len, int level,
chunk_nav_t nav)
{
chunk_t *pc = cur;
do
{
pc = chunk_get_next(pc, nav);
if ((pc == NULL) ||
((pc->len() == len) && (memcmp(str, pc->text(), len) == 0) &&
((pc->level == level) || (level < 0))))
{
break;
}
} while (pc != NULL);
return(pc);
}
/**
* Grabs the prev chunk of the given type at the level.
*
* @param cur Starting chunk
* @param type The type to look for
* @param level -1 (any level) or the level to match
* @return NULL or the match
*/
chunk_t *chunk_get_prev_type(chunk_t *cur, c_token_t type,
int level, chunk_nav_t nav)
{
chunk_t *pc = cur;
do
{
pc = chunk_get_prev(pc, nav);
if ((pc == NULL) ||
((pc->type == type) && ((pc->level == level) || (level < 0))))
{
break;
}
} while (pc != NULL);
return(pc);
}
chunk_t *chunk_get_prev_str(chunk_t *cur, const char *str, int len, int level,
chunk_nav_t nav)
{
chunk_t *pc = cur;
do
{
pc = chunk_get_prev(pc, nav);
if ((pc == NULL) ||
((pc->len() == len) && (memcmp(str, pc->text(), len) == 0) &&
((pc->level == level) || (level < 0))))
{
break;
}
} while (pc != NULL);
return(pc);
}
/**
* Check to see if there is a newline bewteen the two chunks
*/
bool chunk_is_newline_between(chunk_t *start, chunk_t *end)
{
chunk_t *pc;
for (pc = start; pc != end; pc = chunk_get_next(pc))
{
if (chunk_is_newline(pc))
{
return(true);
}
}
return(false);
}
/**
* Swaps the two chunks.
*
* @param pc1 The first chunk
* @param pc2 The second chunk
*/
void chunk_swap(chunk_t *pc1, chunk_t *pc2)
{
g_cl.Swap(pc1, pc2);
}
/**
* Finds the first chunk on the line that pc is on.
* This just backs up until a newline or NULL is hit.
*
* given: [ a - b - c - n1 - d - e - n2 ]
* input: [ a | b | c | n1 ] => a
* input: [ d | e | n2 ] => d
*/
chunk_t *chunk_first_on_line(chunk_t *pc)
{
chunk_t *first = pc;
while (((pc = chunk_get_prev(pc)) != NULL) && !chunk_is_newline(pc))
{
first = pc;
}
return(first);
}
/**
* Swaps two lines that are started with the specified chunks.
*
* @param pc1 The first chunk of line 1
* @param pc2 The first chunk of line 2
*/
void chunk_swap_lines(chunk_t *pc1, chunk_t *pc2)
{
chunk_t *ref2;
chunk_t *tmp;
pc1 = chunk_first_on_line(pc1);
pc2 = chunk_first_on_line(pc2);
if ((pc1 == NULL) || (pc2 == NULL) || (pc1 == pc2))
{
return;
}
/**
* Example start:
* ? - start1 - a1 - b1 - nl1 - ? - ref2 - start2 - a2 - b2 - nl2 - ?
* ^- pc1 ^- pc2
*/
ref2 = chunk_get_prev(pc2);
/* Move the line started at pc2 before pc1 */
while ((pc2 != NULL) && !chunk_is_newline(pc2))
{
tmp = chunk_get_next(pc2);
g_cl.Pop(pc2);
g_cl.AddBefore(pc2, pc1);
pc2 = tmp;
}
/**
* Should now be:
* ? - start2 - a2 - b2 - start1 - a1 - b1 - nl1 - ? - ref2 - nl2 - ?
* ^- pc1 ^- pc2
*/
/* Now move the line started at pc1 after ref2 */
while ((pc1 != NULL) && !chunk_is_newline(pc1))
{
tmp = chunk_get_next(pc1);
g_cl.Pop(pc1);
if (ref2 != NULL)
{
g_cl.AddAfter(pc1, ref2);
}
else
{
g_cl.AddHead(pc1);
}
ref2 = pc1;
pc1 = tmp;
}
/**
* Should now be:
* ? - start2 - a2 - b2 - nl1 - ? - ref2 - start1 - a1 - b1 - nl2 - ?
* ^- pc1 ^- pc2
*/
/* pc1 and pc2 should be the newlines for their lines.
* swap the chunks and the nl_count so that the spacing remains the same.
*/
if ((pc1 != NULL) && (pc2 != NULL))
{
int nl_count = pc1->nl_count;
pc1->nl_count = pc2->nl_count;
pc2->nl_count = nl_count;
chunk_swap(pc1, pc2);
}
}
/**
* Gets the next non-vbrace chunk
*/
chunk_t *chunk_get_next_nvb(chunk_t *cur, chunk_nav_t nav)
{
chunk_t *pc = cur;
do
{
pc = chunk_get_next(pc, nav);
} while (chunk_is_vbrace(pc));
return(pc);
}
/**
* Gets the prev non-vbrace chunk
*/
chunk_t *chunk_get_prev_nvb(chunk_t *cur, chunk_nav_t nav)
{
chunk_t *pc = cur;
do
{
pc = chunk_get_prev(pc, nav);
} while (chunk_is_vbrace(pc));
return(pc);
}
void set_chunk_type(chunk_t *pc, c_token_t tt)
{
LOG_FUNC_ENTRY();
if (pc && (pc->type != tt))
{
LOG_FMT(LSETTYP, "set_chunk_type: %d:%d '%s' %s:%s => %s:%s",
pc->orig_line, pc->orig_col, pc->text(),
get_token_name(pc->type), get_token_name(pc->parent_type),
get_token_name(tt), get_token_name(pc->parent_type));
log_func_stack_inline(LSETTYP);
pc->type = tt;
}
}
void set_chunk_parent(chunk_t *pc, c_token_t pt)
{
LOG_FUNC_ENTRY();
if (pc && (pc->parent_type != pt))
{
LOG_FMT(LSETPAR, "set_chunk_parent: %d:%d '%s' %s:%s => %s:%s",
pc->orig_line, pc->orig_col, pc->text(),
get_token_name(pc->type), get_token_name(pc->parent_type),
get_token_name(pc->type), get_token_name(pt));
log_func_stack_inline(LSETPAR);
pc->parent_type = pt;
}
}