struct hl_line_attr *hl_regex_highlight(struct hl_regex_info **info, char *line, enum hl_group_kind group_kind) { hl_line_attr *attrs = NULL; if (*info && (*info)->regex && (*info)->regex[0]) { int pos = 0; for (;;) { int ret; int len; int start, end; ret = hl_regex_search(info, line + pos, (*info)->regex, (*info)->icase, &start, &end); if (ret <= 0) break; len = end - start; pos += start; /* Push search attribute */ sbpush(attrs, hl_line_attr(pos, group_kind)); /* And the back to regular text attribute */ sbpush(attrs, hl_line_attr(pos + len, 0)); pos += len; } } return attrs; }
static char *detab_buffer(char *buffer, int tabstop) { int i; int dst = 0; char *newbuf = NULL; int size = sbcount(buffer); char *tab = strchr(buffer, '\t'); if (!tab) return buffer; for (i = 0; i < size; i++) { if (buffer[i] == '\t') { int spaces = tabstop - dst % tabstop; while(spaces--) { sbpush(newbuf, ' '); dst++; } } else { sbpush(newbuf, buffer[i]); dst++; } if (buffer[i] == '\n' || buffer[i] == '\r') dst = 0; } sbfree(buffer); return newbuf; }
void source_add_disasm_line(struct list_node *node, const char *line) { uint64_t addr = 0; struct source_line sline; char *colon = 0, colon_char = 0; sline.line = NULL; sbsetcount(sline.line, strlen(line) + 1); strcpy(sline.line, line); sline.line = detab_buffer(sline.line, node->file_buf.tabstop); sline.attrs = NULL; sline.len = sbcount(sline.line); colon = strchr((char*)line, ':'); if (colon) { colon_char = *colon; *colon = 0; } cgdb_hexstr_to_u64(line, &addr); if (colon) { *colon = colon_char; } sbpush(node->file_buf.addrs, addr); struct line_flags lf = { 0, 0 }; sbpush(node->file_buf.lines, sline); sbpush(node->lflags, lf); }
static int lua_cwd(lua_State *L) { #ifdef _WIN32 char drv[2]; int l; SB sb; sbinit(&sb); drv[0] = '.'; drv[1] = 0; l = GetFullPathNameA(drv, sb.maxlen, sb.buffer, 0); if (l > sb.maxlen) { sbgrow(&sb, l+1); l = GetFullPathNameA(drv, sb.maxlen, sb.buffer, 0); } if (l <= 0) return sbsetpush(L, &sb, "."); sb.len += l; return sbpush(L, &sb); #elif HAVE_GETCWD const char *s; SB sb; sbinit(&sb); s = getcwd(sb.buffer, sb.maxlen); while (!s && errno==ERANGE) { sbgrow(&sb, sb.maxlen + SBINCREMENT); s = getcwd(sb.buffer, sb.maxlen); } if (! s) return sbsetpush(L, &sb, "."); sb.len += strlen(s); return sbpush(L, &sb); #else const char *s; SB sb; sbinit(&sb); sbgrow(&sb, PATH_MAX); s = getwd(sb.buffer); if (! s) return sbsetpush(L, &sb, "."); sb.len += strlen(s); return sbpush(L, &sb); #endif }
static void scroller_addline(struct scroller *scr, char *line, struct hl_line_attr *attrs, enum ScrInputKind kind) { struct scroller_line sl; /* Add attribute from last inferior line to start of this one */ if (kind == SCR_INPUT_INFERIOR && (scr->last_inferior_attr != -1)) { /* If there isn't already a color attribute for the first column */ if (!attrs || (attrs[0].col() != 0)) { int count = sbcount(attrs); /* Bump the count up and scoot the attributes over one */ sbsetcount(attrs, count + 1); memmove(attrs+1, attrs, count * sizeof(struct hl_line_attr)); attrs[0] = hl_line_attr(0, scr->last_inferior_attr); } scr->last_inferior_attr = -1; } sl.line = line; sl.line_len = strlen(line); sl.kind = kind; sl.attrs = attrs; sbpush(scr->lines, sl); scr->lines_to_display++; scroller_set_last_inferior_attr(scr); }
int highlight_node(const char *filename, struct buffer *buf) { int ret; int length = 0; int lasttype = -1; struct ibuf *ibuf = ibuf_init(); struct tokenizer *t = tokenizer_init(); if (tokenizer_set_file(t, filename, buf->language) == -1) { if_print_message("%s:%d tokenizer_set_file error", __FILE__, __LINE__); return -1; } while ((ret = tokenizer_get_token(t)) > 0) { enum tokenizer_type e = tokenizer_get_packet_type(t); /*if_print_message ( "TOKEN(%d:%s)\n", e, tokenizer_get_printable_enum ( e ) ); */ if (e == TOKENIZER_NEWLINE) { sbpush(buf->tlines, strdup(ibuf_get(ibuf))); if (length > buf->max_width) buf->max_width = length; length = 0; lasttype = -1; ibuf_clear(ibuf); } else { const char *tok_data = tokenizer_get_data(t); enum hl_group_kind hlg = hlg_from_tokenizer_type(e, tok_data); if (hlg == HLG_LAST) { logger_write_pos(logger, __FILE__, __LINE__, "Bad hlg_type for '%s', e==%d\n", tok_data, e); hlg = HLG_TEXT; } /* Set the highlight group type */ add_type(ibuf, &lasttype, hlg); /* Add the text and bump our length */ length += ibuf_add(ibuf, tok_data); } } ibuf_free(ibuf); tokenizer_destroy(t); return 0; }
char *sys_quote_nonprintables(const char *str, int len) { int i; char *ret = NULL; if (len == -1) len = strlen(str); /* Nil terminate our return string */ sbpush(ret, 0); for (i = 0; i < len; ++i) { const char *ch = NULL; if (str[i] == '\r') ch = "\\r"; else if (str[i] == '\n') ch = "\\n"; else if (str[i] == '\032') ch = "\\032"; else if (str[i] == '\033') ch = "\\033"; else if (str[i] == '\b') ch = "\\b"; else if (str[i] == '\t') ch = "\\t"; if (ch) sbpushstrf(&ret, "(%s)", ch); else sbpushstr(&ret, &str[i], 1); } return ret; }
static int highlight_node(struct list_node *node) { int i; int ret; int line = 0; int length = 0; int lasttype = -1; struct token_data tok_data; struct tokenizer *t = tokenizer_init(); struct buffer *buf = &node->file_buf; for (i = 0; i < sbcount(buf->lines); i++) { sbfree(buf->lines[i].attrs); buf->lines[i].attrs = NULL; } if (!buf->file_data) { for (line = 0; line < sbcount(buf->lines); line++) { struct source_line *sline = &buf->lines[line]; tokenizer_set_buffer(t, sline->line, buf->language); length = 0; lasttype = -1; while ((ret = tokenizer_get_token(t, &tok_data)) > 0) { if (tok_data.e == TOKENIZER_NEWLINE) break; enum hl_group_kind hlg = hlg_from_tokenizer_type(tok_data.e, tok_data.data); /* Add attribute if highlight group has changed */ if (lasttype != hlg) { sbpush(buf->lines[line].attrs, hl_line_attr(length, hlg)); lasttype = hlg; } /* Add the text and bump our length */ length += strlen(tok_data.data); } } } else { if (tokenizer_set_buffer(t, buf->file_data, buf->language) == -1) { if_print_message("%s:%d tokenizer_set_buffer error", __FILE__, __LINE__); return -1; } while ((ret = tokenizer_get_token(t, &tok_data)) > 0) { if (tok_data.e == TOKENIZER_NEWLINE) { if (length > buf->max_width) buf->max_width = length; length = 0; lasttype = -1; line++; } else { enum hl_group_kind hlg = hlg_from_tokenizer_type(tok_data.e, tok_data.data); if (hlg == HLG_LAST) { clog_error(CLOG_CGDB, "Bad hlg_type for '%s', e==%d\n", tok_data.data, tok_data.e); hlg = HLG_TEXT; } /* Add attribute if highlight group has changed */ if (lasttype != hlg) { sbpush(buf->lines[line].attrs, hl_line_attr(length, hlg)); lasttype = hlg; } /* Add the text and bump our length */ length += strlen(tok_data.data); } } } tokenizer_destroy(t); return 0; }
/** * Load file and fill tlines line pointers. * * \param buf * struct buffer pointer * * \param filename * name of file to load * * \return * 0 on sucess, -1 on error */ static int load_file_buf(struct buffer *buf, const char *filename) { FILE *file; long file_size; int ret = -1; /* Special buffer not backed by file */ if (filename[0] == '*') return 0; file = fopen(filename, "rb"); if (!file) return -1; file_size = get_file_size(file); if (file_size > 0) { size_t bytes_read; /* Set the stretchy buffer size to our file size plus one for nil */ sbsetcount(buf->file_data, file_size + 1); /* Read in the entire file */ bytes_read = fread(buf->file_data, 1, file_size, file); /* If we had a partial read, bail */ if (bytes_read != file_size) { sbfree(buf->file_data); buf->file_data = NULL; fclose(file); return -1; } /* Zero terminate buffer */ buf->file_data[bytes_read] = 0; /* Convert tabs to spaces */ buf->tabstop = cgdbrc_get_int(CGDBRC_TABSTOP); buf->file_data = detab_buffer(buf->file_data, buf->tabstop); { char *line_start = buf->file_data; char *line_feed = strchr(line_start, '\n'); while (line_feed) { size_t line_len; char *line_end = line_feed; /* Trim trailing cr-lfs */ while (line_end >= line_start && (*line_end == '\n' || *line_end == '\r')) line_end--; /* Update max length string found */ line_len = line_end - line_start + 1; if (line_len > buf->max_width) buf->max_width = line_len; struct source_line sline; sline.line = line_start; sline.len = line_len; sline.attrs = NULL; /* Add this line to lines array */ sbpush(buf->lines, sline); line_start = line_feed + 1; line_feed = strchr(line_start, '\n'); } if (*line_start) { struct source_line sline; sline.line = line_start; sline.len = strlen(line_start); sline.attrs = NULL; sbpush(buf->lines, sline); } ret = 0; } } fclose(file); return ret; }
/* parse: Translates special characters in a string. (i.e. backspace, tab...) * ------ * * buf: The string to parse * * Return Value: A newly allocated copy of buf, with modifications made. */ static char *parse(struct scroller *scr, struct hl_line_attr **attrs, const char *orig, const char *buf, int buflen, enum ScrInputKind kind) { // Read in tabstop settings, but don't change them on the fly as we'd have to // store each previous line and recalculate every one of them. static const int tab_size = cgdbrc_get_int(CGDBRC_TABSTOP); int tabcount = count(buf, buflen, '\t'); int orig_len = strlen(orig); int length = MAX(orig_len, scr->current.pos) + buflen + (tab_size - 1) * tabcount + 1; char *rv = (char *) cgdb_calloc(length, 1); int i, j; int debugwincolor = cgdbrc_get_int(CGDBRC_DEBUGWINCOLOR); int width, height; height = swin_getmaxy(scr->win); width = swin_getmaxx(scr->win); /* Copy over original buffer */ strcpy(rv, orig); i = scr->current.pos; /* Expand special characters */ for (j = 0; j < buflen; j++) { switch (buf[j]) { /* Backspace/Delete -> Erase last character */ case 8: case 127: if (i > 0) i--; break; /* Tab -> Translating to spaces */ case '\t': do { rv[i++] = ' '; } while (i % tab_size != 0); break; /* Carriage return -> Move back to the beginning of the line */ case '\r': i = 0; if (buf[j + 1] != '\n') { sbfree(*attrs); *attrs = NULL; } break; case '\033': /* Handle ansi escape characters */ if (hl_ansi_color_support(hl_groups_instance) && debugwincolor) { int attr; int ansi_count = hl_ansi_get_color_attrs( hl_groups_instance, buf + j, &attr); if (ansi_count) { j += ansi_count - 1; sbpush(*attrs, hl_line_attr(i, attr)); } } else { rv[i++] = buf[j]; } break; default: rv[i++] = buf[j]; break; } } scr->current.pos = i; /** * The prompt should never be longer than the width of the terminal. * * The below should only be done for the readline prompt interaction, * not for text coming from gdb/inferior. Otherwise you'll truncate * their text in the scroller! * * When readline is working with the prompt (at least in "dumb" mode) * it assumes that the terminal will only display as many characters as * the terminal is wide. If the terminal is reduced in size (resized to a * smaller width) readline will only clear the number of characters * that will fit into the new terminal width. Our prompt may still * have a lot more characters than that (the characters that existed * in the prompt before the resize). This truncation of the prompt * is solving that problem. */ size_t rvlength = strlen(rv); if (kind == SCR_INPUT_READLINE && rvlength >= width) { rv[width - 1] = 0; } return rv; }
static void scr_add_buf(struct scroller *scr, const char *buf, enum ScrInputKind kind) { char *x; int distance; /* Find next newline in the string */ x = strchr((char *)buf, '\n'); distance = x ? x - buf : strlen(buf); /* Append to the last line in the buffer */ if (distance > 0) { int is_crlf = (distance == 1) && (buf[0] == '\r'); if (!is_crlf) { int index = sbcount(scr->lines) - 1; char *orig = scr->lines[index].line; int orig_len = scr->lines[index].line_len; if ((scr->last_inferior_attr != -1) && (kind != scr->lines[index].kind)) { /* Default to 0: Add that color attribute in */ int attr = 0; if (kind == SCR_INPUT_INFERIOR) { attr = scr->last_inferior_attr; scr->last_inferior_attr = -1; } sbpush(scr->lines[index].attrs, hl_line_attr(orig_len, attr)); } scr->lines[index].kind = kind; scr->lines[index].line = parse( scr, &scr->lines[index].attrs, orig, buf, distance, kind); scr->lines[index].line_len = strlen(scr->lines[index].line); scroller_set_last_inferior_attr(scr); free(orig); } } /* Create additional lines if buf contains newlines */ while (x != NULL) { char *line; struct hl_line_attr *attrs = NULL; buf = x + 1; x = strchr((char *)buf, '\n'); distance = x ? x - buf : strlen(buf); /* inferior input with no lf. */ if (!x && (kind == SCR_INPUT_INFERIOR) && distance && (distance < 4096)) { /* Store away and parse when the rest of the line shows up */ scr->last_inferior_line = strdup(buf); /* Add line since we did have a lf */ scr->current.pos = 0; scroller_addline(scr, strdup(""), NULL, kind); break; } /* Expand the buffer */ scr->current.pos = 0; /* Add the new line */ line = parse(scr, &attrs, "", buf, distance, kind); scroller_addline(scr, line, attrs, kind); } /* Don't want to exit scroll mode simply because new data received */ if (!scr->in_scroll_mode) { scr_end(scr); } }
static int lua_basename(lua_State *L) { const char *fname = luaL_checkstring(L, 1); const char *suffix = luaL_optstring(L, 2, 0); #ifdef _WIN32 int sl; const char *p, *s; SB sb; sbinit(&sb); /* Special cases */ if (fname[0] && fname[1]==':') { sbaddn(&sb, fname, 2); fname += 2; if (fname[0]=='/' || fname[0]=='\\') sbadd1(&sb, '/'); while (fname[0]=='/' || fname[0]=='\\') fname += 1; if (fname[0]==0) return sbpush(L, &sb); sb.len = 0; } /* Position p after last nontrivial slash */ s = p = fname; while (*s) { if ((s[0]=='\\' || s[0]=='/') && (s[1] && s[1]!='/' && s[1]!='\\' ) ) p = s + 1; s++; } /* Copy into buffer */ while (*p && *p!='/' && *p!='\\') sbadd1(&sb, *p++); /* Process suffix */ if (suffix==0 || suffix[0]==0) return sbpush(L, &sb); if (suffix[0]=='.') suffix += 1; if (suffix[0]==0) return sbpush(L, &sb); sl = strlen(suffix); if (sb.len > sl) { s = sb.buffer + sb.len - (sl + 1); if (s[0]=='.' && _strnicmp(s+1,suffix, sl)==0) sb.len = s - sb.buffer; } return sbpush(L, &sb); #else int sl; const char *s, *p; SB sb; sbinit(&sb); /* Position p after last nontrivial slash */ s = p = fname; while (*s) { if (s[0]=='/' && s[1] && s[1]!='/') p = s + 1; s++; } /* Copy into buffer */ while (*p && *p!='/') sbadd1(&sb, *p++); /* Process suffix */ if (suffix==0 || suffix[0]==0) return sbpush(L, &sb); if (suffix[0]=='.') suffix += 1; if (suffix[0]==0) return sbpush(L, &sb); sl = strlen(suffix); if (sb.len > sl) { s = sb.buffer + sb.len - (sl + 1); if (s[0]=='.' && strncmp(s+1,suffix, sl)==0) sb.len = s - sb.buffer; } return sbpush(L, &sb); #endif }
static int concat_fname(lua_State *L, const char *fname) { const char *from = lua_tostring(L, -1); #ifdef _WIN32 const char *s; SB sb; sbinit(&sb); sbaddn(&sb, from, strlen(from)); if (fname==0) return sbpush(L, &sb); /* Handle absolute part of fname */ if (fname[0]=='/' || fname[0]=='\\') { if (fname[1]=='/' || fname[1]=='\\') { sb.len = 0; /* Case //abcd */ sbaddn(&sb, "//", 2); } else { char drive; if (sb.len >= 2 && sb.buffer[1]==':' /* Case "/abcd" */ && isalpha((unsigned char)(sb.buffer[0])) ) drive = sb.buffer[0]; else drive = _getdrive() + 'A' - 1; sb.len = 0; sbadd1(&sb, drive); sbaddn(&sb, ":/", 2); } } else if (fname[0] && /* Case "x:abcd" */ isalpha((unsigned char)(fname[0])) && fname[1]==':') { if (fname[2]!='/' && fname[2]!='\\') { if (sb.len < 2 || sb.buffer[1]!=':' || !isalpha((unsigned char)(sb.buffer[0])) || (toupper((unsigned char)sb.buffer[0]) != toupper((unsigned char)fname[0]) ) ) { int l; char drv[4]; sb.len = 0; drv[0]=fname[0]; drv[1]=':'; drv[2]='.'; drv[3]=0; l = GetFullPathNameA(drv, sb.maxlen, sb.buffer, 0); if (l > sb.maxlen) { sbgrow(&sb, l+1); l = GetFullPathNameA(drv, sb.maxlen, sb.buffer, 0); } if (l <= 0) sbaddn(&sb, drv, 3); else sb.len += l; } fname += 2; } else { sb.len = 0; /* Case "x:/abcd" */ sbadd1(&sb, toupper((unsigned char)fname[0])); sbaddn(&sb, ":/", 2); fname += 2; while (*fname == '/' || *fname == '\\') fname += 1; } } /* Process path components */ for (;;) { while (*fname=='/' || *fname=='\\') fname ++; if (*fname == 0) return sbpush(L, &sb); if (fname[0]=='.') { if (fname[1]=='/' || fname[1]=='\\' || fname[1]==0) { fname += 1; continue; } if (fname[1]=='.') if (fname[2]=='/' || fname[2]=='\\' || fname[2]==0) { size_t l; fname += 2; lua_pushcfunction(L, lua_dirname); sbpush(L, &sb); lua_call(L, 1, 1); s = lua_tolstring(L, -1, &l); sbinit(&sb); sbaddn(&sb, s, l); lua_pop(L, 1); continue; } } if (sb.len==0 || (sb.buffer[sb.len-1]!='/' && sb.buffer[sb.len-1]!='\\') ) sbadd1(&sb, '/'); while (*fname && *fname!='/' && *fname!='\\') sbadd1(&sb, *fname++); } #else SB sb; sbinit(&sb); if (fname && fname[0]=='/') sbadd1(&sb, '/'); else sbaddn(&sb, from, strlen(from)); for (;;) { while (fname && fname[0]=='/') fname++; if (!fname || !fname[0]) { sbadd1(&sb, '/'); while (sb.len > 1 && sb.buffer[sb.len-1]=='/') sb.len --; return sbpush(L, &sb); } if (fname[0]=='.') { if (fname[1]=='/' || fname[1]==0) { fname +=1; continue; } if (fname[1]=='.') if (fname[2]=='/' || fname[2]==0) { fname +=2; while (sb.len > 0 && sb.buffer[sb.len-1]=='/') sb.len --; while (sb.len > 0 && sb.buffer[sb.len-1]!='/') sb.len --; continue; } } if (sb.len == 0 || sb.buffer[sb.len-1] != '/') sbadd1(&sb, '/'); while (*fname!=0 && *fname!='/') sbadd1(&sb, *fname++); } #endif }
static int lua_dirname(lua_State *L) { const char *fname = luaL_checkstring(L, 1); #ifdef _WIN32 const char *s; const char *p; SB sb; sbinit(&sb); /* Handle leading drive specifier */ if (isalpha((unsigned char)fname[0]) && fname[1]==':') { sbadd1(&sb, *fname++); sbadd1(&sb, *fname++); } /* Search last non terminal / or \ */ p = 0; s = fname; while (*s) { if ((s[0]=='\\' || s[0]=='/') && (s[1] && s[1]!='/' && s[1]!='\\') ) p = s; s++; } /* Cannot find non terminal / or \ */ if (p == 0) { if (sb.len > 0) { if (fname[0]==0 || fname[0]=='/' || fname[0]=='\\') sbadd1(&sb, '/'); return sbpush(L, &sb); } else { if (fname[0]=='/' || fname[0]=='\\') return sbsetpush(L, &sb, "//"); else return sbsetpush(L, &sb, "."); } } /* Single leading slash */ if (p == fname) { sbadd1(&sb, '/'); return sbpush(L, &sb); } /* Backtrack all slashes */ while (p>fname && (p[-1]=='/' || p[-1]=='\\')) p--; /* Multiple leading slashes */ if (p == fname) return sbsetpush(L, &sb, "//"); /* Regular case */ s = fname; do { sbadd1(&sb, *s++); } while (s<p); return sbpush(L, &sb); #else const char *s = fname; const char *p = 0; SB sb; sbinit(&sb); while (*s) { if (s[0]=='/' && s[1] && s[1]!='/') p = s; s++; } if (!p) { if (fname[0]=='/') return sbsetpush(L, &sb, fname); else return sbsetpush(L, &sb, "."); } s = fname; do { sbadd1(&sb, *s++); } while (s<p); return sbpush(L, &sb); #endif }
int filedlg_add_file_choice(struct filedlg *fd, const char *file_choice) { int length; int index, i; int equal = 1; /* Not set to 0, because 0 *is* equal */ if (file_choice == NULL || *file_choice == '\0') return -1; /* Make sure file exists. If temp files are used to create an * executable, and the temp files are deleted, they pollute the * file open dialog with files you can't actually open. * * The downside to not showing them all is that a user might * not understand why certain files aren't showing up. O well. */ if (file_choice[0] != '*') { if (fs_verify_file_exists(file_choice) == 0) return -4; } /* find index to insert by comparing: * Absolute paths go to the end * Relative paths go before the absolute paths */ for (i = 0; i < sbcount(fd->buf->files); i++) { /* Don't add duplicate entry's ... gdb outputs duplicates */ if ((equal = strcmp(fd->buf->files[i], file_choice)) == 0) return -3; else if (equal < 0) { /* Inserting filename, stop before relative path */ if ((file_choice[0] != '.' && file_choice[0] != '/') && fd->buf->files[i][0] == '.') break; /* Inserting filename, stop before absolute path */ if (file_choice[0] != '/' && fd->buf->files[i][0] == '/') break; } else if (equal > 0) { /* Found ( file_choice is greater ) */ /* Inserting Absolute path, it goes to the end */ if (file_choice[0] == '/' && fd->buf->files[i][0] != '/') continue; /* Inserting relative path, continue until before absolute or relative path */ if (file_choice[0] == '.' && (fd->buf->files[i][0] != '.' && fd->buf->files[i][0] != '/')) continue; break; } } index = i; sbpush(fd->buf->files, NULL); /* shift everything down and then insert into index */ for (i = sbcount(fd->buf->files) - 1; i > index; i--) fd->buf->files[i] = fd->buf->files[i - 1]; fd->buf->files[index] = cgdb_strdup(file_choice); if ((length = strlen(file_choice)) > fd->buf->max_width) fd->buf->max_width = length; return 0; }
/** * Display the source. * * A line in the source viewer looks like, * # │ marker text * where, * # is the line number to display or ~ if no line number * │ is the divider between the line number or it is a mark * marker is shortarrow, longarrow, highlight, block, etc * text is the source code to display * * The syntax highlighting works as follows, * * The # * - If breakpoint is set, use Breakpoint * - If breakpoint is disabled, use DisabledBreakpoint * - If selected line, use SelectedLineNr * - If executing line, use ExecutingLineNr * - Otherwise, no highlighting group * * The │ * - When source window is in focus, the character is bolded, otherwise normal * - If the user has a mark set, the mark will be displayed instead of any * other character. * - Edge case: When the marker is long or short arrow, CGDB prints ├ * instead of │ the ├ is colored based on highlighting group for * the selected or executing arrow. * * The marker * - The marker is the shortarrow, longarrow, highlight or block * - The color is based off the corresponding highlighting group * * The text * - The syntax highlighting source code to display * - Will be colored with SelectedLineHighlight or ExecutingLineHighlight * if the line is the selected or executing line and the display is set * to highlight. */ int source_display(struct sviewer *sview, int focus, enum win_refresh dorefresh) { int i; int lwidth; int line; int count; enum LineDisplayStyle exe_display_style, sel_display_style; int sellineno, exelineno; int enabled_bp, disabled_bp; int exe_line_display_is_arrow, sel_line_display_is_arrow; int exe_arrow_attr, sel_arrow_attr; int exe_block_attr, sel_block_attr; char fmt[16]; int width, height; int focus_attr = focus ? SWIN_A_BOLD : 0; int showmarks = cgdbrc_get_int(CGDBRC_SHOWMARKS); int hlsearch = cgdbrc_get_int(CGDBRC_HLSEARCH); int mark_attr; struct hl_line_attr *sel_highlight_attrs = 0; struct hl_line_attr *exe_highlight_attrs = 0; /* Check that a file is loaded */ if (!sview->cur || !sview->cur->file_buf.lines) { logo_display(sview->win); if (dorefresh == WIN_REFRESH) swin_wrefresh(sview->win); else swin_wnoutrefresh(sview->win); return 0; } sellineno = hl_groups_get_attr( hl_groups_instance, HLG_SELECTED_LINE_NUMBER); exelineno = hl_groups_get_attr( hl_groups_instance, HLG_EXECUTING_LINE_NUMBER); enabled_bp = hl_groups_get_attr( hl_groups_instance, HLG_ENABLED_BREAKPOINT); disabled_bp = hl_groups_get_attr( hl_groups_instance, HLG_DISABLED_BREAKPOINT); exe_display_style = cgdbrc_get_displaystyle(CGDBRC_EXECUTING_LINE_DISPLAY); exe_arrow_attr = hl_groups_get_attr( hl_groups_instance, HLG_EXECUTING_LINE_ARROW); exe_block_attr = hl_groups_get_attr( hl_groups_instance, HLG_EXECUTING_LINE_BLOCK); sel_display_style = cgdbrc_get_displaystyle(CGDBRC_SELECTED_LINE_DISPLAY); sel_arrow_attr = hl_groups_get_attr( hl_groups_instance, HLG_SELECTED_LINE_ARROW); sel_block_attr = hl_groups_get_attr( hl_groups_instance, HLG_SELECTED_LINE_BLOCK); exe_line_display_is_arrow = exe_display_style == LINE_DISPLAY_SHORT_ARROW || exe_display_style == LINE_DISPLAY_LONG_ARROW; sel_line_display_is_arrow = sel_display_style == LINE_DISPLAY_SHORT_ARROW || sel_display_style == LINE_DISPLAY_LONG_ARROW; mark_attr = hl_groups_get_attr(hl_groups_instance, HLG_MARK); sbpush(sel_highlight_attrs, hl_line_attr(0, HLG_SELECTED_LINE_HIGHLIGHT)); sbpush(exe_highlight_attrs, hl_line_attr(0, HLG_EXECUTING_LINE_HIGHLIGHT)); /* Make sure cursor is visible */ swin_curs_set(!!focus); /* Initialize variables */ height = swin_getmaxy(sview->win); width = swin_getmaxx(sview->win); /* Set starting line number (center source file if it's small enough) */ count = sbcount(sview->cur->file_buf.lines); if (count < height) { line = (count - height) / 2; } else { line = sview->cur->sel_line - height / 2; if (line > count - height) line = count - height; else if (line < 0) line = 0; } /* Print 'height' lines of the file, starting at 'line' */ lwidth = log10_uint(count) + 1; snprintf(fmt, sizeof(fmt), "%%%dd", lwidth); for (i = 0; i < height; i++, line++) { int column_offset = 0; /* Is this the current selected line? */ int is_sel_line = (line >= 0 && sview->cur->sel_line == line); /* Is this the current executing line */ int is_exe_line = (line >= 0 && sview->cur->exe_line == line); struct source_line *sline = (line < 0 || line >= count)? NULL:&sview->cur->file_buf.lines[line]; struct hl_line_attr *printline_attrs = (sline)?sline->attrs:0; swin_wmove(sview->win, i, 0); /* Print the line number */ if (line < 0 || line >= count) { for (int j = 1; j < lwidth; j++) swin_waddch(sview->win, ' '); swin_waddch(sview->win, '~'); } else { int line_attr = 0; int bp_val = sview->cur->lflags[line].breakpt; if (bp_val == 1) { line_attr = enabled_bp; } else if (bp_val == 2) { line_attr = disabled_bp; } else if (bp_val == 0 && is_exe_line) { line_attr = exelineno; } else if (bp_val == 0 && is_sel_line) { line_attr = sellineno; } swin_wattron(sview->win, line_attr); swin_wprintw(sview->win, fmt, line + 1); swin_wattroff(sview->win, line_attr); } if (!swin_has_colors()) { /* TODO: swin_wprintw(sview->win, "%.*s\n", sview->cur->file_buf.lines[line].line, sview->cur->file_buf.lines[line].len); */ continue; } /* Print the vertical bar or mark */ { SWIN_CHTYPE vert_bar_char; int vert_bar_attr; int mc; if (showmarks && ((mc = source_get_mark_char(sview, sview->cur, line)) > 0)) { vert_bar_char = mc; vert_bar_attr = mark_attr; } else if (is_exe_line && exe_line_display_is_arrow) { vert_bar_attr = exe_arrow_attr; vert_bar_char = SWIN_SYM_LTEE; } else if (is_sel_line && sel_line_display_is_arrow) { vert_bar_attr = sel_arrow_attr; vert_bar_char = SWIN_SYM_LTEE; } else { vert_bar_attr = focus_attr; vert_bar_char = SWIN_SYM_VLINE; } swin_wattron(sview->win, vert_bar_attr); swin_waddch(sview->win, vert_bar_char); swin_wattroff(sview->win, vert_bar_attr); } /* Print the marker */ if (is_exe_line || is_sel_line) { enum LineDisplayStyle display_style; int arrow_attr, block_attr; struct hl_line_attr *highlight_attr; if (is_exe_line) { display_style = exe_display_style; arrow_attr = exe_arrow_attr; block_attr = exe_block_attr; highlight_attr = exe_highlight_attrs; } else { display_style = sel_display_style; arrow_attr = sel_arrow_attr; block_attr = sel_block_attr; highlight_attr = sel_highlight_attrs; } switch (display_style) { case LINE_DISPLAY_SHORT_ARROW: swin_wattron(sview->win, arrow_attr); swin_waddch(sview->win, '>'); swin_wattroff(sview->win, arrow_attr); break; case LINE_DISPLAY_LONG_ARROW: swin_wattron(sview->win, arrow_attr); column_offset = get_line_leading_ws_count( sline->line, sline->len); column_offset -= (sview->cur->sel_col + 1); if (column_offset < 0) column_offset = 0; /* Now actually draw the arrow */ for (int j = 0; j < column_offset; j++) swin_waddch(sview->win, SWIN_SYM_HLINE); swin_waddch(sview->win, '>'); swin_wattroff(sview->win, arrow_attr); break; case LINE_DISPLAY_HIGHLIGHT: swin_waddch(sview->win, ' '); printline_attrs = highlight_attr; break; case LINE_DISPLAY_BLOCK: column_offset = get_line_leading_ws_count( sline->line, sline->len); column_offset -= (sview->cur->sel_col + 1); if (column_offset < 0) column_offset = 0; /* Now actually draw the space to the block */ for (int j = 0; j < column_offset; j++) swin_waddch(sview->win, ' '); /* Draw the block */ swin_wattron(sview->win, block_attr); swin_waddch(sview->win, ' '); swin_wattroff(sview->win, block_attr); break; } } else { swin_waddch(sview->win, ' '); } /* Print the text */ if (line < 0 || line >= count) { for (int j = 2 + lwidth; j < width; j++) swin_waddch(sview->win, ' '); } else { int x, y; y = swin_getcury(sview->win); x = swin_getcurx(sview->win); hl_printline(sview->win, sline->line, sline->len, printline_attrs, -1, -1, sview->cur->sel_col + column_offset, width - lwidth - 2); if (hlsearch && sview->last_hlregex) { struct hl_line_attr *attrs = hl_regex_highlight( &sview->last_hlregex, sline->line, HLG_SEARCH); if (sbcount(attrs)) { hl_printline_highlight(sview->win, sline->line, sline->len, attrs, x, y, sview->cur->sel_col + column_offset, width - lwidth - 2); sbfree(attrs); } } if (is_sel_line && sview->hlregex) { struct hl_line_attr *attrs = hl_regex_highlight( &sview->hlregex, sline->line, HLG_INCSEARCH); if (sbcount(attrs)) { hl_printline_highlight(sview->win, sline->line, sline->len, attrs, x, y, sview->cur->sel_col + column_offset, width - lwidth - 2); sbfree(attrs); } } } } switch(dorefresh) { case WIN_NO_REFRESH: swin_wnoutrefresh(sview->win); break; case WIN_REFRESH: swin_wrefresh(sview->win); break; } sbfree(sel_highlight_attrs); sbfree(exe_highlight_attrs); return 0; }
int rline_rl_complete(struct rline *rline, char **completions, display_callback display_cb) { int size; int key; rl_command_func_t *compare_func = NULL; if (!rline) return -1; /* Currently, if readline output's the tab completion to rl_outstream, it will fill * the pty between it and CGDB and will cause CGDB to hang. */ if (!display_cb) return -1; size = sbcount(completions); if (size == 0) { rl_completion_word_break_hook = NULL; rl_completion_entry_function = NULL; } else { int i; for (i = 0; i < size; i++) sbpush(completions_array, completions[i]); rl_completion_word_break_hook = rline_rl_cpvfunc_t; rl_completion_entry_function = rline_rl_completion_entry_function; } rl_completion_display_matches_hook = display_cb; /* This is probably a hack, however it works for now. * * Basically, rl_complete is working fine. After the call to rl_complete, * rl_line_buffer contains the proper data. However, the CGDB main loop * always call rline_rl_forced_update_display, which in the case of tab * completion does this, (gdb) b ma(gdb) b main * * Normally, this works fine because the user hits '\n', which puts the prompt * on the next line. In this case, the user hit's \t. * * In order work around this problem, simply putting the \r should work * for now. * * This obviously shouldn't be done when readline is doing * `?' means list the possible completions. * style completion. Because that actuall does list all of the values on * a different line. In this situation the \r goes after the completion * is done, since only the current prompt is on that line. */ /* Another confusing comparison. This checks to see if the last * readline function and the current readline function and the * tab completion callback are all the same. This ensures that this * is the second time the user hit \t in a row. Instead of simply * calling rl_complete_internal, it's better to call, rl_completion_mode * because this checks to see what kind of completion should be done. */ if (rline->rline_rl_last_func == rline->tab_completion && rline->rline_rl_last_func == rl_last_func) compare_func = rline->tab_completion; key = rl_completion_mode(compare_func); if (key == TAB) fprintf(rline->output, "\r"); rl_complete_internal(key); if (key != TAB) fprintf(rline->output, "\r"); /* Free the current completion array entries */ rline_free_completions(); return 0; }