1 /**
2 * @file chunk_list.cpp
3 * Manages and navigates the list of chunks.
4 *
5 * @author Ben Gardner
6 * @license GPL v2+
7 */
8
9 #include "chunk_list.h"
10
11 #include "ListManager.h"
12 #include "prototypes.h"
13 #include "space.h"
14
15 typedef ListManager<chunk_t> ChunkList_t;
16
17
18 /**
19 * use this enum to define in what direction or location an
20 * operation shall be performed.
21 */
22 enum class direction_e : unsigned int
23 {
24 FORWARD,
25 BACKWARD
26 };
27
28
29 /**
30 * @brief prototype for a function that checks a chunk to have a given type
31 *
32 * @note this typedef defines the function type "check_t"
33 * for a function pointer of type
34 * bool function(chunk_t *pc)
35 */
36 typedef bool (*check_t)(chunk_t *pc);
37
38
39 /**
40 * @brief prototype for a function that searches through a chunk list
41 *
42 * @note this typedef defines the function type "search_t"
43 * for a function pointer of type
44 * chunk_t *function(chunk_t *cur, nav_t scope)
45 */
46 typedef chunk_t * (*search_t)(chunk_t *cur, scope_e scope);
47
48
49 /**
50 * @brief search for a chunk that satisfies a condition in a chunk list
51 *
52 * A generic function that traverses a chunks list either
53 * in forward or reverse direction. The traversal continues until a
54 * chunk satisfies the condition defined by the compare function.
55 * Depending on the parameter cond the condition will either be
56 * checked to be true or false.
57 *
58 * Whenever a chunk list traversal is to be performed this function
59 * shall be used. This keeps the code clear and easy to understand.
60 *
61 * If there are performance issues this function might be worth to
62 * be optimized as it is heavily used.
63 *
64 * @param cur chunk to start search at
65 * @param check_fct compare function
66 * @param scope code parts to consider for search
67 * @param dir search direction
68 * @param cond success condition
69 *
70 * @retval nullptr no requested chunk was found or invalid parameters provided
71 * @retval chunk_t pointer to the found chunk
72 */
73 static chunk_t *chunk_search(chunk_t *cur, const check_t check_fct, const scope_e scope = scope_e::ALL, const direction_e dir = direction_e::FORWARD, const bool cond = true);
74
75
76 /**
77 * @brief search for a chunk that satisfies a condition in a chunk list.
78 *
79 * This function is similar to chunk_search, except that it is tweaked to
80 * handle searches inside of preprocessor directives. Specifically, if the
81 * starting token is inside a preprocessor directive, it will ignore a line
82 * continuation, and will abort the search if it reaches the end of the
83 * directive. This function only searches forward.
84 *
85 * @param cur chunk to start search at
86 * @param check_fct compare function
87 * @param scope code parts to consider for search
88 * @param cond success condition
89 *
90 * @retval nullptr no requested chunk was found or invalid parameters provided
91 * @retval chunk_t pointer to the found chunk or pointer to the chunk at the
92 * end of the preprocessor directive
93 */
94 static chunk_t *chunk_ppa_search(chunk_t *cur, const check_t check_fct, const bool cond = true);
95
96
97 static void chunk_log(chunk_t *pc, const char *text);
98
99
100 /*
101 * TODO: if we use C++ we can overload the following two functions
102 * and thus name them equally
103 */
104
105 /**
106 * @brief search a chunk of a given category in a chunk list
107 *
108 * traverses a chunk list either in forward or backward direction.
109 * The traversal continues until a chunk of a given category is found.
110 *
111 * This function is a specialization of chunk_search.
112 *
113 * @param cur chunk to start search at
114 * @param type category to search for
115 * @param scope code parts to consider for search
116 * @param dir search direction
117 *
118 * @retval nullptr no chunk found or invalid parameters provided
119 * @retval chunk_t pointer to the found chunk
120 */
121 static chunk_t *chunk_search_type(chunk_t *cur, const c_token_t type, const scope_e scope = scope_e::ALL, const direction_e dir = direction_e::FORWARD);
122
123
124 /**
125 * @brief search a chunk of a given type and level
126 *
127 * Traverses a chunk list in the specified direction until a chunk of a given type
128 * is found.
129 *
130 * This function is a specialization of chunk_search.
131 *
132 * @param cur chunk to start search at
133 * @param type category to search for
134 * @param scope code parts to consider for search
135 * @param dir search direction
136 * @param level nesting level to match or -1 / ANY_LEVEL
137 *
138 * @retval nullptr no chunk found or invalid parameters provided
139 * @retval chunk_t pointer to the found chunk
140 */
141 static chunk_t *chunk_search_typelevel(chunk_t *cur, c_token_t type, scope_e scope = scope_e::ALL, direction_e dir = direction_e::FORWARD, int level = -1);
142
143
144 /**
145 * @brief searches a chunk that holds a specific string
146 *
147 * Traverses a chunk list either in forward or backward direction until a chunk
148 * with the provided string was found. Additionally a nesting level can be
149 * provided to narrow down the search.
150 *
151 * @param cur chunk to start search at
152 * @param str string that searched chunk needs to have
153 * @param len length of the string
154 * @param scope code parts to consider for search
155 * @param dir search direction
156 * @param level nesting level of the searched chunk, ignored when negative
157 *
158 * @retval NULL no chunk found or invalid parameters provided
159 * @retval chunk_t pointer to the found chunk
160 */
161 static chunk_t *chunk_search_str(chunk_t *cur, const char *str, size_t len, scope_e scope, direction_e dir, int level);
162
163
164 /**
165 * @brief Add a new chunk before/after the given position in a chunk list
166 *
167 * If ref is nullptr, add either at the head or tail based on the specified pos
168 *
169 * @param pc_in chunk to add to list
170 * @param ref insert position in list
171 * @param pos insert before or after
172 *
173 * @return chunk_t pointer to the added chunk
174 */
175 static chunk_t *chunk_add(const chunk_t *pc_in, chunk_t *ref, const direction_e pos = direction_e::FORWARD);
176
177
178 /**
179 * @brief Determines which chunk search function to use
180 *
181 * Depending on the required search direction return a pointer
182 * to the corresponding chunk search function.
183 *
184 * @param dir search direction
185 *
186 * @return pointer to chunk search function
187 */
188 static search_t select_search_fct(const direction_e dir = direction_e::FORWARD);
189
190
191 ChunkList_t g_cl; //! global chunk list
192
193
chunk_get_head(void)194 chunk_t *chunk_get_head(void)
195 {
196 return(g_cl.GetHead());
197 }
198
199
chunk_get_tail(void)200 chunk_t *chunk_get_tail(void)
201 {
202 return(g_cl.GetTail());
203 }
204
205
select_search_fct(const direction_e dir)206 static search_t select_search_fct(const direction_e dir)
207 {
208 return((dir == direction_e::FORWARD) ? chunk_get_next : chunk_get_prev);
209 }
210
211
chunk_search_prev_cat(chunk_t * pc,const c_token_t cat)212 chunk_t *chunk_search_prev_cat(chunk_t *pc, const c_token_t cat)
213 {
214 return(chunk_search_type(pc, cat, scope_e::ALL, direction_e::BACKWARD));
215 }
216
217
chunk_search_next_cat(chunk_t * pc,const c_token_t cat)218 chunk_t *chunk_search_next_cat(chunk_t *pc, const c_token_t cat)
219 {
220 return(chunk_search_type(pc, cat, scope_e::ALL, direction_e::FORWARD));
221 }
222
223
are_chunks_in_same_line(chunk_t * start,chunk_t * end)224 bool are_chunks_in_same_line(chunk_t *start, chunk_t *end)
225 {
226 chunk_t *tmp;
227
228 if (start != nullptr)
229 {
230 tmp = chunk_get_next(start);
231 }
232 else
233 {
234 return(false);
235 }
236
237 while ( tmp != nullptr
238 && tmp != end)
239 {
240 if (chunk_is_token(tmp, CT_NEWLINE))
241 {
242 return(false);
243 }
244 tmp = chunk_get_next(tmp);
245 }
246 return(true);
247 }
248
249
chunk_search_type(chunk_t * cur,const c_token_t type,const scope_e scope,const direction_e dir)250 static chunk_t *chunk_search_type(chunk_t *cur, const c_token_t type,
251 const scope_e scope, const direction_e dir)
252 {
253 /*
254 * Depending on the parameter dir the search function searches
255 * in forward or backward direction
256 */
257 search_t search_function = select_search_fct(dir);
258 chunk_t *pc = cur;
259
260 do // loop over the chunk list
261 {
262 pc = search_function(pc, scope); // in either direction while
263 } while ( pc != nullptr // the end of the list was not reached yet
264 && pc->type != type); // and the demanded chunk was not found either
265
266 return(pc); // the latest chunk is the searched one
267 }
268
269
chunk_search_typelevel(chunk_t * cur,c_token_t type,scope_e scope,direction_e dir,int level)270 static chunk_t *chunk_search_typelevel(chunk_t *cur, c_token_t type, scope_e scope, direction_e dir, int level)
271 {
272 /*
273 * Depending on the parameter dir the search function searches
274 * in forward or backward direction
275 */
276 search_t search_function = select_search_fct(dir);
277 chunk_t *pc = cur;
278
279 do // loop over the chunk list
280 {
281 pc = search_function(pc, scope); // in either direction while
282 } while ( pc != nullptr // the end of the list was not reached yet
283 && (!is_expected_type_and_level(pc, type, level)));
284
285 return(pc); // the latest chunk is the searched one
286 }
287
288
chunk_search_str(chunk_t * cur,const char * str,size_t len,scope_e scope,direction_e dir,int level)289 static chunk_t *chunk_search_str(chunk_t *cur, const char *str, size_t len, scope_e scope, direction_e dir, int level)
290 {
291 /*
292 * Depending on the parameter dir the search function searches
293 * in forward or backward direction */
294 search_t search_function = select_search_fct(dir);
295 chunk_t *pc = cur;
296
297 do // loop over the chunk list
298 {
299 pc = search_function(pc, scope); // in either direction while
300 } while ( pc != nullptr // the end of the list was not reached yet
301 && (!is_expected_string_and_level(pc, str, level, len)));
302
303 return(pc); // the latest chunk is the searched one
304 }
305
306
chunk_search(chunk_t * cur,const check_t check_fct,const scope_e scope,const direction_e dir,const bool cond)307 static chunk_t *chunk_search(chunk_t *cur, const check_t check_fct, const scope_e scope,
308 const direction_e dir, const bool cond)
309 {
310 /*
311 * Depending on the parameter dir the search function searches
312 * in forward or backward direction */
313 search_t search_function = select_search_fct(dir);
314 chunk_t *pc = cur;
315
316 do // loop over the chunk list
317 {
318 pc = search_function(pc, scope); // in either direction while
319 } while ( pc != nullptr // the end of the list was not reached yet
320 && (check_fct(pc) != cond)); // and the demanded chunk was not found either
321
322 return(pc); // the latest chunk is the searched one
323 }
324
325
chunk_ppa_search(chunk_t * cur,const check_t check_fct,const bool cond)326 static chunk_t *chunk_ppa_search(chunk_t *cur, const check_t check_fct, const bool cond)
327 {
328 if ( cur != nullptr
329 && !cur->flags.test(PCF_IN_PREPROC))
330 {
331 // if not in preprocessor, do a regular search
332 return(chunk_search(cur, check_fct, scope_e::ALL,
333 direction_e::FORWARD, cond));
334 }
335 chunk_t *pc = cur;
336
337 while ( pc != nullptr
338 && (pc = pc->next) != nullptr)
339 {
340 if (!pc->flags.test(PCF_IN_PREPROC))
341 {
342 // Bail if we run off the end of the preprocessor directive, but
343 // return the next token, NOT nullptr, because the caller may need to
344 // know where the search ended
345 assert(chunk_is_token(pc, CT_NEWLINE));
346 return(pc);
347 }
348
349 if (chunk_is_token(pc, CT_NL_CONT))
350 {
351 // Skip line continuation
352 continue;
353 }
354
355 if (check_fct(pc) == cond)
356 {
357 // Requested token was found
358 return(pc);
359 }
360 }
361 // Ran out of tokens
362 return(nullptr);
363 }
364
365
366 /* @todo maybe it is better to combine chunk_get_next and chunk_get_prev
367 * into a common function However this should be done with the preprocessor
368 * to avoid addition check conditions that would be evaluated in the
369 * while loop of the calling function */
chunk_get_next(chunk_t * cur,scope_e scope)370 chunk_t *chunk_get_next(chunk_t *cur, scope_e scope)
371 {
372 if (cur == nullptr)
373 {
374 return(nullptr);
375 }
376 chunk_t *pc = g_cl.GetNext(cur);
377
378 if ( pc == nullptr
379 || scope == scope_e::ALL)
380 {
381 return(pc);
382 }
383
384 if (cur->flags.test(PCF_IN_PREPROC))
385 {
386 // If in a preproc, return nullptr if trying to leave
387 if (!pc->flags.test(PCF_IN_PREPROC))
388 {
389 return(nullptr);
390 }
391 return(pc);
392 }
393
394 // Not in a preproc, skip any preproc
395 while ( pc != nullptr
396 && pc->flags.test(PCF_IN_PREPROC))
397 {
398 pc = g_cl.GetNext(pc);
399 }
400 return(pc);
401 }
402
403
chunk_get_prev(chunk_t * cur,scope_e scope)404 chunk_t *chunk_get_prev(chunk_t *cur, scope_e scope)
405 {
406 if (cur == nullptr)
407 {
408 return(nullptr);
409 }
410 chunk_t *pc = g_cl.GetPrev(cur);
411
412 if ( pc == nullptr
413 || scope == scope_e::ALL)
414 {
415 return(pc);
416 }
417
418 if (cur->flags.test(PCF_IN_PREPROC))
419 {
420 // If in a preproc, return NULL if trying to leave
421 if (!pc->flags.test(PCF_IN_PREPROC))
422 {
423 return(nullptr);
424 }
425 return(pc);
426 }
427
428 // Not in a preproc, skip any preproc
429 while ( pc != nullptr
430 && pc->flags.test(PCF_IN_PREPROC))
431 {
432 pc = g_cl.GetPrev(pc);
433 }
434 return(pc);
435 }
436
437
chunk_dup(const chunk_t * pc_in)438 chunk_t *chunk_dup(const chunk_t *pc_in)
439 {
440 chunk_t *pc = new chunk_t; // Allocate a new chunk
441
442 if (pc == nullptr)
443 {
444 // @todo clean up properly before crashing
445 LOG_FMT(LERR, "Failed to allocate memory\n");
446 log_func_stack_inline(LSETFLG);
447 log_flush(true);
448 exit(EXIT_FAILURE);
449 }
450 // Copy all fields and then init the entry
451 *pc = *pc_in; // TODO: what happens if pc_in == nullptr?
452 g_cl.InitEntry(pc);
453
454 return(pc);
455 }
456
457
chunk_log_msg(chunk_t * chunk,const log_sev_t log,const char * str)458 static void chunk_log_msg(chunk_t *chunk, const log_sev_t log, const char *str)
459 {
460 LOG_FMT(log, "%s orig_line is %zu, orig_col is %zu, ",
461 str, chunk->orig_line, chunk->orig_col);
462
463 if (chunk_is_token(chunk, CT_NEWLINE))
464 {
465 LOG_FMT(log, "<Newline>,\n");
466 }
467 else if (chunk_is_token(chunk, CT_VBRACE_OPEN))
468 {
469 LOG_FMT(log, "<VBRACE_OPEN>,\n");
470 }
471 else if (chunk_is_token(chunk, CT_VBRACE_CLOSE))
472 {
473 LOG_FMT(log, "<VBRACE_CLOSE>,\n");
474 }
475 else
476 {
477 LOG_FMT(log, "text() is '%s', type is %s,\n", chunk->text(), get_token_name(chunk->type));
478 }
479 }
480
481
chunk_log(chunk_t * pc,const char * text)482 static void chunk_log(chunk_t *pc, const char *text)
483 {
484 if ( pc != nullptr
485 && (cpd.unc_stage != unc_stage_e::TOKENIZE)
486 && (cpd.unc_stage != unc_stage_e::CLEANUP))
487 {
488 const log_sev_t log = LCHUNK;
489 chunk_t *prev = chunk_get_prev(pc);
490 chunk_t *next = chunk_get_next(pc);
491
492 chunk_log_msg(pc, log, text);
493
494 if ( prev != nullptr
495 && next != nullptr)
496 {
497 chunk_log_msg(prev, log, " @ between");
498 chunk_log_msg(next, log, " and");
499 }
500 else if (next != nullptr)
501 {
502 chunk_log_msg(next, log, " @ before");
503 }
504 else if (prev != nullptr)
505 {
506 chunk_log_msg(prev, log, " @ after");
507 }
508 LOG_FMT(log, " stage is %s", // Issue #3034
509 get_unc_stage_name(cpd.unc_stage));
510 log_func_stack_inline(log);
511 }
512 }
513
514
chunk_add_after(const chunk_t * pc_in,chunk_t * ref)515 chunk_t *chunk_add_after(const chunk_t *pc_in, chunk_t *ref)
516 {
517 return(chunk_add(pc_in, ref, direction_e::FORWARD));
518 }
519
520
chunk_add_before(const chunk_t * pc_in,chunk_t * ref)521 chunk_t *chunk_add_before(const chunk_t *pc_in, chunk_t *ref)
522 {
523 return(chunk_add(pc_in, ref, direction_e::BACKWARD));
524 }
525
526
chunk_del(chunk_t * & pc)527 void chunk_del(chunk_t * &pc)
528 {
529 g_cl.Pop(pc);
530 delete pc;
531 pc = nullptr;
532 }
533
534
chunk_move_after(chunk_t * pc_in,chunk_t * ref)535 void chunk_move_after(chunk_t *pc_in, chunk_t *ref)
536 {
537 LOG_FUNC_ENTRY();
538 g_cl.Pop(pc_in);
539 g_cl.AddAfter(pc_in, ref);
540
541 // HACK: Adjust the original column
542 pc_in->column = ref->column + space_col_align(ref, pc_in);
543 pc_in->orig_col = pc_in->column;
544 pc_in->orig_col_end = pc_in->orig_col + pc_in->len();
545 }
546
547
chunk_get_next_nl(chunk_t * cur,scope_e scope)548 chunk_t *chunk_get_next_nl(chunk_t *cur, scope_e scope)
549 {
550 return(chunk_search(cur, chunk_is_newline, scope, direction_e::FORWARD, true));
551 }
552
553
chunk_get_prev_nl(chunk_t * cur,scope_e scope)554 chunk_t *chunk_get_prev_nl(chunk_t *cur, scope_e scope)
555 {
556 return(chunk_search(cur, chunk_is_newline, scope, direction_e::BACKWARD, true));
557 }
558
559
chunk_get_next_nnl(chunk_t * cur,scope_e scope)560 chunk_t *chunk_get_next_nnl(chunk_t *cur, scope_e scope)
561 {
562 return(chunk_search(cur, chunk_is_newline, scope, direction_e::FORWARD, false));
563 }
564
565
chunk_get_prev_nnl(chunk_t * cur,scope_e scope)566 chunk_t *chunk_get_prev_nnl(chunk_t *cur, scope_e scope)
567 {
568 return(chunk_search(cur, chunk_is_newline, scope, direction_e::BACKWARD, false));
569 }
570
571
chunk_get_next_ncnnl(chunk_t * cur,scope_e scope)572 chunk_t *chunk_get_next_ncnnl(chunk_t *cur, scope_e scope)
573 {
574 return(chunk_search(cur, chunk_is_comment_or_newline, scope, direction_e::FORWARD, false));
575 }
576
577
chunk_get_prev_ncnnl(chunk_t * cur,scope_e scope)578 chunk_t *chunk_get_prev_ncnnl(chunk_t *cur, scope_e scope)
579 {
580 return(chunk_search(cur, chunk_is_comment_or_newline, scope, direction_e::BACKWARD, false));
581 }
582
583
chunk_get_next_ncnnlnp(chunk_t * cur,scope_e scope)584 chunk_t *chunk_get_next_ncnnlnp(chunk_t *cur, scope_e scope)
585 {
586 return(chunk_search(cur, chunk_is_comment_newline_or_preproc, scope, direction_e::FORWARD, false));
587 }
588
589
chunk_get_prev_ncnnlnp(chunk_t * cur,scope_e scope)590 chunk_t *chunk_get_prev_ncnnlnp(chunk_t *cur, scope_e scope)
591 {
592 return(chunk_search(cur, chunk_is_comment_newline_or_preproc, scope, direction_e::BACKWARD, false));
593 }
594
595
chunk_get_next_ncnnl_in_pp(chunk_t * cur,scope_e scope)596 chunk_t *chunk_get_next_ncnnl_in_pp(chunk_t *cur, scope_e scope)
597 {
598 return(chunk_search(cur, chunk_is_comment_or_newline_in_preproc, scope, direction_e::FORWARD, false));
599 }
600
601
chunk_get_prev_ncnnl_in_pp(chunk_t * cur,scope_e scope)602 chunk_t *chunk_get_prev_ncnnl_in_pp(chunk_t *cur, scope_e scope)
603 {
604 return(chunk_search(cur, chunk_is_comment_or_newline_in_preproc, scope, direction_e::BACKWARD, false));
605 }
606
607
chunk_ppa_get_next_ncnnl(chunk_t * cur)608 chunk_t *chunk_ppa_get_next_ncnnl(chunk_t *cur)
609 {
610 return(chunk_ppa_search(cur, chunk_is_comment_or_newline, false));
611 }
612
613
chunk_get_next_nblank(chunk_t * cur,scope_e scope)614 chunk_t *chunk_get_next_nblank(chunk_t *cur, scope_e scope)
615 {
616 return(chunk_search(cur, chunk_is_comment_newline_or_blank, scope, direction_e::FORWARD, false));
617 }
618
619
chunk_get_prev_nblank(chunk_t * cur,scope_e scope)620 chunk_t *chunk_get_prev_nblank(chunk_t *cur, scope_e scope)
621 {
622 return(chunk_search(cur, chunk_is_comment_newline_or_blank, scope, direction_e::BACKWARD, false));
623 }
624
625
chunk_get_next_nc(chunk_t * cur,scope_e scope)626 chunk_t *chunk_get_next_nc(chunk_t *cur, scope_e scope)
627 {
628 return(chunk_search(cur, chunk_is_comment, scope, direction_e::FORWARD, false));
629 }
630
631
chunk_get_prev_nc(chunk_t * cur,scope_e scope)632 chunk_t *chunk_get_prev_nc(chunk_t *cur, scope_e scope)
633 {
634 return(chunk_search(cur, chunk_is_comment, scope, direction_e::BACKWARD, false));
635 }
636
637
chunk_get_next_nisq(chunk_t * cur,scope_e scope)638 chunk_t *chunk_get_next_nisq(chunk_t *cur, scope_e scope)
639 {
640 return(chunk_search(cur, chunk_is_balanced_square, scope, direction_e::FORWARD, false));
641 }
642
643
chunk_get_prev_ncnnlni(chunk_t * cur,scope_e scope)644 chunk_t *chunk_get_prev_ncnnlni(chunk_t *cur, scope_e scope)
645 {
646 return(chunk_search(cur, chunk_is_comment_or_newline_or_ignored, scope, direction_e::BACKWARD, false));
647 }
648
649
chunk_get_next_type(chunk_t * cur,c_token_t type,int level,scope_e scope)650 chunk_t *chunk_get_next_type(chunk_t *cur, c_token_t type, int level, scope_e scope)
651 {
652 return(chunk_search_typelevel(cur, type, scope, direction_e::FORWARD, level));
653 }
654
655
chunk_get_prev_type(chunk_t * cur,c_token_t type,int level,scope_e scope)656 chunk_t *chunk_get_prev_type(chunk_t *cur, c_token_t type, int level, scope_e scope)
657 {
658 return(chunk_search_typelevel(cur, type, scope, direction_e::BACKWARD, level));
659 }
660
661
chunk_get_next_str(chunk_t * cur,const char * str,size_t len,int level,scope_e scope)662 chunk_t *chunk_get_next_str(chunk_t *cur, const char *str, size_t len, int level, scope_e scope)
663 {
664 return(chunk_search_str(cur, str, len, scope, direction_e::FORWARD, level));
665 }
666
667
chunk_get_prev_str(chunk_t * cur,const char * str,size_t len,int level,scope_e scope)668 chunk_t *chunk_get_prev_str(chunk_t *cur, const char *str, size_t len, int level, scope_e scope)
669 {
670 return(chunk_search_str(cur, str, len, scope, direction_e::BACKWARD, level));
671 }
672
673
chunk_is_newline_between(chunk_t * start,chunk_t * end)674 bool chunk_is_newline_between(chunk_t *start, chunk_t *end)
675 {
676 for (chunk_t *pc = start; pc != end; pc = chunk_get_next(pc))
677 {
678 if (chunk_is_newline(pc))
679 {
680 return(true);
681 }
682 }
683
684 return(false);
685 }
686
687
chunk_swap(chunk_t * pc1,chunk_t * pc2)688 void chunk_swap(chunk_t *pc1, chunk_t *pc2)
689 {
690 g_cl.Swap(pc1, pc2);
691 }
692
693
694 // TODO: the following function shall be made similar to the search functions
chunk_first_on_line(chunk_t * pc)695 chunk_t *chunk_first_on_line(chunk_t *pc)
696 {
697 chunk_t *first = pc;
698
699 while ( (pc = chunk_get_prev(pc)) != nullptr
700 && !chunk_is_newline(pc))
701 {
702 first = pc;
703 }
704 return(first);
705 }
706
707
chunk_is_last_on_line(chunk_t & pc)708 bool chunk_is_last_on_line(chunk_t &pc) //TODO: pc should be const here
709 {
710 // check if pc is the very last chunk of the file
711 const auto *end = chunk_get_tail();
712
713 if (&pc == end)
714 {
715 return(true);
716 }
717 // if the next chunk is a newline then pc is the last chunk on its line
718 const auto *next = chunk_get_next(&pc);
719
720 if (chunk_is_token(next, CT_NEWLINE))
721 {
722 return(true);
723 }
724 return(false);
725 }
726
727
728 // TODO: this function needs some cleanup
chunk_swap_lines(chunk_t * pc1,chunk_t * pc2)729 void chunk_swap_lines(chunk_t *pc1, chunk_t *pc2)
730 {
731 // to swap lines we need to find the first chunk of the lines
732 pc1 = chunk_first_on_line(pc1);
733 pc2 = chunk_first_on_line(pc2);
734
735 if ( pc1 == nullptr
736 || pc2 == nullptr
737 || pc1 == pc2)
738 {
739 return;
740 }
741 /*
742 * Example start:
743 * ? - start1 - a1 - b1 - nl1 - ? - ref2 - start2 - a2 - b2 - nl2 - ?
744 * ^- pc1 ^- pc2
745 */
746 chunk_t *ref2 = chunk_get_prev(pc2);
747
748 // Move the line started at pc2 before pc1
749 while ( pc2 != nullptr
750 && !chunk_is_newline(pc2))
751 {
752 chunk_t *tmp = chunk_get_next(pc2);
753 g_cl.Pop(pc2);
754 g_cl.AddBefore(pc2, pc1);
755 pc2 = tmp;
756 }
757 /*
758 * Should now be:
759 * ? - start2 - a2 - b2 - start1 - a1 - b1 - nl1 - ? - ref2 - nl2 - ?
760 * ^- pc1 ^- pc2
761 */
762
763 // Now move the line started at pc1 after ref2
764 while ( pc1 != nullptr
765 && !chunk_is_newline(pc1))
766 {
767 chunk_t *tmp = chunk_get_next(pc1);
768 g_cl.Pop(pc1);
769
770 if (ref2 != nullptr)
771 {
772 g_cl.AddAfter(pc1, ref2);
773 }
774 else
775 {
776 g_cl.AddHead(pc1);
777 }
778 ref2 = pc1;
779 pc1 = tmp;
780 }
781 /*
782 * Should now be:
783 * ? - start2 - a2 - b2 - nl1 - ? - ref2 - start1 - a1 - b1 - nl2 - ?
784 * ^- pc1 ^- pc2
785 */
786
787 /*
788 * pc1 and pc2 should be the newlines for their lines.
789 * swap the chunks and the nl_count so that the spacing remains the same.
790 */
791 if ( pc1 != nullptr
792 && pc2 != nullptr)
793 {
794 size_t nl_count = pc1->nl_count;
795
796 pc1->nl_count = pc2->nl_count;
797 pc2->nl_count = nl_count;
798
799 chunk_swap(pc1, pc2);
800 }
801 } // chunk_swap_lines
802
803
chunk_get_next_nvb(chunk_t * cur,const scope_e scope)804 chunk_t *chunk_get_next_nvb(chunk_t *cur, const scope_e scope)
805 {
806 return(chunk_search(cur, chunk_is_vbrace, scope, direction_e::FORWARD, false));
807 }
808
809
chunk_get_prev_nvb(chunk_t * cur,const scope_e scope)810 chunk_t *chunk_get_prev_nvb(chunk_t *cur, const scope_e scope)
811 {
812 return(chunk_search(cur, chunk_is_vbrace, scope, direction_e::BACKWARD, false));
813 }
814
815
chunk_flags_set_real(chunk_t * pc,pcf_flags_t clr_bits,pcf_flags_t set_bits)816 void chunk_flags_set_real(chunk_t *pc, pcf_flags_t clr_bits, pcf_flags_t set_bits)
817 {
818 if (pc != nullptr)
819 {
820 LOG_FUNC_ENTRY();
821 auto const nflags = (pc->flags & ~clr_bits) | set_bits;
822
823 if (pc->flags != nflags)
824 {
825 LOG_FMT(LSETFLG,
826 "%s(%d): %016llx^%016llx=%016llx\n"
827 " orig_line is %zu, orig_col is %zu, text() '%s', type is %s,",
828 __func__, __LINE__,
829 static_cast<pcf_flags_t::int_t>(pc->flags),
830 static_cast<pcf_flags_t::int_t>(pc->flags ^ nflags),
831 static_cast<pcf_flags_t::int_t>(nflags),
832 pc->orig_line, pc->orig_col, pc->text(),
833 get_token_name(pc->type));
834 LOG_FMT(LSETFLG, " parent_type is %s,\n ",
835 get_token_name(get_chunk_parent_type(pc)));
836 log_func_stack_inline(LSETFLG);
837 pc->flags = nflags;
838 }
839 }
840 }
841
842
set_chunk_type_real(chunk_t * pc,c_token_t token,const char * func,int line)843 void set_chunk_type_real(chunk_t *pc, c_token_t token, const char *func, int line)
844 {
845 LOG_FUNC_ENTRY();
846
847 if ( pc == nullptr
848 || pc->type == token)
849 {
850 return;
851 }
852 LOG_FMT(LSETTYP, "%s(%d): orig_line is %zu, orig_col is %zu, pc->text() ",
853 func, line, pc->orig_line, pc->orig_col);
854
855 if (token == CT_NEWLINE)
856 {
857 LOG_FMT(LSETTYP, "<Newline>\n");
858 }
859 else
860 {
861 LOG_FMT(LSETTYP, "'%s'\n", pc->text());
862 }
863 LOG_FMT(LSETTYP, " pc->type is %s, pc->parent_type is %s => *type is %s, *parent_type is %s\n",
864 get_token_name(pc->type), get_token_name(get_chunk_parent_type(pc)),
865 get_token_name(token), get_token_name(get_chunk_parent_type(pc)));
866 pc->type = token;
867 } // set_chunk_type_real
868
869
set_chunk_parent_real(chunk_t * pc,c_token_t token,const char * func,int line)870 void set_chunk_parent_real(chunk_t *pc, c_token_t token, const char *func, int line)
871 {
872 LOG_FUNC_ENTRY();
873
874 if ( pc == nullptr
875 || get_chunk_parent_type(pc) == token)
876 {
877 return;
878 }
879 LOG_FMT(LSETPAR, "%s(%d): orig_line is %zu, orig_col is %zu, pc->text() ",
880 func, line, pc->orig_line, pc->orig_col);
881
882 if (token == CT_NEWLINE)
883 {
884 LOG_FMT(LSETPAR, "<Newline>\n");
885 }
886 else
887 {
888 char copy[1000];
889 LOG_FMT(LSETPAR, "'%s'\n", pc->elided_text(copy));
890 }
891 LOG_FMT(LSETPAR, " pc->type is %s, pc->parent_type is %s => *type is %s, *parent_type is %s\n",
892 get_token_name(pc->type), get_token_name(get_chunk_parent_type(pc)),
893 get_token_name(token), get_token_name(get_chunk_parent_type(pc)));
894 pc->parent_type = token;
895 } // set_chunk_parent_real
896
897
get_chunk_parent_type(chunk_t * pc)898 c_token_t get_chunk_parent_type(chunk_t *pc)
899 {
900 LOG_FUNC_ENTRY();
901
902 if (pc == nullptr)
903 {
904 return(CT_NONE);
905 }
906 return(pc->parent_type);
907 } // get_chunk_parent_type
908
909
chunk_add(const chunk_t * pc_in,chunk_t * ref,const direction_e pos)910 static chunk_t *chunk_add(const chunk_t *pc_in, chunk_t *ref, const direction_e pos)
911 {
912 #ifdef DEBUG
913 // test if the pc_in chunk is properly set
914 if (pc_in->pp_level == 999)
915 {
916 fprintf(stderr, "%s(%d): pp_level is not set\n", __func__, __LINE__);
917 log_func_stack_inline(LSETFLG);
918 log_flush(true);
919 exit(EX_SOFTWARE);
920 }
921
922 if (pc_in->orig_line == 0)
923 {
924 fprintf(stderr, "%s(%d): no line number\n", __func__, __LINE__);
925 log_func_stack_inline(LSETFLG);
926 log_flush(true);
927 exit(EX_SOFTWARE);
928 }
929
930 if (pc_in->orig_col == 0)
931 {
932 fprintf(stderr, "%s(%d): no column number\n", __func__, __LINE__);
933 log_func_stack_inline(LSETFLG);
934 log_flush(true);
935 exit(EX_SOFTWARE);
936 }
937 #endif /* DEBUG */
938
939 chunk_t *pc = chunk_dup(pc_in);
940
941 if (pc != nullptr)
942 {
943 if (ref != nullptr) // ref is a valid chunk
944 {
945 (pos == direction_e::FORWARD) ? g_cl.AddAfter(pc, ref) : g_cl.AddBefore(pc, ref);
946 }
947 else // ref == NULL
948 {
949 (pos == direction_e::FORWARD) ? g_cl.AddHead(pc) : g_cl.AddTail(pc);
950 }
951 chunk_log(pc, "chunk_add(A):");
952 }
953 return(pc);
954 } // chunk_add
955
956
chunk_get_next_ssq(chunk_t * cur)957 chunk_t *chunk_get_next_ssq(chunk_t *cur)
958 {
959 while ( chunk_is_token(cur, CT_TSQUARE)
960 || chunk_is_token(cur, CT_SQUARE_OPEN))
961 {
962 if (chunk_is_token(cur, CT_SQUARE_OPEN))
963 {
964 cur = chunk_skip_to_match(cur);
965 }
966 cur = chunk_get_next_ncnnl(cur);
967 }
968 return(cur);
969 }
970
971
chunk_get_prev_ssq(chunk_t * cur)972 chunk_t *chunk_get_prev_ssq(chunk_t *cur)
973 {
974 while ( chunk_is_token(cur, CT_TSQUARE)
975 || chunk_is_token(cur, CT_SQUARE_CLOSE))
976 {
977 if (chunk_is_token(cur, CT_SQUARE_CLOSE))
978 {
979 cur = chunk_skip_to_match_rev(cur);
980 }
981 cur = chunk_get_prev_ncnnl(cur);
982 }
983 return(cur);
984 }
985
986
chunk_get_pp_start(chunk_t * cur)987 chunk_t *chunk_get_pp_start(chunk_t *cur)
988 {
989 if (!chunk_is_preproc(cur))
990 {
991 return(nullptr);
992 }
993
994 while (!chunk_is_token(cur, CT_PREPROC))
995 {
996 cur = chunk_get_prev(cur, scope_e::PREPROC);
997 }
998 return(cur);
999 }
1000
1001
1002 //! skip to the final word/type in a :: chain
chunk_skip_dc_member(chunk_t * start,scope_e scope,direction_e dir)1003 static chunk_t *chunk_skip_dc_member(chunk_t *start, scope_e scope, direction_e dir)
1004 {
1005 LOG_FUNC_ENTRY();
1006
1007 if (start == nullptr)
1008 {
1009 return(nullptr);
1010 }
1011 const auto step_fcn = (dir == direction_e::FORWARD)
1012 ? chunk_get_next_ncnnl : chunk_get_prev_ncnnl;
1013
1014 chunk_t *pc = start;
1015 chunk_t *next = chunk_is_token(pc, CT_DC_MEMBER) ? pc : step_fcn(pc, scope);
1016
1017 while (chunk_is_token(next, CT_DC_MEMBER))
1018 {
1019 pc = step_fcn(next, scope);
1020
1021 if (pc == nullptr)
1022 {
1023 return(nullptr);
1024 }
1025 next = step_fcn(pc, scope);
1026 }
1027 return(pc);
1028 }
1029
1030
chunk_skip_dc_member(chunk_t * start,scope_e scope)1031 chunk_t *chunk_skip_dc_member(chunk_t *start, scope_e scope)
1032 {
1033 return(chunk_skip_dc_member(start, scope, direction_e::FORWARD));
1034 }
1035
1036
chunk_skip_dc_member_rev(chunk_t * start,scope_e scope)1037 chunk_t *chunk_skip_dc_member_rev(chunk_t *start, scope_e scope)
1038 {
1039 return(chunk_skip_dc_member(start, scope, direction_e::BACKWARD));
1040 }
1041
1042
1043 // set parent member
chunk_set_parent(chunk_t * pc,chunk_t * parent)1044 void chunk_set_parent(chunk_t *pc, chunk_t *parent)
1045 {
1046 if (pc == nullptr)
1047 {
1048 return;
1049 }
1050
1051 if (parent == nullptr)
1052 {
1053 return;
1054 }
1055
1056 if (pc == parent)
1057 {
1058 return;
1059 }
1060 pc->parent = parent;
1061 }
1062
1063
get_type_of_the_parent(chunk_t * pc)1064 c_token_t get_type_of_the_parent(chunk_t *pc)
1065 {
1066 if (pc == nullptr)
1067 {
1068 return(CT_UNKNOWN);
1069 }
1070
1071 if (pc->parent == nullptr)
1072 {
1073 return(CT_PARENT_NOT_SET);
1074 }
1075 return(pc->parent->type);
1076 }
1077
1078
chunk_is_attribute_or_declspec(chunk_t * pc)1079 bool chunk_is_attribute_or_declspec(chunk_t *pc)
1080 {
1081 return( language_is_set(LANG_CPP)
1082 && ( chunk_is_token(pc, CT_ATTRIBUTE)
1083 || chunk_is_token(pc, CT_DECLSPEC)));
1084 }
1085
1086
chunk_is_class_enum_struct_union(chunk_t * pc)1087 bool chunk_is_class_enum_struct_union(chunk_t *pc)
1088 {
1089 return( chunk_is_class_or_struct(pc)
1090 || chunk_is_enum(pc)
1091 || chunk_is_token(pc, CT_UNION));
1092 }
1093
1094
chunk_is_class_or_struct(chunk_t * pc)1095 bool chunk_is_class_or_struct(chunk_t *pc)
1096 {
1097 return( chunk_is_token(pc, CT_CLASS)
1098 || chunk_is_token(pc, CT_STRUCT));
1099 }
1100
1101
chunk_is_class_struct_union(chunk_t * pc)1102 bool chunk_is_class_struct_union(chunk_t *pc)
1103 {
1104 return( chunk_is_class_or_struct(pc)
1105 || chunk_is_token(pc, CT_UNION));
1106 }
1107
1108
chunk_is_enum(chunk_t * pc)1109 bool chunk_is_enum(chunk_t *pc)
1110 {
1111 return( chunk_is_token(pc, CT_ENUM)
1112 || chunk_is_token(pc, CT_ENUM_CLASS));
1113 }
1114
1115
chunk_compare_position(const chunk_t * A_token,const chunk_t * B_token)1116 int chunk_compare_position(const chunk_t *A_token, const chunk_t *B_token)
1117 {
1118 if (A_token == nullptr)
1119 {
1120 assert(A_token);
1121 }
1122
1123 if (B_token == nullptr)
1124 {
1125 assert(B_token);
1126 }
1127
1128 if (A_token->orig_line < B_token->orig_line)
1129 {
1130 return(-1);
1131 }
1132 else if (A_token->orig_line == B_token->orig_line)
1133 {
1134 if (A_token->orig_col < B_token->orig_col)
1135 {
1136 return(-1);
1137 }
1138 else if (A_token->orig_col == B_token->orig_col)
1139 {
1140 return(0);
1141 }
1142 }
1143 return(1);
1144 }
1145