source: mainline/uspace/app/edit/sheet.c@ 85c98af

Last change on this file since 85c98af was 85c98af, checked in by Manuele Conti <manuele.conti@…>, 5 years ago

Avoid memory leak into sheet_create function

  • Property mode set to 100644
File size: 8.5 KB
RevLine 
[3052ff4]1/*
2 * Copyright (c) 2009 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup edit
30 * @{
31 */
32/**
33 * @file
34 * @brief Prototype implementation of Sheet data structure.
35 *
36 * The sheet is an abstract data structure representing a piece of text.
37 * On top of this data structure we can implement a text editor. It is
38 * possible to implement the sheet such that the editor can make small
39 * changes to large files or files containing long lines efficiently.
40 *
41 * The sheet structure allows basic operations of text insertion, deletion,
42 * retrieval and mapping of coordinates to position in the file and vice
43 * versa. The text that is inserted or deleted can contain tabs and newlines
44 * which are interpreted and properly acted upon.
45 *
46 * This is a trivial implementation with poor efficiency with O(N+n)
47 * insertion and deletion and O(N) mapping (in both directions), where
48 * N is the size of the file and n is the size of the inserted/deleted text.
49 */
50
51#include <stdlib.h>
[19f857a]52#include <str.h>
[3052ff4]53#include <errno.h>
54#include <adt/list.h>
55#include <align.h>
[c29f20b]56#include <macros.h>
[3052ff4]57
58#include "sheet.h"
[69cf3a4]59#include "sheet_impl.h"
[3052ff4]60
61enum {
[c29f20b]62 TAB_WIDTH = 8,
63
64 /** Initial of dat buffer in bytes */
65 INITIAL_SIZE = 32
[3052ff4]66};
67
68/** Initialize an empty sheet. */
[b7fd2a0]69errno_t sheet_create(sheet_t **rsh)
[3052ff4]70{
[69cf3a4]71 sheet_t *sh;
72
73 sh = calloc(1, sizeof(sheet_t));
74 if (sh == NULL)
75 return ENOMEM;
76
[c29f20b]77 sh->dbuf_size = INITIAL_SIZE;
[3052ff4]78 sh->text_size = 0;
79
80 sh->data = malloc(sh->dbuf_size);
[85c98af]81 if (sh->data == NULL) {
82 free(sh);
[3052ff4]83 return ENOMEM;
[85c98af]84 }
[3052ff4]85
[b72efe8]86 list_initialize(&sh->tags);
[3052ff4]87
[69cf3a4]88 *rsh = sh;
[3052ff4]89 return EOK;
90}
91
92/** Insert text into sheet.
93 *
94 * @param sh Sheet to insert to.
95 * @param pos Point where to insert.
96 * @param dir Whether to insert before or after the point (affects tags).
97 * @param str The text to insert (printable characters, tabs, newlines).
98 *
[cde999a]99 * @return EOK on success or an error code.
[3052ff4]100 *
101 * @note @a dir affects which way tags that were placed on @a pos will
102 * move. If @a dir is @c dir_before, the tags will move forward
103 * and vice versa.
104 */
[b7fd2a0]105errno_t sheet_insert(sheet_t *sh, spt_t *pos, enum dir_spec dir, char *str)
[3052ff4]106{
107 char *ipp;
108 size_t sz;
[c29f20b]109 char *newp;
[3052ff4]110
111 sz = str_size(str);
[c29f20b]112 if (sh->text_size + sz > sh->dbuf_size) {
113 /* Enlarge data buffer. */
114 newp = realloc(sh->data, sh->dbuf_size * 2);
115 if (newp == NULL)
116 return ELIMIT;
117
118 sh->data = newp;
119 sh->dbuf_size = sh->dbuf_size * 2;
120 }
[3052ff4]121
122 ipp = sh->data + pos->b_off;
123
[c29f20b]124 /* Copy data. */
[3052ff4]125 memmove(ipp + sz, ipp, sh->text_size - pos->b_off);
126 memcpy(ipp, str, sz);
127 sh->text_size += sz;
128
[c29f20b]129 /* Adjust tags. */
[3052ff4]130
[feeac0d]131 list_foreach(sh->tags, link, tag_t, tag) {
[3052ff4]132 if (tag->b_off > pos->b_off)
133 tag->b_off += sz;
134 else if (tag->b_off == pos->b_off && dir == dir_before)
135 tag->b_off += sz;
136 }
137
138 return EOK;
139}
140
141/** Delete text from sheet.
142 *
143 * Deletes the range of text between two points from the sheet.
144 *
145 * @param sh Sheet to delete from.
146 * @param spos Starting point.
147 * @param epos Ending point.
148 *
[cde999a]149 * @return EOK on success or an error code.
[7c3fb9b]150 */
[b7fd2a0]151errno_t sheet_delete(sheet_t *sh, spt_t *spos, spt_t *epos)
[3052ff4]152{
153 char *spp;
154 size_t sz;
[c29f20b]155 char *newp;
156 size_t shrink_size;
[3052ff4]157
158 spp = sh->data + spos->b_off;
159 sz = epos->b_off - spos->b_off;
160
161 memmove(spp, spp + sz, sh->text_size - (spos->b_off + sz));
162 sh->text_size -= sz;
163
[c29f20b]164 /* Adjust tags. */
[feeac0d]165 list_foreach(sh->tags, link, tag_t, tag) {
[3052ff4]166 if (tag->b_off >= epos->b_off)
167 tag->b_off -= sz;
168 else if (tag->b_off >= spos->b_off)
169 tag->b_off = spos->b_off;
170 }
[c29f20b]171
172 /* See if we should free up some memory. */
173 shrink_size = max(sh->dbuf_size / 4, INITIAL_SIZE);
174 if (sh->text_size <= shrink_size && sh->dbuf_size > INITIAL_SIZE) {
175 /* Shrink data buffer. */
176 newp = realloc(sh->data, shrink_size);
177 if (newp == NULL) {
178 /* Failed to shrink buffer... no matter. */
179 return EOK;
180 }
181
182 sh->data = newp;
183 sh->dbuf_size = shrink_size;
184 }
185
[3052ff4]186 return EOK;
187}
188
189/** Read text from sheet. */
190void sheet_copy_out(sheet_t *sh, spt_t const *spos, spt_t const *epos,
191 char *buf, size_t bufsize, spt_t *fpos)
192{
193 char *spp;
194 size_t range_sz;
195 size_t copy_sz;
196 size_t off, prev;
197 wchar_t c;
198
199 spp = sh->data + spos->b_off;
200 range_sz = epos->b_off - spos->b_off;
201 copy_sz = (range_sz < bufsize - 1) ? range_sz : bufsize - 1;
202
203 prev = off = 0;
204 do {
205 prev = off;
206 c = str_decode(spp, &off, copy_sz);
207 } while (c != '\0');
208
209 /* Crop copy_sz down to the last full character. */
210 copy_sz = prev;
211
212 memcpy(buf, spp, copy_sz);
213 buf[copy_sz] = '\0';
214
215 fpos->b_off = spos->b_off + copy_sz;
216 fpos->sh = sh;
217}
218
219/** Get point preceding or following character cell. */
220void sheet_get_cell_pt(sheet_t *sh, coord_t const *coord, enum dir_spec dir,
221 spt_t *pt)
222{
223 size_t cur_pos, prev_pos;
224 wchar_t c;
225 coord_t cc;
226
227 cc.row = cc.column = 1;
228 cur_pos = prev_pos = 0;
229 while (true) {
230 if (prev_pos >= sh->text_size) {
231 /* Cannot advance any further. */
232 break;
233 }
234
235 if ((cc.row >= coord->row && cc.column > coord->column) ||
236 cc.row > coord->row) {
237 /* We are past the requested coordinates. */
238 break;
239 }
240
241 prev_pos = cur_pos;
242
243 c = str_decode(sh->data, &cur_pos, sh->text_size);
244 if (c == '\n') {
245 ++cc.row;
246 cc.column = 1;
247 } else if (c == '\t') {
248 cc.column = 1 + ALIGN_UP(cc.column, TAB_WIDTH);
249 } else {
250 ++cc.column;
251 }
252 }
253
254 pt->sh = sh;
255 pt->b_off = (dir == dir_before) ? prev_pos : cur_pos;
256}
257
258/** Get the number of character cells a row occupies. */
259void sheet_get_row_width(sheet_t *sh, int row, int *length)
260{
261 coord_t coord;
262 spt_t pt;
263
264 /* Especially nasty hack */
265 coord.row = row;
266 coord.column = 65536;
[a35b458]267
[3052ff4]268 sheet_get_cell_pt(sh, &coord, dir_before, &pt);
269 spt_get_coord(&pt, &coord);
[8f6bffdd]270 *length = coord.column;
[3052ff4]271}
272
273/** Get the number of rows in a sheet. */
274void sheet_get_num_rows(sheet_t *sh, int *rows)
275{
276 int cnt;
277 size_t bo;
278
279 cnt = 1;
280 for (bo = 0; bo < sh->dbuf_size; ++bo) {
281 if (sh->data[bo] == '\n')
282 cnt += 1;
283 }
284
285 *rows = cnt;
286}
287
288/** Get the coordinates of an s-point. */
289void spt_get_coord(spt_t const *pos, coord_t *coord)
290{
291 size_t off;
292 coord_t cc;
293 wchar_t c;
294 sheet_t *sh;
295
296 sh = pos->sh;
297 cc.row = cc.column = 1;
298
299 off = 0;
300 while (off < pos->b_off && off < sh->text_size) {
301 c = str_decode(sh->data, &off, sh->text_size);
302 if (c == '\n') {
303 ++cc.row;
304 cc.column = 1;
305 } else if (c == '\t') {
306 cc.column = 1 + ALIGN_UP(cc.column, TAB_WIDTH);
307 } else {
308 ++cc.column;
309 }
310 }
311
312 *coord = cc;
313}
314
315/** Test if two s-points are equal. */
316bool spt_equal(spt_t const *a, spt_t const *b)
317{
318 return a->b_off == b->b_off;
319}
320
[7feb86e6]321/** Get a character at spt and return next spt */
322wchar_t spt_next_char(spt_t spt, spt_t *next)
323{
324 wchar_t ch = str_decode(spt.sh->data, &spt.b_off, spt.sh->text_size);
325 if (next)
326 *next = spt;
327 return ch;
328}
329
330wchar_t spt_prev_char(spt_t spt, spt_t *prev)
331{
332 wchar_t ch = str_decode_reverse(spt.sh->data, &spt.b_off, spt.sh->text_size);
333 if (prev)
334 *prev = spt;
335 return ch;
336}
337
[3052ff4]338/** Place a tag on the specified s-point. */
339void sheet_place_tag(sheet_t *sh, spt_t const *pt, tag_t *tag)
340{
341 tag->b_off = pt->b_off;
342 tag->sh = sh;
[b72efe8]343 list_append(&tag->link, &sh->tags);
[3052ff4]344}
345
346/** Remove a tag from the sheet. */
347void sheet_remove_tag(sheet_t *sh, tag_t *tag)
348{
349 list_remove(&tag->link);
350}
351
352/** Get s-point on which the tag is located right now. */
353void tag_get_pt(tag_t const *tag, spt_t *pt)
354{
355 pt->b_off = tag->b_off;
356 pt->sh = tag->sh;
357}
358
359/** @}
360 */
Note: See TracBrowser for help on using the repository browser.