sheet.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2009 Jiri Svoboda
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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                 /* Enlarge data buffer. */
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         /* Copy data. */
00117         memmove(ipp + sz, ipp, sh->text_size - pos->b_off);
00118         memcpy(ipp, str, sz);
00119         sh->text_size += sz;
00120 
00121         /* Adjust tags. */
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         /* Adjust tags. */
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         /* See if we should free up some memory. */
00177         shrink_size = max(sh->dbuf_size / 4, INITIAL_SIZE);
00178         if (sh->text_size <= shrink_size && sh->dbuf_size > INITIAL_SIZE) {
00179                 /* Shrink data buffer. */
00180                 newp = realloc(sh->data, shrink_size);
00181                 if (newp == NULL) {
00182                         /* Failed to shrink buffer... no matter. */
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         /* Crop copy_sz down to the last full character. */
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                         /* Cannot advance any further. */
00236                         break;
00237                 }
00238 
00239                 if ((cc.row >= coord->row && cc.column > coord->column) ||
00240                     cc.row > coord->row) {
00241                         /* We are past the requested coordinates. */
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         /* Especially nasty hack */
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 

Generated on Thu Jun 2 07:45:41 2011 for HelenOS/USB by  doxygen 1.4.7