/* radare - LGPL - Copyright 2013-2015 - pancake */ #include #define W(y) r_cons_canvas_write(c,y) #define G(x,y) r_cons_canvas_gotoxy(c,x,y) R_API void r_cons_canvas_free (RConsCanvas *c) { free (c->b); free (c->attrs); free (c); } R_API void r_cons_canvas_clear (RConsCanvas *c) { int y; if (c && c->b) { memset (c->b, '\n', c->blen); c->b[c->blen] = 0; for (y = 0; yh; y++) c->b[ y * c->w ] = '\n'; if(c->attrs){ c->attrslen=0; memset (c->attrs, 0, sizeof (*c->attrs)*c->blen); } } } R_API RConsCanvas* r_cons_canvas_new (int w, int h) { RConsCanvas *c; if (w<1||h<1) return NULL; c = R_NEW0 (RConsCanvas); if (!c) return NULL; c->color = 0; c->sx = 0; c->sy = 0; c->blen = (w+1)*h; c->b = malloc (c->blen+1); if (!c->b) { free (c); return NULL; } c->attrslen = 0; c->attrs = calloc(sizeof(*c->attrs),c->blen+1); if (!c->attrs) { free (c->b); free (c); return NULL; } c->attr=Color_RESET; c->w = w; c->h = h; c->x = c->y = 0; r_cons_canvas_clear (c); return c; } R_API int r_cons_canvas_gotoxy(RConsCanvas *c, int x, int y) { int ret = R_TRUE; if (!c) return 0; x += c->sx; y += c->sy; if (x >= c->w) { c->x = c->w; ret = R_FALSE; } if (y >= c->h) { c->y = c->h; ret = R_FALSE; } if (x <0) { //c->x = 0; ret = R_FALSE; } if (y <0) { c->y = 0; ret = R_FALSE; } if (xw && x>=0) c->x = x; if (yh && y>=0) c->y = y; return ret; } #if 0 static char *getptr(RConsCanvas *c, int *left) { if (left) *left = c->w - c->x; return c->b + (c->y * c->w) + c->x; } #endif static char *getrow (char *p, char **n) { char *q; if (!p) return NULL; q = strchr (p, '\n'); if (n) *n = NULL; if (q) { *q = 0; if (n) *n = q+1; } return p; } static char *prefixline(RConsCanvas *c, int *left) { int x; char *p; if (!c) return NULL; p = c->b + (c->y * c->w); for (x = 0; xx; x++) { if (p[x] == '\n') p[x] = ' '; } if (left) *left = c->w - c->x; return p+x; } static const char ** attr_at(RConsCanvas *c,int loc){ int i, j; if (!c->color || c->attrslen==0) return NULL; j = c->attrslen / 2; for (i=0; i<(c->attrslen); i++){ if (c->attrs[j].loc == loc) return &c->attrs[j].a; if(c->attrs[j].loc < loc) { j++; /* k=c->attrslen/(2+(i*i)); if(k==0) j++; else j+=k; */ if(j>=c->attrslen) break; if(c->attrs[j].loc > loc) break; } else if(c->attrs[j].loc > loc) { j--; /* k=c->attrslen/(2+(i*i)); if(k==0) j--; else j+=k; */ if(j<=0) break; if(c->attrs[j].loc < loc) break; } } return NULL; } static void sort_attrs(RConsCanvas *c) { int i,j; RConsCanvasAttr value; for (i = 1; i < c->attrslen; i++) { value = c->attrs[i]; for (j = i-1; j>=0 && c->attrs[j].loc>value.loc; j--) { c->attrs[j+1] = c->attrs[j]; } c->attrs[j+1] = value; } } static void stamp_attr(RConsCanvas *c,int length){ int i; const char ** s; const int loc = c->x + (c->y * c->w); s = attr_at(c, loc); if (s) { //If theres already an attr there, just replace it. *s = c->attr; } else { c->attrs[c->attrslen].loc = loc; c->attrs[c->attrslen].a = c->attr; c->attrslen++; sort_attrs(c); } for(i=0;iattr; } } R_API void r_cons_canvas_write(RConsCanvas *c, const char *_s) { int left, slen, i, linenum = 0; char *p, *s, *str; char *line, *n; int x, delta; if (!c || !_s || !*_s) return; str = s = strdup (_s); for (i=0; ; i++) { line = getrow (s, &n); if (!line) break; p = prefixline (c, &left); slen = R_MIN (left-1, strlen (line)); if (slen<1) { break; } if (!G (c->x-c->sx+slen, c->y-c->sy)) { // TODO : chop slen slen = (c->w - (c->x-c->sx)); if (slen<1) break; s = n; continue; } delta = 0; x = c->x - c->sx - slen; // if (x<0) x = 0; if (!G (x, c->y - c->sy)) continue; stamp_attr(c,slen); memcpy (p, line+delta, slen-delta); if (!n) break; s = n; if (!G (c->x-c->sx, c->y+1 - c->sy)) break; linenum ++; } free (str); } R_API char *r_cons_canvas_to_string(RConsCanvas *c) { int x, y, olen = 0; char *o; const char* b; const char**atr; if (!c) return NULL; b = c->b; o = calloc (sizeof(char), (c->w * (c->h + 1)) * (CONS_MAX_ATTR_SZ)); if (!o) return NULL; for (y = 0; y < c->h; y++) { for (x = 0; xw; x++) { const int p = x + (y * c->w); atr = attr_at (c,p); if(atr) { strcat (o, *atr); olen += strlen (*atr); } if (!b[p] || b[p]=='\n') break; o[olen++] = b[p]; } o[olen++] = '\n'; } o[olen] = '\0'; return o; } R_API void r_cons_canvas_print(RConsCanvas *c) { char *o = r_cons_canvas_to_string (c); if (o) { r_cons_strcat (o); free (o); } } R_API int r_cons_canvas_resize(RConsCanvas *c, int w, int h) { const int blen = (w+1) * h; char *b = NULL; if (!c || w < 0) return R_FALSE; b = realloc (c->b, blen+1); if (!b) return R_FALSE; c->attrs = realloc(c->attrs,sizeof(*c->attrs)*blen+1); if (!c->attrs) return R_FALSE; c->blen = blen; c->b = b; c->w = w; c->h = h; c->x = 0; c->y = 0; r_cons_canvas_clear (c); return R_TRUE; } R_API void r_cons_canvas_box(RConsCanvas *c, int x, int y, int w, int h, const char *color) { int i; int roundcorners = 0; char *row = NULL; char corner = '='; if (w < 0) return; if (color) c->attr = color; row = malloc (w+1); row[0] = roundcorners?'.':corner; memset (row+1, '-', w-2); row[w-1] = roundcorners?'.':corner; row[w] = 0; if (G(x, y)) { W(row); } if (G(x, y+h-1)) { row[0] = roundcorners?'\'':corner; row[w-1] = roundcorners?'\'':corner; W(row); } for (i=1;iattr = Color_RESET; } R_API void r_cons_canvas_fill(RConsCanvas *c, int x, int y, int w, int h, char ch, int replace) { int i; char *row = NULL; if (w < 0) return; row = malloc (w+1); memset (row, ch, w); row[w] = 0; for (i=0;ilinemode) { r_cons_canvas_line_square (c, x, y, x2, y2, style); return; } else { r_cons_canvas_line_diagonal (c, x, y, x2, y2, style); } }