source: mainline/uspace/app/edit/sheet.c@ 8a6ba94

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 8a6ba94 was b72efe8, checked in by Jiri Svoboda <jiri@…>, 14 years ago

Separate list_t typedef from link_t (user-space part).

  • list_t represents lists
  • Use list_first(), list_last(), list_empty() where appropriate
  • Use list_foreach() where possible
  • assert_link_not_used()
  • usb_hid_report_path_free() shall not unlink the path, caller must do it
  • Property mode set to 100644
File size: 8.1 KB
Line 
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>
52#include <str.h>
53#include <errno.h>
54#include <adt/list.h>
55#include <align.h>
56#include <macros.h>
57
58#include "sheet.h"
59
60enum {
61 TAB_WIDTH = 8,
62
63 /** Initial of dat buffer in bytes */
64 INITIAL_SIZE = 32
65};
66
67/** Initialize an empty sheet. */
68int sheet_init(sheet_t *sh)
69{
70 sh->dbuf_size = INITIAL_SIZE;
71 sh->text_size = 0;
72
73 sh->data = malloc(sh->dbuf_size);
74 if (sh->data == NULL)
75 return ENOMEM;
76
77 list_initialize(&sh->tags);
78
79 return EOK;
80}
81
82/** Insert text into sheet.
83 *
84 * @param sh Sheet to insert to.
85 * @param pos Point where to insert.
86 * @param dir Whether to insert before or after the point (affects tags).
87 * @param str The text to insert (printable characters, tabs, newlines).
88 *
89 * @return EOK on success or negative error code.
90 *
91 * @note @a dir affects which way tags that were placed on @a pos will
92 * move. If @a dir is @c dir_before, the tags will move forward
93 * and vice versa.
94 */
95int sheet_insert(sheet_t *sh, spt_t *pos, enum dir_spec dir, char *str)
96{
97 char *ipp;
98 size_t sz;
99 tag_t *tag;
100 char *newp;
101
102 sz = str_size(str);
103 if (sh->text_size + sz > sh->dbuf_size) {
104 /* Enlarge data buffer. */
105 newp = realloc(sh->data, sh->dbuf_size * 2);
106 if (newp == NULL)
107 return ELIMIT;
108
109 sh->data = newp;
110 sh->dbuf_size = sh->dbuf_size * 2;
111 }
112
113 ipp = sh->data + pos->b_off;
114
115 /* Copy data. */
116 memmove(ipp + sz, ipp, sh->text_size - pos->b_off);
117 memcpy(ipp, str, sz);
118 sh->text_size += sz;
119
120 /* Adjust tags. */
121
122 list_foreach(sh->tags, link) {
123 tag = list_get_instance(link, tag_t, link);
124
125 if (tag->b_off > pos->b_off)
126 tag->b_off += sz;
127 else if (tag->b_off == pos->b_off && dir == dir_before)
128 tag->b_off += sz;
129 }
130
131 return EOK;
132}
133
134/** Delete text from sheet.
135 *
136 * Deletes the range of text between two points from the sheet.
137 *
138 * @param sh Sheet to delete from.
139 * @param spos Starting point.
140 * @param epos Ending point.
141 *
142 * @return EOK on success or negative error code.
143 **/
144int sheet_delete(sheet_t *sh, spt_t *spos, spt_t *epos)
145{
146 char *spp;
147 size_t sz;
148 tag_t *tag;
149 char *newp;
150 size_t shrink_size;
151
152 spp = sh->data + spos->b_off;
153 sz = epos->b_off - spos->b_off;
154
155 memmove(spp, spp + sz, sh->text_size - (spos->b_off + sz));
156 sh->text_size -= sz;
157
158 /* Adjust tags. */
159 list_foreach(sh->tags, link) {
160 tag = list_get_instance(link, tag_t, link);
161
162 if (tag->b_off >= epos->b_off)
163 tag->b_off -= sz;
164 else if (tag->b_off >= spos->b_off)
165 tag->b_off = spos->b_off;
166 }
167
168 /* See if we should free up some memory. */
169 shrink_size = max(sh->dbuf_size / 4, INITIAL_SIZE);
170 if (sh->text_size <= shrink_size && sh->dbuf_size > INITIAL_SIZE) {
171 /* Shrink data buffer. */
172 newp = realloc(sh->data, shrink_size);
173 if (newp == NULL) {
174 /* Failed to shrink buffer... no matter. */
175 return EOK;
176 }
177
178 sh->data = newp;
179 sh->dbuf_size = shrink_size;
180 }
181
182 return EOK;
183}
184
185/** Read text from sheet. */
186void sheet_copy_out(sheet_t *sh, spt_t const *spos, spt_t const *epos,
187 char *buf, size_t bufsize, spt_t *fpos)
188{
189 char *spp;
190 size_t range_sz;
191 size_t copy_sz;
192 size_t off, prev;
193 wchar_t c;
194
195 spp = sh->data + spos->b_off;
196 range_sz = epos->b_off - spos->b_off;
197 copy_sz = (range_sz < bufsize - 1) ? range_sz : bufsize - 1;
198
199 prev = off = 0;
200 do {
201 prev = off;
202 c = str_decode(spp, &off, copy_sz);
203 } while (c != '\0');
204
205 /* Crop copy_sz down to the last full character. */
206 copy_sz = prev;
207
208 memcpy(buf, spp, copy_sz);
209 buf[copy_sz] = '\0';
210
211 fpos->b_off = spos->b_off + copy_sz;
212 fpos->sh = sh;
213}
214
215/** Get point preceding or following character cell. */
216void sheet_get_cell_pt(sheet_t *sh, coord_t const *coord, enum dir_spec dir,
217 spt_t *pt)
218{
219 size_t cur_pos, prev_pos;
220 wchar_t c;
221 coord_t cc;
222
223 cc.row = cc.column = 1;
224 cur_pos = prev_pos = 0;
225 while (true) {
226 if (prev_pos >= sh->text_size) {
227 /* Cannot advance any further. */
228 break;
229 }
230
231 if ((cc.row >= coord->row && cc.column > coord->column) ||
232 cc.row > coord->row) {
233 /* We are past the requested coordinates. */
234 break;
235 }
236
237 prev_pos = cur_pos;
238
239 c = str_decode(sh->data, &cur_pos, sh->text_size);
240 if (c == '\n') {
241 ++cc.row;
242 cc.column = 1;
243 } else if (c == '\t') {
244 cc.column = 1 + ALIGN_UP(cc.column, TAB_WIDTH);
245 } else {
246 ++cc.column;
247 }
248 }
249
250 pt->sh = sh;
251 pt->b_off = (dir == dir_before) ? prev_pos : cur_pos;
252}
253
254/** Get the number of character cells a row occupies. */
255void sheet_get_row_width(sheet_t *sh, int row, int *length)
256{
257 coord_t coord;
258 spt_t pt;
259
260 /* Especially nasty hack */
261 coord.row = row;
262 coord.column = 65536;
263
264 sheet_get_cell_pt(sh, &coord, dir_before, &pt);
265 spt_get_coord(&pt, &coord);
266 *length = coord.column - 1;
267}
268
269/** Get the number of rows in a sheet. */
270void sheet_get_num_rows(sheet_t *sh, int *rows)
271{
272 int cnt;
273 size_t bo;
274
275 cnt = 1;
276 for (bo = 0; bo < sh->dbuf_size; ++bo) {
277 if (sh->data[bo] == '\n')
278 cnt += 1;
279 }
280
281 *rows = cnt;
282}
283
284/** Get the coordinates of an s-point. */
285void spt_get_coord(spt_t const *pos, coord_t *coord)
286{
287 size_t off;
288 coord_t cc;
289 wchar_t c;
290 sheet_t *sh;
291
292 sh = pos->sh;
293 cc.row = cc.column = 1;
294
295 off = 0;
296 while (off < pos->b_off && off < sh->text_size) {
297 c = str_decode(sh->data, &off, sh->text_size);
298 if (c == '\n') {
299 ++cc.row;
300 cc.column = 1;
301 } else if (c == '\t') {
302 cc.column = 1 + ALIGN_UP(cc.column, TAB_WIDTH);
303 } else {
304 ++cc.column;
305 }
306 }
307
308 *coord = cc;
309}
310
311/** Test if two s-points are equal. */
312bool spt_equal(spt_t const *a, spt_t const *b)
313{
314 return a->b_off == b->b_off;
315}
316
317/** Place a tag on the specified s-point. */
318void sheet_place_tag(sheet_t *sh, spt_t const *pt, tag_t *tag)
319{
320 tag->b_off = pt->b_off;
321 tag->sh = sh;
322 list_append(&tag->link, &sh->tags);
323}
324
325/** Remove a tag from the sheet. */
326void sheet_remove_tag(sheet_t *sh, tag_t *tag)
327{
328 list_remove(&tag->link);
329}
330
331/** Get s-point on which the tag is located right now. */
332void tag_get_pt(tag_t const *tag, spt_t *pt)
333{
334 pt->b_off = tag->b_off;
335 pt->sh = tag->sh;
336}
337
338/** @}
339 */
Note: See TracBrowser for help on using the repository browser.