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
00026
00027
00028
00051 #include <stdlib.h>
00052 #include <str.h>
00053 #include <errno.h>
00054 #include <adt/list.h>
00055 #include <align.h>
00056 #include <macros.h>
00057
00058 #include "sheet.h"
00059
00060 enum {
00061 TAB_WIDTH = 8,
00062
00064 INITIAL_SIZE = 32
00065 };
00066
00068 int sheet_init(sheet_t *sh)
00069 {
00070 sh->dbuf_size = INITIAL_SIZE;
00071 sh->text_size = 0;
00072
00073 sh->data = malloc(sh->dbuf_size);
00074 if (sh->data == NULL)
00075 return ENOMEM;
00076
00077 list_initialize(&sh->tags_head);
00078
00079 return EOK;
00080 }
00081
00095 int sheet_insert(sheet_t *sh, spt_t *pos, enum dir_spec dir, char *str)
00096 {
00097 char *ipp;
00098 size_t sz;
00099 link_t *link;
00100 tag_t *tag;
00101 char *newp;
00102
00103 sz = str_size(str);
00104 if (sh->text_size + sz > sh->dbuf_size) {
00105
00106 newp = realloc(sh->data, sh->dbuf_size * 2);
00107 if (newp == NULL)
00108 return ELIMIT;
00109
00110 sh->data = newp;
00111 sh->dbuf_size = sh->dbuf_size * 2;
00112 }
00113
00114 ipp = sh->data + pos->b_off;
00115
00116
00117 memmove(ipp + sz, ipp, sh->text_size - pos->b_off);
00118 memcpy(ipp, str, sz);
00119 sh->text_size += sz;
00120
00121
00122
00123 link = sh->tags_head.next;
00124 while (link != &sh->tags_head) {
00125 tag = list_get_instance(link, tag_t, link);
00126
00127 if (tag->b_off > pos->b_off)
00128 tag->b_off += sz;
00129 else if (tag->b_off == pos->b_off && dir == dir_before)
00130 tag->b_off += sz;
00131
00132 link = link->next;
00133 }
00134
00135 return EOK;
00136 }
00137
00148 int sheet_delete(sheet_t *sh, spt_t *spos, spt_t *epos)
00149 {
00150 char *spp;
00151 size_t sz;
00152 link_t *link;
00153 tag_t *tag;
00154 char *newp;
00155 size_t shrink_size;
00156
00157 spp = sh->data + spos->b_off;
00158 sz = epos->b_off - spos->b_off;
00159
00160 memmove(spp, spp + sz, sh->text_size - (spos->b_off + sz));
00161 sh->text_size -= sz;
00162
00163
00164 link = sh->tags_head.next;
00165 while (link != &sh->tags_head) {
00166 tag = list_get_instance(link, tag_t, link);
00167
00168 if (tag->b_off >= epos->b_off)
00169 tag->b_off -= sz;
00170 else if (tag->b_off >= spos->b_off)
00171 tag->b_off = spos->b_off;
00172
00173 link = link->next;
00174 }
00175
00176
00177 shrink_size = max(sh->dbuf_size / 4, INITIAL_SIZE);
00178 if (sh->text_size <= shrink_size && sh->dbuf_size > INITIAL_SIZE) {
00179
00180 newp = realloc(sh->data, shrink_size);
00181 if (newp == NULL) {
00182
00183 return EOK;
00184 }
00185
00186 sh->data = newp;
00187 sh->dbuf_size = shrink_size;
00188 }
00189
00190 return EOK;
00191 }
00192
00194 void sheet_copy_out(sheet_t *sh, spt_t const *spos, spt_t const *epos,
00195 char *buf, size_t bufsize, spt_t *fpos)
00196 {
00197 char *spp;
00198 size_t range_sz;
00199 size_t copy_sz;
00200 size_t off, prev;
00201 wchar_t c;
00202
00203 spp = sh->data + spos->b_off;
00204 range_sz = epos->b_off - spos->b_off;
00205 copy_sz = (range_sz < bufsize - 1) ? range_sz : bufsize - 1;
00206
00207 prev = off = 0;
00208 do {
00209 prev = off;
00210 c = str_decode(spp, &off, copy_sz);
00211 } while (c != '\0');
00212
00213
00214 copy_sz = prev;
00215
00216 memcpy(buf, spp, copy_sz);
00217 buf[copy_sz] = '\0';
00218
00219 fpos->b_off = spos->b_off + copy_sz;
00220 fpos->sh = sh;
00221 }
00222
00224 void sheet_get_cell_pt(sheet_t *sh, coord_t const *coord, enum dir_spec dir,
00225 spt_t *pt)
00226 {
00227 size_t cur_pos, prev_pos;
00228 wchar_t c;
00229 coord_t cc;
00230
00231 cc.row = cc.column = 1;
00232 cur_pos = prev_pos = 0;
00233 while (true) {
00234 if (prev_pos >= sh->text_size) {
00235
00236 break;
00237 }
00238
00239 if ((cc.row >= coord->row && cc.column > coord->column) ||
00240 cc.row > coord->row) {
00241
00242 break;
00243 }
00244
00245 prev_pos = cur_pos;
00246
00247 c = str_decode(sh->data, &cur_pos, sh->text_size);
00248 if (c == '\n') {
00249 ++cc.row;
00250 cc.column = 1;
00251 } else if (c == '\t') {
00252 cc.column = 1 + ALIGN_UP(cc.column, TAB_WIDTH);
00253 } else {
00254 ++cc.column;
00255 }
00256 }
00257
00258 pt->sh = sh;
00259 pt->b_off = (dir == dir_before) ? prev_pos : cur_pos;
00260 }
00261
00263 void sheet_get_row_width(sheet_t *sh, int row, int *length)
00264 {
00265 coord_t coord;
00266 spt_t pt;
00267
00268
00269 coord.row = row;
00270 coord.column = 65536;
00271
00272 sheet_get_cell_pt(sh, &coord, dir_before, &pt);
00273 spt_get_coord(&pt, &coord);
00274 *length = coord.column - 1;
00275 }
00276
00278 void sheet_get_num_rows(sheet_t *sh, int *rows)
00279 {
00280 int cnt;
00281 size_t bo;
00282
00283 cnt = 1;
00284 for (bo = 0; bo < sh->dbuf_size; ++bo) {
00285 if (sh->data[bo] == '\n')
00286 cnt += 1;
00287 }
00288
00289 *rows = cnt;
00290 }
00291
00293 void spt_get_coord(spt_t const *pos, coord_t *coord)
00294 {
00295 size_t off;
00296 coord_t cc;
00297 wchar_t c;
00298 sheet_t *sh;
00299
00300 sh = pos->sh;
00301 cc.row = cc.column = 1;
00302
00303 off = 0;
00304 while (off < pos->b_off && off < sh->text_size) {
00305 c = str_decode(sh->data, &off, sh->text_size);
00306 if (c == '\n') {
00307 ++cc.row;
00308 cc.column = 1;
00309 } else if (c == '\t') {
00310 cc.column = 1 + ALIGN_UP(cc.column, TAB_WIDTH);
00311 } else {
00312 ++cc.column;
00313 }
00314 }
00315
00316 *coord = cc;
00317 }
00318
00320 bool spt_equal(spt_t const *a, spt_t const *b)
00321 {
00322 return a->b_off == b->b_off;
00323 }
00324
00326 void sheet_place_tag(sheet_t *sh, spt_t const *pt, tag_t *tag)
00327 {
00328 tag->b_off = pt->b_off;
00329 tag->sh = sh;
00330 list_append(&tag->link, &sh->tags_head);
00331 }
00332
00334 void sheet_remove_tag(sheet_t *sh, tag_t *tag)
00335 {
00336 list_remove(&tag->link);
00337 }
00338
00340 void tag_get_pt(tag_t const *tag, spt_t *pt)
00341 {
00342 pt->b_off = tag->b_off;
00343 pt->sh = tag->sh;
00344 }
00345