00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <stdlib.h>
00026 #include <string.h>
00027
00028 #include <common/xmalloc.h>
00029 #include "text.h"
00030
00031 static char *
00032 _find_position (text_buf * b, int x, int y)
00033 {
00034 return b->buf + y * b->width + x;
00035 }
00036
00037 static const char *
00038 _find_position_const (const text_buf * b, int x, int y)
00039 {
00040 return b->buf + y * b->width + x;
00041 }
00042
00043
00044 static void
00045 _check_expand_buf (text_buf * b, int ypos)
00046 {
00047 ++ypos;
00048
00049 if (b->reserved_h < ypos)
00050 {
00051 b->reserved_h = ypos * 1.5;
00052 b->buf = xrealloc (b->buf, b->width * b->reserved_h);
00053 }
00054
00055 if (b->height < ypos)
00056 b->height = ypos;
00057 }
00058
00059
00060 static char *
00061 _cursor_ptr (text_buf * b)
00062 {
00063 int x = b->cursor_x;
00064
00065 if (x < 0)
00066 x = 0;
00067
00068 _check_expand_buf (b, b->cursor_y);
00069
00070 return _find_position (b, x, b->cursor_y);
00071 }
00072
00073
00074 static void
00075 _newline (text_buf * b)
00076 {
00077 if (b->cursor_x == 0)
00078 return;
00079
00080 b->cursor_x = 0;
00081 ++b->cursor_y;
00082 _check_expand_buf (b, b->cursor_y);
00083 memset (_cursor_ptr (b), ' ', b->width);
00084 }
00085
00086
00087 static const char *
00088 _find_next_word_delimiter (const char *text)
00089 {
00090 while (*text && *text != ' ')
00091 ++text;
00092
00093 return text;
00094 }
00095
00096
00097 static int
00098 _is_whitespace (const char *p, int step, int count)
00099 {
00100 for (; count; --count, p += step)
00101 {
00102 if (*p != ' ')
00103 return 0;
00104 }
00105
00106 return 1;
00107 }
00108
00109
00110 text_buf *
00111 text_buf_malloc (int width, int height)
00112 {
00113 text_buf *new = xmalloc (sizeof (text_buf));
00114
00115 new->width = width;
00116 new->height = height;
00117 new->reserved_h = height;
00118 new->cursor_x = 0;
00119 new->cursor_y = 0;
00120 new->buf = xmalloc (width * height);
00121 memset (new->buf, ' ', width * height);
00122
00123 return new;
00124 }
00125
00126
00127 void
00128 text_buf_free (text_buf * b)
00129 {
00130 free (b->buf);
00131 free (b);
00132 }
00133
00134
00135 void
00136 text_print (text_buf * b, const char *text)
00137 {
00138 int startpos = b->cursor_x < 0 ? -(b->cursor_x) : 0;
00139 int chars = b->width - startpos;
00140 int len = strlen (text);
00141
00142 if (b->cursor_y < 0 || b->cursor_x >= b->width || b->cursor_x + len <= 0)
00143 {
00144
00145
00146
00147 b->cursor_x += len;
00148 return;
00149 }
00150
00151 memcpy (_cursor_ptr (b), text + startpos, chars);
00152 }
00153
00154
00155 void
00156 text_print_wrap (text_buf * b, const char *text)
00157 {
00158 char add_hyphen;
00159 const char *pos;
00160 const char *brk;
00161 int wordlen;
00162
00163 while (*text)
00164 {
00165 pos = _find_next_word_delimiter (text);
00166 wordlen = pos - text;
00167 add_hyphen = 0;
00168
00169
00170
00171
00172
00173
00174
00175 if (b->cursor_x + wordlen >= b->width)
00176 {
00177 brk = text + b->width - b->cursor_x - 1;
00178 while (brk > text && *brk != '-')
00179 --brk;
00180
00181 if (brk > text)
00182 wordlen = brk - text + 1;
00183 else
00184 {
00185 if (wordlen > b->width)
00186 {
00187 wordlen = (b->width - b->cursor_x - 1);
00188 if (wordlen < 4)
00189 wordlen = 0;
00190 else
00191 add_hyphen = 1;
00192
00193 }
00194 else
00195 {
00196 wordlen = 0;
00197 }
00198 }
00199 }
00200
00201 if (wordlen == 0)
00202 {
00203 _newline (b);
00204 }
00205 else
00206 {
00207 memcpy (_cursor_ptr (b), text, wordlen);
00208 b->cursor_x += wordlen;
00209 if (b->cursor_x < b->width)
00210 {
00211 *(_cursor_ptr (b)) = ' ';
00212 ++b->cursor_x;
00213 }
00214 text += wordlen;
00215 while (*text && *text == ' ')
00216 ++text;
00217 }
00218 }
00219 }
00220
00221
00222 void
00223 text_add_centered_line (text_buf * b, const char *text,
00224 char filler, char left_end, char right_end)
00225 {
00226 int len = strlen (text);
00227 int space;
00228 int i;
00229 char *p;
00230
00231 if (len > b->width)
00232 {
00233 text += len / 2;
00234 len = b->width;
00235 }
00236
00237 space = (b->width - len) / 2;
00238 _newline (b);
00239 p = _cursor_ptr (b);
00240
00241 for (i = 0; i < space - 1; ++i)
00242 *p++ = filler;
00243 for (; i < space; ++i)
00244 *p++ = left_end;
00245 for (; i < b->width - space; ++i)
00246 *p++ = *text ? *text++ : ' ';
00247 for (; i < b->width - (space - 1); ++i)
00248 *p++ = right_end;
00249 for (; i < b->width; ++i)
00250 *p++ = filler;
00251
00252 ++b->cursor_x;
00253 _newline (b);
00254 }
00255
00256
00257 text_buf *
00258 text_copy_region (const text_buf * b, int x, int y, int w, int h)
00259 {
00260
00261
00262 text_buf *newbuf = text_buf_malloc (w, h);
00263 const char *src = _find_position_const (b, x, y);
00264 char *dest = newbuf->buf;
00265 int i;
00266
00267 for (i = 0; i < h; ++i)
00268 {
00269 memcpy (dest, src, w);
00270 dest += w;
00271 src += b->width;
00272 }
00273
00274 return newbuf;
00275 }
00276
00277
00278 void
00279 text_paste_region (text_buf * dest, const text_buf * source, int x, int y)
00280 {
00281
00282
00283 const char *sbuf = source->buf;
00284 char *dbuf = _find_position (dest, x, y);
00285 int i;
00286
00287 for (i = 0; i < source->height; ++i)
00288 {
00289 memcpy (dbuf, sbuf, source->width);
00290 sbuf += source->width;
00291 dbuf += dest->width;
00292 }
00293 }
00294
00295
00296 void
00297 text_crop (text_buf * b, int top, int bottom, int left, int right)
00298 {
00299 char *src = _find_position (b, top, left);
00300 char *dest = b->buf;
00301 int new_width = b->width - (left + right);
00302 int new_height = b->height - (top + bottom);
00303 int i;
00304
00305 for (i = 0; i < new_height; ++i)
00306 {
00307 memcpy (dest, src, new_width);
00308 src += new_width;
00309 dest += b->width;
00310 }
00311
00312 b->buf = xrealloc (b->buf, new_width * new_height);
00313 b->width = new_width;
00314 b->height = new_height;
00315 b->reserved_h = new_height;
00316 b->cursor_x = 0;
00317 b->cursor_y = 0;
00318 }
00319
00320
00321 void
00322 text_autocrop (text_buf * b)
00323 {
00324 int top = 0;
00325 int bottom = 0;
00326 int left = 0;
00327 int right = 0;
00328 int size = b->width * b->height;
00329
00330 if (size == 0)
00331 return;
00332
00333
00334
00335
00336
00337 while (top < b->height
00338 && _is_whitespace (_find_position_const (b, top, 0), 1, b->width))
00339 {
00340 ++top;
00341 }
00342
00343 while (bottom < b->height - top
00344 &&
00345 _is_whitespace (_find_position_const (b, b->height - bottom - 1, 0),
00346 1, b->width))
00347 {
00348 ++bottom;
00349 }
00350
00351
00352
00353
00354
00355
00356 while (left < b->width
00357 && _is_whitespace (_find_position_const (b, top, left), b->width,
00358 b->height - (top + bottom)))
00359 {
00360 ++left;
00361 }
00362
00363 while (right < b->width - left
00364 && _is_whitespace (_find_position_const (b, top + 1, -right + 1),
00365 b->width, b->height - (top + bottom)))
00366 {
00367 ++right;
00368 }
00369
00370 text_crop (b, top, bottom, left, right);
00371 }