amp

pcm player/editor for plan9
git clone git://nsmpr.xyz/amp.git
Log | Files | Refs | README

commit c26ca5332605a4fb9d201a79fc1fdb8b1e6385d0
parent ba7b99c16f3b734f1d1cb4facb194b57aececd20
Author: glenda <glenda@kobeni>
Date:   Sun, 18 Feb 2024 18:40:52 +0000

fs: implement fcut trunc

Diffstat:
Mfs.c | 65+++++++++++++++++++++++++++++++++++++++--------------------------
Mpages.c | 26++++++++++++++++++++++++++
Mpages.h | 1+
3 files changed, 66 insertions(+), 26 deletions(-)

diff --git a/fs.c b/fs.c @@ -22,6 +22,7 @@ void fs_open(Req *r); void fs_read(Req *r); void fs_write(Req *r); +void fcut_open(Req *r); void fcut_write(Req *r); void normalize_sel(void); @@ -73,14 +74,12 @@ fs_open(Req *r) char *rstr = nil; File *file = r->fid->file; uchar mode = r->ifcall.mode; - if ((mode & OTRUNC) == 0) goto end; - if (file == fctl) goto end; if (file == fcut) { - // if needed split pages at 'min' and 'max' in two - // remove pages from min to max - rstr = "trunc not implemented yet"; + fcut_open(r); goto end; } + if ((mode & OTRUNC) == 0) goto end; + if (file == fctl) goto end; if (file == fdata) { pg.length = 0; fdata->length = 0; @@ -162,37 +161,51 @@ fs_write(Req *r) } void +fcut_open(Req *r) +{ + vlong min, max; + min = sel.min * FrameSize; + max = sel.max * FrameSize; + + if ((r->ifcall.mode & OTRUNC) != 0) { + Page *maxpg = splitpage(&pg, max); + Page *minpg = splitpage(&pg, min); + assert(minpg != nil); + assert(maxpg != nil); + if (minpg->prev != nil) { + minpg->prev->next = maxpg; + maxpg->prev = minpg->prev; + } else { + pg.start = maxpg; + maxpg->prev = nil; + } + while (minpg != maxpg) { + Page *fp = minpg; + fp->as->len = 0; + minpg = fp->next; + freepage(fp); + } + pg.length -= max - min; + fdata->length = pg.length; + fcut->length = 0; + sel.max = sel.min; + normalize_sel(); + } +} + +void fcut_write(Req *r) { Page *maxpage; vlong min, max, offset; - long count, d; + long count; min = sel.min * FrameSize; max = sel.max * FrameSize; - // find page that 'max' lands on - offset = 0; - maxpage = pg.start; - while ((maxpage != nil) && (offset + maxpage->as->len < max)) { - offset += maxpage->as->len; - maxpage = maxpage->next; - } + maxpage = splitpage(&pg, max); if (maxpage == nil) { maxpage = addpage(&pg); } - d = max - offset; - if (d > 0) { - // split page in two - Page *s = duppage(maxpage); - s->as->len = d; - s->next = maxpage; - if (s->prev != nil) s->prev->next = s; - else pg.start = s; - maxpage->as->len -= d; - maxpage->as->cap -= d; - maxpage->as->p += d; - maxpage->prev = s; - } // insert more pages as needed offset = r->ifcall.offset + min; count = r->ifcall.count; diff --git a/pages.c b/pages.c @@ -151,3 +151,29 @@ addpage(PBuf *pb) pb->size += new->as->len; return new; } + +Page * +splitpage(PBuf *pb, vlong offset) +{ + vlong d, count = 0; + Page *sp = pb->start; + // find page at offset + while ((sp != nil) && (count + sp->as->len < offset)) { + count += sp->as->len; + sp = sp->next; + } + if (sp == nil) return nil; + d = offset - count; + if (d > 0) { + Page *np = duppage(sp); + np->as->len = d; + np->next = sp; + if (np->prev != nil) np->prev->next = np; + else pb->start = np; + sp->as->len -= d; + sp->as->cap -= d; + sp->as->p += d; + sp->prev = np; + } + return sp; +} diff --git a/pages.h b/pages.h @@ -52,3 +52,4 @@ Page * allocpage(void); Page * duppage(Page *); void freepage(Page *); Page * addpage(PBuf *pb); +Page * splitpage(PBuf *pb, vlong offset);