shithub: cuefs

Download patch

ref: 0b3f9e8300f084a030c21db509c1b31cfcc29ab5
author: Tevo <estevan.cps@gmail.com>
date: Fri Nov 20 13:24:23 EST 2020

Semifunctional cuesheet parser

--- /dev/null	Thu Dec 31 12:39:09 2020
+++ b/cue.c	Fri Nov 20 13:24:23 2020
@@ -0,0 +1,129 @@
+#include <u.h>
+#include <libc.h>
+
+#include "cuefs.h"
+#include "y.tab.h"
+
+Timestamp
+parsetime(int min, int sec, int frames)
+{
+	sec += min*60;
+	frames += sec*75;
+
+	return (Timestamp){frames};
+}
+
+Cuesheet*
+newsheet(void)
+{
+	return emallocz(sizeof(Cuesheet), 1);
+}
+
+AFile*
+lastfile(Cuesheet *c)
+{
+	if(c->files == nil)
+		return nil;
+
+	if(c->curfile == nil)
+		c->curfile = c->files;
+
+	while(c->curfile->next != nil)
+		c->curfile = c->curfile->next;
+
+	return c->curfile;
+}
+
+Entry*
+lastentry(Cuesheet *c)
+{
+	if(c->entries == nil)
+		return nil;
+
+	if(c->curentry == nil)
+		c->curentry = c->entries;
+
+	while(c->curentry->next != nil)
+		c->curentry = c->curentry->next;
+
+	return c->curentry;
+}
+
+void
+atleast(Timestamps *ts, int val)
+{
+	if(ts->maxindex > val)
+		return;
+	ts->starts = erealloc(ts->starts, (val+1) * sizeof(*ts->starts));
+	ts->maxindex = val;
+}
+
+void
+setperformer(Cuesheet *c, char *artist)
+{
+	artist = strdup(artist);
+	if(c->curentry == nil)
+		setstr(nil, &c->performer, artist);
+	else
+		setstr(c->performer, &c->curentry->performer, artist);
+}
+
+void
+settitle(Cuesheet *c, char *title)
+{
+	title = strdup(title);
+	if(c->curentry == nil)
+		setstr(nil, &c->title, title);
+	else
+		setstr(nil, &c->curentry->title, title);
+}
+
+void
+addfile(Cuesheet *c, char *name, int format)
+{
+	AFile *new;
+
+	lastfile(c);
+
+	new = emalloc(sizeof(*new));
+	new->name = strdup(name);
+	new->type = format;
+	new->next = nil;
+
+	if(c->files == nil)
+		c->files = new;
+	else
+		c->curfile->next = new;
+
+	c->curfile = new;
+}
+
+void
+addnewtrack(Cuesheet *c, int i)
+{
+	Entry *new;
+
+	lastentry(c);
+
+	new = emallocz(sizeof(*new), 1);
+	new->file = c->curfile;
+	new->performer = c->performer;
+	new->index = i;
+
+	if(c->entries == nil)
+		c->entries = new;
+	else
+		c->curentry->next = nil;
+
+	c->curentry = new;
+}
+
+void
+settimestamp(Cuesheet *c, int i, Timestamp t)
+{
+	if(c->curentry == nil)
+		parserfatal("timestamp outside of track");
+
+	atleast(c->curentry, i);
+	c->curentry->starts[i] = t;
+}
--- /dev/null	Thu Dec 31 12:39:09 2020
+++ b/cue.l	Fri Nov 20 13:24:23 2020
@@ -0,0 +1,51 @@
+%{
+#include "cuefs.h"
+#include "y.tab.h"
+
+%}
+
+%%
+\".*\"		{
+					yylval.str = strdup(yytext+1);
+
+					if(yylval.str[yyleng-2] != '"')
+						parserwarn("improperly terminated string");
+					else
+						yylval.str[yyleng-2] = '\0';
+
+					return STRING;
+				}
+
+[0-9]+			{
+					yylval.i = atoi(yytext);
+					return INTEGER;
+				}
+
+"CATALOG"		return CATALOG;
+"CDTEXTFILE"	return CDTEXTFILE;
+"FILE"			return FILE;
+"FLAGS"			return FLAGS;
+"DCP"			return DCP;
+"4CH"			return CHAN4;
+"PRE"			return PREEMPH;
+"SCMS"			return SCMS;
+"INDEX"			return INDEX;
+"ISRC"			return ISRC;
+"PERFORMER"		return PERFORMER;
+"POSTGAP"		return POSTGAP;
+"PREGAP"		return PREGAP;
+"SONGWRITER"	return SONGWRITER;
+"TITLE"			return TITLE;
+"TRACK"			return TRACK;
+"WAVE"			return FWAVE;
+"MP3"			return FMP3;
+"AIFF"			return FAIFF;
+"BINARY"		return FBINARY;
+"MOTOROLA"		return FMOTOROLA;
+"AUDIO"			return AUDIO;
+
+[:\n]			return *yytext;
+
+"REM".*\n		;
+[ \t]+			;
+%%
--- /dev/null	Thu Dec 31 12:39:09 2020
+++ b/cue.y	Fri Nov 20 13:24:23 2020
@@ -0,0 +1,49 @@
+%{
+#include <u.h>
+#include <libc.h>
+
+#include "cuefs.h"
+%}
+
+%union
+{
+	int i;
+	char *str;
+	Timestamp time;
+}
+
+%token <i>   INTEGER
+%token <str> STRING
+
+%type <i>    filetype
+%type <time> timestamp
+
+%token CATALOG CDTEXTFILE FLAGS DCP CHAN4 PREEMPH SCMS INDEX
+%token ISRC PERFORMER POSTGAP PREGAP SONGWRITER TITLE TRACK
+%token FILE FWAVE FMP3 FAIFF FBINARY FMOTOROLA AUDIO
+
+%%
+cuesheet:
+	| expr '\n' cuesheet
+	;
+
+expr:
+	| PERFORMER STRING			{ setperformer(cursheet, $2); }
+	| TITLE STRING				{ settitle(cursheet, $2); }
+	| FILE STRING filetype		{ addfile(cursheet, $2, $3); }
+	| TRACK INTEGER AUDIO		{ addnewtrack(cursheet, $2); }
+	| INDEX INTEGER timestamp	{ settimestamp(cursheet, $2, $3); }
+	;
+
+filetype:
+	FWAVE			{ $$ = WAVE; }
+	| FMP3			{ $$ = MP3; }
+	| FAIFF			{ $$ = AIFF; }
+	| FBINARY		{ $$ = BINARY; }
+	| FMOTOROLA		{ $$ = MOTOROLA; }
+	;
+
+timestamp:
+	INTEGER ':' INTEGER ':' INTEGER		{ $$ = parsetime($1, $3, $5); }
+	;
+%%
--- /dev/null	Thu Dec 31 12:39:09 2020
+++ b/cuefs.h	Fri Nov 20 13:24:23 2020
@@ -0,0 +1,72 @@
+
+extern char *fname;
+extern int infd;
+
+/* lex/yacc */
+int yylex(void);
+int yyparse(void);
+void yyerror(char*);
+
+/* misc.c */
+void* erealloc(void*, ulong);
+void* emallocz(ulong, int);
+void* emalloc(ulong);
+
+char* setstr(char*, char**, char*);
+
+void parserwarn(char*, ...);
+void parserfatal(char*, ...);
+
+/*****/
+
+enum
+{
+	WAVE, MP3, AIFF, BINARY, MOTOROLA
+};
+
+typedef struct
+{
+	u64int frames;
+} Timestamp;
+
+typedef struct AFile
+{
+	char *name;
+	int type;
+	struct AFile *next;
+} AFile;
+
+typedef struct
+{
+	u8int maxindex;
+	Timestamp *starts;
+} Timestamps;
+
+typedef struct Entry
+{
+	Timestamps;
+	int index;
+	AFile *file;
+	char *title, *performer;
+	Timestamp start;
+	struct Entry *next;
+} Entry;
+
+typedef struct
+{
+	char *title, *performer;
+	AFile *files, *curfile;
+	Entry *entries, *curentry;
+} Cuesheet;
+
+extern Cuesheet *cursheet;
+
+Timestamp parsetime(int, int, int);
+
+Cuesheet* newsheet(void);
+
+void setperformer(Cuesheet*, char*);
+void settitle(Cuesheet*, char*);
+void addfile(Cuesheet*, char*, int);
+void addnewtrack(Cuesheet*, int);
+void settimestamp(Cuesheet*, int, Timestamp);
--- /dev/null	Thu Dec 31 12:39:09 2020
+++ b/fs.c	Fri Nov 20 13:24:23 2020
@@ -0,0 +1,7 @@
+#include <u.h>
+#include <libc.h>
+
+#include "cuefs.h"
+#include "y.tab.h"
+
+Cuesheet *cursheet;
--- /dev/null	Thu Dec 31 12:39:09 2020
+++ b/main.c	Fri Nov 20 13:24:23 2020
@@ -0,0 +1,38 @@
+#include <u.h>
+#include <libc.h>
+
+#include "cuefs.h"
+
+char *fname = "<stdin>";
+
+void
+usage(void)
+{
+	fprint(2, "usage: %s\n", argv0);
+	exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+	ARGBEGIN {
+	default:
+		usage();
+	} ARGEND;
+
+	if(argc > 1)
+		usage();
+
+	if(argc == 1)
+	{
+		fname = argv[0];
+		infd = open(fname, OREAD);
+	}
+
+	cursheet = newsheet();
+	yyparse();
+
+	close(infd);
+
+	exits(0);
+}
--- /dev/null	Thu Dec 31 12:39:09 2020
+++ b/misc.c	Fri Nov 20 13:24:23 2020
@@ -0,0 +1,78 @@
+#include <u.h>
+#include <libc.h>
+
+#include "cuefs.h"
+#include "y.tab.h"
+
+void*
+erealloc(void *p, ulong s)
+{
+	p = realloc(p, s);
+	if(s > 0 && p == nil)
+		sysfatal("realloc: %r");
+	setrealloctag(p, getcallerpc(&p));
+	return p;
+}
+
+void*
+emallocz(ulong s, int clr)
+{
+	void* p = mallocz(s, clr);
+	if(p == nil)
+		sysfatal("mallocz: %r");
+	setmalloctag(p, getcallerpc(&s));
+	return p;
+}
+
+void*
+emalloc(ulong s)
+{
+	void* p = malloc(s);
+	if(p == nil)
+		sysfatal("malloc: %r");
+	setmalloctag(p, getcallerpc(&s));
+	return p;
+}
+
+void
+yyerror(char *str)
+{
+	extern int yylineno;
+	fprint(2, "%s:%d: %s\n", fname, yylineno, str);
+}
+
+char*
+setstr(char *baseline, char **dest, char *str)
+{
+	if(*dest != nil && *dest != baseline)
+		free(*dest);
+	*dest = str;
+	return str;
+}
+
+void
+parserwarn(char *fmt, ...)
+{
+	char *str;
+	va_list args;
+
+	va_start(args, fmt);
+	str = vsmprint(fmt, args);
+	yyerror(str);
+	free(str);
+	va_end(args);
+}
+
+void
+parserfatal(char *fmt, ...)
+{
+	char *str;
+	va_list args;
+
+	va_start(args, fmt);
+	str = vsmprint(fmt, args);
+	yyerror(str);
+	free(str);
+	va_end(args);
+	exits("cantparse");
+}
--- /dev/null	Thu Dec 31 12:39:09 2020
+++ b/mkfile	Fri Nov 20 13:24:23 2020
@@ -0,0 +1,30 @@
+</$objtype/mkfile
+
+LFILES=\
+	cue.l
+
+YFILES=\
+	cue.y
+
+OBJ=\
+	lex.yy.$O	\
+	y.tab.$O	\
+	main.$O		\
+	misc.$O		\
+	cue.$O		\
+	fs.$O
+
+%.$O: %.c
+	$CC $CFLAGS $prereq
+
+$O.out: $OBJ
+	$LD $prereq
+
+lex.yy.c: $LFILES y.tab.h
+	$LEX -9 $LFILES
+
+y.tab.c y.tab.h: $YFILES
+	$YACC -d $YFILES
+
+clean nuke:V:
+	rm -f lex.yy.c y.debug y.tab.[ch] *.[$OS] [$OS].*