amp

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

fs.c (5098B)


      1 #include <u.h>
      2 #include <libc.h>
      3 #include <fcall.h>
      4 #include <thread.h>
      5 #include <9p.h>
      6 
      7 #include "pages.h"
      8 
      9 enum {
     10 	FrameSize = sizeof(s16int) * 2,
     11 };
     12 
     13 PBuf pg;
     14 
     15 struct {
     16 	int min;
     17 	int max;
     18 	char str[12*3+1]; // see update_selstr
     19 } sel;
     20 
     21 void fs_open(Req *r);
     22 void fs_read(Req *r);
     23 void fs_write(Req *r);
     24 
     25 void fcut_open(Req *r);
     26 void fcut_write(Req *r);
     27 
     28 void normalize_sel(void);
     29 void update_selstr(void);
     30 
     31 Srv ampsrv = {
     32 	.read = fs_read,
     33 	.write = fs_write,
     34 	.open = fs_open,
     35 };
     36 
     37 File *fdata, *fcut, *fctl;
     38 char *service, *mountpath = "/mnt/amp";
     39 
     40 void
     41 usage(void)
     42 {
     43 	fprint(2,"usage: %s\n", argv0);
     44 	threadexitsall("usage");
     45 }
     46 
     47 void
     48 threadmain(int argc, char **argv)
     49 {
     50 	ARGBEGIN {
     51 	case 'D':
     52 		chatty9p++;
     53 		break;
     54 	case 's':
     55 		service = EARGF(usage());
     56 		break;
     57 	case 'm':
     58 		mountpath = EARGF(usage());
     59 		break;
     60 	default: usage();
     61 	} ARGEND
     62 	if (argc != 0) usage();
     63 	update_selstr();
     64 	ampsrv.tree = alloctree("amp", "amp", DMDIR|0555, nil);
     65 	fdata = createfile(ampsrv.tree->root, "data", "amp", 0666, nil);
     66 	fcut = createfile(ampsrv.tree->root, "cut", "amp", 0666, nil);
     67 	fctl = createfile(ampsrv.tree->root, "ctl", "amp", 0666, nil);
     68 	threadpostmountsrv(&ampsrv, service, mountpath, MREPL);
     69 }
     70 
     71 void
     72 fs_open(Req *r)
     73 {
     74 	char *rstr = nil;
     75 	File *file = r->fid->file;
     76 	uchar mode = r->ifcall.mode;
     77 	if (file == fcut) {
     78 		fcut_open(r);
     79 		goto end;
     80 	}
     81 	if ((mode & OTRUNC) == 0) goto end;
     82 	if (file == fctl) goto end;
     83 	if (file == fdata) {
     84 		pg.length = 0;
     85 		fdata->length = 0;
     86 		// TODO: free pages ???
     87 		// probably better to do it on fs_close()
     88 		goto end;
     89 	}
     90 	rstr = "what";
     91 end:
     92 	respond(r, rstr);
     93 }
     94 
     95 void
     96 fs_read(Req *r)
     97 {
     98 	if (r->fid->file == fdata) {
     99 		r->ofcall.count = pbread(&pg, r->ofcall.data,
    100 		  r->ifcall.count, r->ifcall.offset);
    101 		respond(r, nil);
    102 	} else if (r->fid->file == fcut) {
    103 		vlong min = sel.min * FrameSize;
    104 		vlong max = sel.max * FrameSize;
    105 		r->ifcall.offset += min;
    106 		if (r->ifcall.offset + r->ifcall.count > max)
    107 			r->ifcall.count = max - r->ifcall.offset;
    108 		if (r->ifcall.offset > max) r->ifcall.count = 0;
    109 		r->ofcall.count = pbread(&pg, r->ofcall.data,
    110 		  r->ifcall.count, r->ifcall.offset);
    111 		respond(r, nil);
    112 	} else if (r->fid->file == fctl) {
    113 		readstr(r, sel.str);
    114 		respond(r, nil);
    115 	} else {
    116 		respond(r, "nope");
    117 	}
    118 }
    119 
    120 void
    121 fs_write(Req *r)
    122 {
    123 	if (r->fid->file == fdata) {
    124 		r->ofcall.count = pbwrite(&pg, r->ifcall.data,
    125 		  r->ifcall.count, r->ifcall.offset);
    126 		if (pg.length > fdata->length) fdata->length = pg.length;
    127 		update_selstr();
    128 		respond(r, nil);
    129 	} else if (r->fid->file == fcut) {
    130 		fcut_write(r);
    131 		update_selstr();
    132 		respond(r, nil);
    133 	} else if (r->fid->file == fctl) {
    134 		int newmin, newmax;
    135 		char *np, *rp;
    136 		np = r->ifcall.data;
    137 		newmin = strtol(np, &rp, 10);
    138 		if (rp <= np) {
    139 			respond(r, "bad first value");
    140 			return;
    141 		}
    142 		newmax = strtol(rp, &rp, 10);
    143 		if (rp <= np) {
    144 			respond(r, "bad second value");
    145 			return;
    146 		}
    147 		if (rp - np > r->ifcall.count) {
    148 			respond(r, "somehow buffer overrun");
    149 			return;
    150 		}
    151 		sel.min = newmin;
    152 		sel.max = newmax;
    153 		normalize_sel();
    154 		update_selstr();
    155 		fcut->length = (sel.max - sel.min) * FrameSize;
    156 		r->ofcall.count = r->ifcall.count;
    157 		respond(r, nil);
    158 	} else {
    159 		respond(r, "nope");
    160 	}
    161 }
    162 
    163 void
    164 fcut_open(Req *r)
    165 {
    166 	vlong min, max;
    167 	min = sel.min * FrameSize;
    168 	max = sel.max * FrameSize;
    169 
    170 	if ((r->ifcall.mode & OTRUNC) != 0) {
    171 		Page *maxpg = splitpage(&pg, max);
    172 		Page *minpg = splitpage(&pg, min);
    173 		assert(minpg != nil);
    174 		assert(maxpg != nil);
    175 		if (minpg->prev != nil) {
    176 			minpg->prev->next = maxpg;
    177 			maxpg->prev = minpg->prev;
    178 		} else {
    179 			pg.start = maxpg;
    180 			maxpg->prev = nil;
    181 		}
    182 		while (minpg != maxpg) {
    183 			Page *fp = minpg;
    184 			fp->as->len = 0;
    185 			minpg = fp->next;
    186 			freepage(fp);
    187 		}
    188 		pg.length -= max - min;
    189 		fdata->length = pg.length;
    190 		fcut->length = 0;
    191 		sel.max = sel.min;
    192 		normalize_sel();
    193 	}
    194 }
    195 
    196 void
    197 fcut_write(Req *r)
    198 {
    199 	Page *maxpage;
    200 	vlong min, max, offset;
    201 	long count;
    202 	min = sel.min * FrameSize;
    203 	max = sel.max * FrameSize;
    204 
    205 	maxpage = splitpage(&pg, max);
    206 	if (maxpage == nil) {
    207 		maxpage = addpage(&pg);
    208 	}
    209 	// insert more pages as needed
    210 	offset = r->ifcall.offset + min;
    211 	count = r->ifcall.count;
    212 	while (offset + count > max) {
    213 		long n = offset + count - max;
    214 		if (n > PageSize) n = PageSize;
    215 		Page *ins = allocpage();
    216 		ins->as->len = n;
    217 		ins->next = maxpage;
    218 		ins->prev = maxpage->prev;
    219 		if (maxpage->prev != nil) maxpage->prev->next = ins;
    220 		else {
    221 			pg.start = ins;
    222 		}
    223 		maxpage->prev = ins;
    224 		max += n;
    225 		pg.length  += n;
    226 	}
    227 	sel.max = max / FrameSize;
    228 	normalize_sel();
    229 	fcut->length = (sel.max - sel.min) * FrameSize;
    230 	fdata->length = pg.length;
    231 	// write to pagebuffer as usual
    232 	r->ofcall.count = pbwrite(&pg, r->ifcall.data, count, offset);
    233 }
    234 
    235 void
    236 normalize_sel(void)
    237 {
    238 	vlong bufmax = pg.length / FrameSize;
    239 	if (sel.min > bufmax) sel.min = bufmax;
    240 	if (sel.max > bufmax) sel.max = bufmax;
    241 	if (sel.min > sel.max) {
    242 		int x = sel.max;
    243 		sel.max = sel.min;
    244 		sel.min = x;
    245 	}
    246 }
    247 
    248 void
    249 update_selstr(void)
    250 {
    251 	snprint(sel.str, sizeof(sel.str), "%11d %11d %11d \n",
    252 	  sel.min, sel.max, (int)(pg.length / FrameSize));
    253 }