shithub: libtags

Download patch

ref: 92b806c9c3f5b3a201c373299835953605a2a2a3
parent: eaaa32c852f9c8229007be1f2c1842eb21eededb
author: Sigrid Solveig Haflínudóttir <[email protected]>
date: Sat Mar 2 12:58:21 EST 2024

sync last changes from 9front and switch to meson

Since 9front ships with its own copy of libtags, it makes
more sense to turn this repo into a proper Unix-like supported
one and clean up.

--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,1 @@
-*.[1-9]
-*.o
-*.out
-result
+build/
binary files a/437.c b/437.c differ
--- a/8859.c
+++ b/8859.c
@@ -2,7 +2,7 @@
 #include "tagspriv.h"
 
 int
-iso88591toutf8(uchar *o, int osz, const uchar *s, int sz)
+iso88591toutf8(uint8_t *o, int osz, const uint8_t *s, int sz)
 {
 	int i;
 
--- a/README.md
+++ b/README.md
@@ -25,7 +25,6 @@
 | thread safe    | yes             | ???              | ???              |
 | speed          | ultra-fast      | slow             | fast             |
 | tag writing    | no, not a goal  | yes              | yes              |
-| Plan 9 support | yes, native     | no               | no               |
 
 CPU time (784 files: mp3, ogg, flac):
 
--- a/examples/mkfile
+++ /dev/null
@@ -1,13 +1,0 @@
-</$objtype/mkfile
-
-TARG=readtags
-
-OFILES=\
-	readtags.$O\
-	
-BIN=/$objtype/bin/audio
-
-HFILES=\
-	/sys/include/tags.h\
-
-</sys/src/cmd/mkone
--- a/examples/readtags.c
+++ b/examples/readtags.c
@@ -1,42 +1,30 @@
-#ifdef __unix__
-#define _DEFAULT_SOURCE
 #include <fcntl.h>
 #include <stdio.h>
 #include <sys/types.h>
 #include <unistd.h>
-#define print printf
-#define seek lseek
-#define nil NULL
-#define OREAD O_RDONLY
 #define USED(x) (void)x
-#else
-#include <u.h>
-#include <libc.h>
-#endif
-#include <tags.h>
+#include "tags.h"
 
 typedef struct Aux Aux;
 
-struct Aux
-{
+struct Aux {
 	int fd;
 };
 
-static const char *t2s[] =
-{
-	[Tartist] = "artist",
+static const char *t2s[] = {
 	[Talbum] = "album",
-	[Ttitle] = "title",
-	[Tdate] = "date",
-	[Ttrack] = "track",
 	[Talbumgain] = "albumgain",
 	[Talbumpeak] = "albumpeak",
-	[Ttrackgain] = "trackgain",
-	[Ttrackpeak] = "trackpeak",
+	[Tartist] = "artist",
+	[Tcomment] = "comment",
+	[Tcomposer] = "composer",
+	[Tdate] = "date",
 	[Tgenre] = "genre",
 	[Timage] = "image",
-	[Tcomposer] = "composer",
-	[Tcomment] = "comment",
+	[Ttitle] = "title",
+	[Ttrack] = "track",
+	[Ttrackgain] = "trackgain",
+	[Ttrackpeak] = "trackpeak",
 };
 
 static void
@@ -44,11 +32,11 @@
 {
 	USED(ctx); USED(k); USED(f);
 	if(t == Timage)
-		print("%-12s %s %d %d\n", t2s[t], v, offset, size);
+		printf("%-12s %s %d %d\n", t2s[t], v, offset, size);
 	else if(t == Tunknown)
-		print("%-12s %s\n", k, v);
+		printf("%-12s %s\n", k, v);
 	else
-		print("%-12s %s\n", t2s[t], v);
+		printf("%-12s %s\n", t2s[t], v);
 }
 
 static void
@@ -68,7 +56,7 @@
 ctxseek(Tagctx *ctx, int offset, int whence)
 {
 	Aux *aux = ctx->aux;
-	return seek(aux->fd, offset, whence);
+	return lseek(aux->fd, offset, whence);
 }
 
 int
@@ -77,8 +65,7 @@
 	int i;
 	char buf[256];
 	Aux aux;
-	Tagctx ctx =
-	{
+	Tagctx ctx = {
 		.read = ctxread,
 		.seek = ctxseek,
 		.tag = tag,
@@ -89,30 +76,30 @@
 	};
 
 	if(argc < 2){
-		print("usage: readtags FILE...\n");
+		printf("usage: readtags FILE...\n");
 		return -1;
 	}
 
 	for(i = 1; i < argc; i++){
-		print("*** %s\n", argv[i]);
-		if((aux.fd = open(argv[i], OREAD)) < 0)
-			print("failed to open\n");
+		printf("*** %s\n", argv[i]);
+		if((aux.fd = open(argv[i], O_RDONLY)) < 0)
+			perror("failed to open");
 		else{
 			if(tagsget(&ctx) != 0)
-				print("no tags or failed to read tags\n");
+				printf("no tags or failed to read tags\n");
 			else{
 				if(ctx.duration > 0)
-					print("%-12s %d ms\n", "duration", ctx.duration);
+					printf("%-12s %d ms\n", "duration", ctx.duration);
 				if(ctx.samplerate > 0)
-					print("%-12s %d\n", "samplerate", ctx.samplerate);
+					printf("%-12s %d\n", "samplerate", ctx.samplerate);
 				if(ctx.channels > 0)
-					print("%-12s %d\n", "channels", ctx.channels);
+					printf("%-12s %d\n", "channels", ctx.channels);
 				if(ctx.bitrate > 0)
-					print("%-12s %d\n", "bitrate", ctx.bitrate);
+					printf("%-12s %d\n", "bitrate", ctx.bitrate);
 			}
 			close(aux.fd);
 		}
-		print("\n");
+		printf("\n");
 	}
 	return 0;
 }
--- a/flac.c
+++ b/flac.c
@@ -6,11 +6,11 @@
 int
 tagflac(Tagctx *ctx)
 {
-	uchar *d;
+	uint8_t *d;
 	int sz, last;
-	uvlong g;
+	uint64_t g;
 
-	d = (uchar*)ctx->buf;
+	d = (uint8_t*)ctx->buf;
 	/* 8 bytes for marker, block type, length. 18 bytes for the stream info */
 	if(ctx->read(ctx, d, 8+18) != 8+18 || memcmp(d, "fLaC\x00", 5) != 0)
 		return -1;
@@ -21,7 +21,7 @@
 	if(ctx->samplerate < 1 || ctx->channels < 1)
 		return -1;
 
-	g = (uvlong)(d[21] & 0xf)<<32 | beu3(&d[22])<<8 | d[25];
+	g = (uint64_t)(d[21] & 0xf)<<32 | beu3(&d[22])<<8 | d[25];
 	ctx->duration = g * 1000 / ctx->samplerate;
 
 	/* skip the rest of the stream info */
--- a/id3v1.c
+++ b/id3v1.c
@@ -13,11 +13,11 @@
 int
 tagid3v1(Tagctx *ctx)
 {
-	uchar *in, *out;
+	uint8_t *in, *out;
 
 	if(ctx->bufsz < Insz+Outsz)
 		return -1;
-	in = (uchar*)ctx->buf;
+	in = (uint8_t*)ctx->buf;
 	out = in + Insz;
 
 	if(ctx->seek(ctx, -Insz, 2) < 0)
@@ -40,7 +40,7 @@
 		txtcb(ctx, Tcomment, "", &in[97]);
 
 	if((ctx->found & 1<<Ttrack) == 0 && in[125] == 0 && in[126] > 0){
-		snprint((char*)out, Outsz, "%d", in[126]);
+		snprintf((char*)out, Outsz, "%d", in[126]);
 		txtcb(ctx, Ttrack, "", out);
 	}
 
--- a/id3v2.c
+++ b/id3v2.c
@@ -75,12 +75,12 @@
 static int
 rva2(Tagctx *ctx, char *tag, int sz)
 {
-	uchar *b, *end;
+	uint8_t *b, *end;
 
 	if((b = memchr(tag, 0, sz)) == nil)
 		return -1;
 	b++;
-	for(end = (uchar*)tag+sz; b+4 < end; b += 5){
+	for(end = (uint8_t*)tag+sz; b+4 < end; b += 5){
 		int type = b[0];
 		float peak;
 		float va = (float)(b[1]<<8 | b[2]) / 512.0f;
@@ -98,8 +98,8 @@
 
 		if(type == 1){ /* master volume */
 			char vas[16], peaks[8];
-			snprint(vas, sizeof(vas), "%+.5f dB", va);
-			snprint(peaks, sizeof(peaks), "%.5f", peak);
+			snprintf(vas, sizeof(vas), "%+.5f dB", va);
+			snprintf(peaks, sizeof(peaks), "%.5f", peak);
 			vas[sizeof(vas)-1] = 0;
 			peaks[sizeof(peaks)-1] = 0;
 
@@ -117,7 +117,7 @@
 }
 
 static int
-resync(uchar *b, int sz)
+resync(uint8_t *b, int sz)
 {
 	int i;
 
@@ -136,7 +136,7 @@
 unsyncread(void *buf, int *sz)
 {
 	int i;
-	uchar *b;
+	uint8_t *b;
 
 	b = buf;
 	for(i = 0; i < *sz; i++){
@@ -153,7 +153,7 @@
 }
 
 static int
-nontext(Tagctx *ctx, uchar *d, int tsz, int unsync)
+nontext(Tagctx *ctx, uint8_t *d, int tsz, int unsync)
 {
 	int n, offset;
 	char *b, *tag;
@@ -201,7 +201,7 @@
 	}else if(strcmp((char*)d, "RVA2") == 0 && tsz >= 6+5){
 		/* replay gain. 6 = "track\0", 5 = other */
 		if(ctx->bufsz >= tsz && (n = ctx->read(ctx, tag, tsz)) == tsz)
-			rva2(ctx, tag, unsync ? resync((uchar*)tag, n) : n);
+			rva2(ctx, tag, unsync ? resync((uint8_t*)tag, n) : n);
 	}
 
 	return ctx->seek(ctx, tsz-n, 1) < 0 ? -1 : 0;
@@ -208,7 +208,7 @@
 }
 
 static int
-text(Tagctx *ctx, uchar *d, int tsz, int unsync)
+text(Tagctx *ctx, uint8_t *d, int tsz, int unsync)
 {
 	char *b, *tag;
 
@@ -223,7 +223,7 @@
 	}
 
 	if(unsync)
-		tsz = resync((uchar*)tag, tsz);
+		tsz = resync((uint8_t*)tag, tsz);
 
 	tag[tsz] = 0;
 	b = &tag[1];
@@ -230,12 +230,12 @@
 
 	switch(tag[0]){
 	case 0: /* iso-8859-1 */
-		if(iso88591toutf8((uchar*)ctx->buf, ctx->bufsz, (uchar*)b, tsz) > 0)
+		if(iso88591toutf8((uint8_t*)ctx->buf, ctx->bufsz, (uint8_t*)b, tsz) > 0)
 			v2cb(ctx, (char*)d, ctx->buf);
 		break;
 	case 1: /* utf-16 */
 	case 2:
-		if(utf16to8((uchar*)ctx->buf, ctx->bufsz, (uchar*)b, tsz) > 0)
+		if(utf16to8((uint8_t*)ctx->buf, ctx->bufsz, (uint8_t*)b, tsz) > 0)
 			v2cb(ctx, (char*)d, ctx->buf);
 		break;
 	case 3: /* utf-8 */
@@ -248,7 +248,7 @@
 }
 
 static int
-isid3(uchar *d)
+isid3(uint8_t *d)
 {
 	/* "ID3" version[2] flags[1] size[4] */
 	return (
@@ -258,7 +258,7 @@
 	);
 }
 
-static const uchar bitrates[4][4][16] = {
+static const uint8_t bitrates[4][4][16] = {
 	{
 		{0},
 		{0,  4,  8, 12, 16, 20, 24, 28, 32, 40, 48, 56, 64,  72,  80, 0}, /* v2.5 III */
@@ -299,8 +299,8 @@
 static void
 getduration(Tagctx *ctx, int offset)
 {
-	uvlong n, framelen, samplespf, toc;
-	uchar *b;
+	uint64_t n, framelen, samplespf, toc;
+	uint8_t *b;
 	uint x;
 	int xversion, xlayer, xbitrate, i;
 
@@ -307,7 +307,7 @@
 	if(ctx->read(ctx, ctx->buf, 256) != 256)
 		return;
 
-	x = beuint((uchar*)ctx->buf);
+	x = beuint((uint8_t*)ctx->buf);
 	xversion = x >> 19 & 3;
 	xlayer = x >> 17 & 3;
 	xbitrate = x >> 12 & 0xf;
@@ -318,12 +318,12 @@
 	ctx->channels = chans[x >> 6 & 3];
 
 	if(ctx->samplerate > 0){
-		framelen = (uvlong)144*ctx->bitrate / ctx->samplerate;
+		framelen = (uint64_t)144*ctx->bitrate / ctx->samplerate;
 		if((x & (1<<9)) != 0) /* padding */
 			framelen += xlayer == 3 ? 4 : 1; /* for I it's 4 bytes */
 
 		if(memcmp(&ctx->buf[0x24], "Info", 4) == 0 || memcmp(&ctx->buf[0x24], "Xing", 4) == 0){
-			b = (uchar*)ctx->buf + 0x28;
+			b = (uint8_t*)ctx->buf + 0x28;
 			x = beuint(b); b += 4;
 			if((x & 1) != 0){ /* number of frames is set */
 				n = beuint(b); b += 4;
@@ -353,11 +353,11 @@
 			}
 			offset += (char*)b - ctx->buf;
 		}else if(memcmp(&ctx->buf[0x24], "VBRI", 4) == 0){
-			n = beuint((uchar*)&ctx->buf[0x32]);
+			n = beuint((uint8_t*)&ctx->buf[0x32]);
 			ctx->duration = n * samplespf * 1000 / ctx->samplerate;
 
 			if(ctx->duration == 0 && framelen > 0){
-				n = beuint((uchar*)&ctx->buf[0x28]); /* file size */
+				n = beuint((uint8_t*)&ctx->buf[0x28]); /* file size */
 				ctx->duration = n * samplespf * 1000 / framelen / ctx->samplerate;
 			}
 		}
@@ -373,7 +373,7 @@
 	int sz, exsz, framesz;
 	int ver, unsync, offset;
 	int newpos, oldpos;
-	uchar d[10], *b;
+	uint8_t d[10], *b;
 
 	if(ctx->read(ctx, d, sizeof(d)) != sizeof(d))
 		return -1;
@@ -458,7 +458,7 @@
 	for(exsz = 0; exsz < 2048; exsz += sz){
 		if(ctx->read(ctx, ctx->buf, sz) != sz)
 			break;
-		for(b = (uchar*)ctx->buf; (b = memchr(b, 'I', sz - 1 - ((char*)b - ctx->buf))) != nil; b++){
+		for(b = (uint8_t*)ctx->buf; (b = memchr(b, 'I', sz - 1 - ((char*)b - ctx->buf))) != nil; b++){
 			newpos = ctx->seek(ctx, (char*)b - ctx->buf + offset + exsz, 0);
 			if(ctx->read(ctx, d, sizeof(d)) != sizeof(d))
 				return 0;
@@ -467,7 +467,7 @@
 				goto header;
 			}
 		}
-		for(b = (uchar*)ctx->buf; (b = memchr(b, 0xff, sz-3)) != nil; b++){
+		for(b = (uint8_t*)ctx->buf; (b = memchr(b, 0xff, sz-3)) != nil; b++){
 			if((b[1] & 0xe0) == 0xe0){
 				offset = ctx->seek(ctx, (char*)b - ctx->buf + offset + exsz, 0);
 				exsz = 2048;
--- a/it.c
+++ b/it.c
@@ -3,7 +3,7 @@
 int
 tagit(Tagctx *ctx)
 {
-	uchar d[4+26+1], o[26*2+1];
+	uint8_t d[4+26+1], o[26*2+1];
 
 	if(ctx->read(ctx, d, 4+26) != 4+26 || memcmp(d, "IMPM", 4) != 0)
 		return -1;
--- a/m4a.c
+++ b/m4a.c
@@ -2,17 +2,17 @@
 /* https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html */
 #include "tagspriv.h"
 
-#define beuint16(d) (ushort)((d)[0]<<8 | (d)[1]<<0)
+#define beuint16(d) (uint16_t)((d)[0]<<8 | (d)[1]<<0)
 
 int
 tagm4a(Tagctx *ctx)
 {
-	uvlong duration;
+	uint64_t duration;
 	uint x;
-	uchar *d;
+	uint8_t *d;
 	int sz, type, dtype, i, skip, n;
 
-	d = (uchar*)ctx->buf;
+	d = (uint8_t*)ctx->buf;
 	/* 4 bytes for atom size, 4 for type, 4 for data - exect "ftyp" to come first */
 	if(ctx->read(ctx, d, 4+4+4) != 4+4+4 || memcmp(d+4, "ftypM4A ", 8) != 0)
 		return -1;
@@ -113,7 +113,7 @@
 					return -1;
 				sz -= 28;
 				if((x = beuint(&d[16])) > 0)
-					duration = ((uvlong)beuint(&d[20])<<32 | beuint(&d[24])) / (uvlong)x;
+					duration = ((uint64_t)beuint(&d[20])<<32 | beuint(&d[24])) / (uint64_t)x;
 			}
 			ctx->duration = duration * 1000;
 			continue;
@@ -135,7 +135,7 @@
 			if(ctx->read(ctx, d, 4) != 4)
 				return -1;
 			sz -= 4;
-			snprint((char*)d, ctx->bufsz, "%d", beuint(d));
+			snprintf((char*)d, ctx->bufsz, "%d", beuint(d));
 			txtcb(ctx, type, "", d);
 		}else if(type == Tgenre && dtype != 1){
 			if(ctx->read(ctx, d, 2) != 2)
--- /dev/null
+++ b/meson.build
@@ -1,0 +1,57 @@
+project(
+	'libtags',
+	'c',
+	version: '1.0',
+	default_options: [
+		'c_std=c99',
+		'warning_level=3',
+		'buildtype=debugoptimized',
+	],
+)
+
+add_project_arguments(
+	'-Wdiscarded-qualifiers',
+	'-Wmissing-prototypes',
+	'-Wformat=2',
+	'-Wformat-overflow=2',
+	'-D_DEFAULT_SOURCE',
+	language: 'c',
+)
+
+src_lib = [
+	'437.c',
+	'8859.c',
+	'flac.c',
+	'id3genres.c',
+	'id3v1.c',
+	'id3v2.c',
+	'it.c',
+	'm4a.c',
+	'mod.c',
+	'opus.c',
+	's3m.c',
+	'tags.c',
+	'utf16.c',
+	'vorbis.c',
+	'wav.c',
+	'xm.c',
+]
+
+src_readtags = [
+	'examples/readtags.c',
+]
+
+lib = static_library(
+	'libtags',
+	sources: src_lib,
+)
+
+libtags = declare_dependency(
+	link_with: lib,
+)
+
+executable(
+	'readtags',
+	sources: src_readtags,
+	dependencies: [ libtags ],
+)
--- a/mkfile
+++ /dev/null
@@ -1,29 +1,0 @@
-</$objtype/mkfile
-LIB=/$objtype/lib/libtags.a
-
-OFILES=\
-	437.$O\
-	8859.$O\
-	flac.$O\
-	id3genres.$O\
-	id3v1.$O\
-	id3v2.$O\
-	it.$O\
-	m4a.$O\
-	opus.$O\
-	s3m.$O\
-	tags.$O\
-	utf16.$O\
-	vorbis.$O\
-	wav.$O\
-	xm.$O\
-	mod.$O\
-
-HFILES=\
-	/sys/include/tags.h\
-	tagspriv.h\
-
-/sys/include/%.h: %.h
-	cp $stem.h /sys/include/$stem.h
-
-</sys/src/cmd/mksyslib
--- a/mod.c
+++ b/mod.c
@@ -25,7 +25,7 @@
 int
 tagmod(Tagctx *ctx)
 {
-	uchar d[20], o[20*2+1];
+	uint8_t d[20], o[20*2+1];
 	int i;
 
 	if(ctx->seek(ctx, 1080, 0) != 1080)
--- a/opus.c
+++ b/opus.c
@@ -4,10 +4,10 @@
 tagopus(Tagctx *ctx)
 {
 	char *v;
-	uchar *d, h[4];
+	uint8_t *d, h[4];
 	int sz, numtags, i, npages, pgend;
 
-	d = (uchar*)ctx->buf;
+	d = (uint8_t*)ctx->buf;
 	for(npages = pgend = 0; npages < 2; npages++){
 		int nsegs;
 		if(ctx->read(ctx, d, 27) != 27)
@@ -81,7 +81,7 @@
 			for(; v != nil && v < ctx->buf+sz;){
 				v = memchr(v, 'O', ctx->buf+sz - v - 14);
 				if(v != nil && v[1] == 'g' && v[2] == 'g' && v[3] == 'S'){
-					uvlong g = leuint(v+6) | (uvlong)leuint(v+10)<<32;
+					uint64_t g = leuint(v+6) | (uint64_t)leuint(v+10)<<32;
 					ctx->duration = g * 1000 / 48000; /* granule positions are always 48KHz */
 				}
 				if(v != nil)
--- a/s3m.c
+++ b/s3m.c
@@ -8,7 +8,7 @@
 	if(ctx->read(ctx, d, 28+1+1) != 28+1+1 || (d[28] != 0x1a && d[28] != 0) || d[29] != 0x10)
 		return -1;
 	d[28] = 0;
-	for(s = d+27; s != d-1 && (*s == ' ' || *s == 0); s--);
+	for(s = d+27; s >= d && (*s == ' ' || *s == 0); s--);
 	s[1] = 0;
 	if(cp437toutf8(o, sizeof(o), d, s+1-d) > 0)
 		txtcb(ctx, Ttitle, "", o);
--- a/tags.c
+++ b/tags.c
@@ -8,18 +8,6 @@
 	int format;
 };
 
-extern int tagflac(Tagctx *ctx);
-extern int tagid3v1(Tagctx *ctx);
-extern int tagid3v2(Tagctx *ctx);
-extern int tagit(Tagctx *ctx);
-extern int tagm4a(Tagctx *ctx);
-extern int tagopus(Tagctx *ctx);
-extern int tags3m(Tagctx *ctx);
-extern int tagvorbis(Tagctx *ctx);
-extern int tagwav(Tagctx *ctx);
-extern int tagxm(Tagctx *ctx);
-extern int tagmod(Tagctx *ctx);
-
 static const Getter g[] =
 {
 	{tagid3v2, Fmp3},
@@ -41,10 +29,10 @@
 	char *e;
 
 	if(f == nil && size == 0){
-		while((uchar)*s <= ' ' && *s)
+		while((uint8_t)*s <= ' ' && *s)
 			s++;
 		e = s + strlen(s);
-		while(e != s && (uchar)e[-1] <= ' ')
+		while(e != s && (uint8_t)e[-1] <= ' ')
 			e--;
 		if(*e != 0)
 		  *e = 0;
@@ -53,7 +41,6 @@
 		ctx->tag(ctx, type, k, s, offset, size, f);
 		if(type != Tunknown){
 			ctx->found |= 1<<type;
-			ctx->num++;
 		}
 	}
 }
@@ -69,7 +56,6 @@
 	ctx->restart = 0;
 	res = -1;
 	for(i = 0; i < nelem(g); i++){
-		ctx->num = 0;
 		if(g[i].f(ctx) == 0){
 			ctx->format = g[i].format;
 			res = 0;
--- a/tags.h
+++ b/tags.h
@@ -1,5 +1,7 @@
-#ifndef __unix__
-#pragma lib "libtags.a"
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
 #endif
 
 typedef struct Tagctx Tagctx;
@@ -6,8 +8,7 @@
 typedef int (*Tagread)(void *buf, int *cnt);
 
 /* Tag type. */
-enum
-{
+enum {
 	Tunknown = -1,
 	Tartist,
 	Talbum,
@@ -25,8 +26,7 @@
 };
 
 /* Format of the audio file. */
-enum
-{
+enum {
 	Funknown = -1,
 	Fmp3,
 	Fogg,
@@ -43,8 +43,7 @@
 };
 
 /* Tag parser context. You need to set it properly before parsing an audio file using libtags. */
-struct Tagctx
-{
+struct Tagctx {
 	/* Read function. This is what libtags uses to read the file. */
 	int (*read)(Tagctx *ctx, void *buf, int cnt);
 
@@ -84,9 +83,12 @@
 
 	/* Private, don't touch. */
 	int found;
-	int num;
 	int restart;
 };
 
 /* Parse the file using this function. Returns 0 on success. */
-extern int tagsget(Tagctx *ctx);
+int tagsget(Tagctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
--- a/tagspriv.h
+++ b/tagspriv.h
@@ -1,44 +1,41 @@
-#ifdef __unix__
-#define _DEFAULT_SOURCE
+#include <stdbool.h>
+#include <stdint.h>
 #include <stdio.h>
-#include <string.h>
 #include <stdlib.h>
+#include <string.h>
 #include <strings.h>
-#include <stdint.h>
-#define snprint snprintf
-#define cistrcmp strcasecmp
-#define cistrncmp strncasecmp
+#include "tags.h"
+
 #define nil NULL
 #define UTFmax 4
 #define nelem(x) (int)(sizeof(x)/sizeof((x)[0]))
-typedef uint8_t uchar;
-typedef uint16_t u16int;
-typedef uint32_t u32int;
-typedef uint64_t uvlong;
-typedef unsigned int uint;
-typedef unsigned short ushort;
-#else
-#include <u.h>
-#include <libc.h>
-#endif
-#include "tags.h"
 
-enum
-{
+enum {
 	Numgenre = 192,
 };
 
-#define beuint(d) (uint)(((uchar*)(d))[0]<<24 | ((uchar*)(d))[1]<<16 | ((uchar*)(d))[2]<<8 | ((uchar*)(d))[3]<<0)
-#define leuint(d) (uint)(((uchar*)(d))[3]<<24 | ((uchar*)(d))[2]<<16 | ((uchar*)(d))[1]<<8 | ((uchar*)(d))[0]<<0)
-
 extern const char *id3genres[Numgenre];
 
+static inline uint32_t
+beuint(const void *d_)
+{
+	const uint8_t *d = d_;
+	return d[0]<<24 | d[1]<<16 | d[2]<<8 | d[3];
+}
+
+static inline uint32_t
+leuint(const void *d_)
+{
+	const uint8_t *d = d_;
+	return d[3]<<24 | d[2]<<16 | d[1]<<8 | d[0];
+}
+
 /*
  * Converts (to UTF-8) at most sz bytes of src and writes it to out buffer.
  * Returns the number of bytes converted.
  * You need sz*2+1 bytes for out buffer to be completely safe.
  */
-int iso88591toutf8(uchar *out, int osz, const uchar *src, int sz);
+int iso88591toutf8(uint8_t *out, int osz, const uint8_t *src, int sz);
 
 /*
  * Converts (to UTF-8) at most sz bytes of src and writes it to out buffer.
@@ -46,7 +43,7 @@
  * You need sz*4+1 bytes for out buffer to be completely safe.
  * UTF-16 defaults to big endian if there is no BOM.
  */
-int utf16to8(uchar *out, int osz, const uchar *src, int sz);
+int utf16to8(uint8_t *out, int osz, const uint8_t *src, int sz);
 
 /*
  * Same as utf16to8, but CP437 to UTF-8.
@@ -63,3 +60,15 @@
 void tagscallcb(Tagctx *ctx, int type, const char *k, char *s, int offset, int size, Tagread f);
 
 #define txtcb(ctx, type, k, s) tagscallcb(ctx, type, k, (char*)s, 0, 0, nil)
+
+int tagflac(Tagctx *ctx);
+int tagid3v1(Tagctx *ctx);
+int tagid3v2(Tagctx *ctx);
+int tagit(Tagctx *ctx);
+int tagm4a(Tagctx *ctx);
+int tagopus(Tagctx *ctx);
+int tags3m(Tagctx *ctx);
+int tagvorbis(Tagctx *ctx);
+int tagwav(Tagctx *ctx);
+int tagxm(Tagctx *ctx);
+int tagmod(Tagctx *ctx);
--- a/utf16.c
+++ b/utf16.c
@@ -3,19 +3,21 @@
 
 #define rchr(s) (be ? ((s)[0]<<8 | (s)[1]) : ((s)[1]<<8 | (s)[0]))
 
-static const uchar mark[] = {0x00, 0x00, 0xc0, 0xe0, 0xf0};
+static const uint8_t mark[] = {0x00, 0x00, 0xc0, 0xe0, 0xf0};
 
 int
-utf16to8(uchar *o, int osz, const uchar *s, int sz)
+utf16to8(uint8_t *o, int osz, const uint8_t *s, int sz)
 {
-	int i, be, c, c2, wr, j;
+	uint32_t c, c2;
+	int i, wr, j;
+	bool be;
 
 	i = 0;
-	be = 1;
+	be = true;
 	if(s[0] == 0xfe && s[1] == 0xff)
 		i += 2;
 	else if(s[0] == 0xff && s[1] == 0xfe){
-		be = 0;
+		be = false;
 		i += 2;
 	}
 
@@ -50,7 +52,7 @@
 			*(--o) = (c & 0xbf) | 0x80;
 			c >>= 6;
 		}
-		*(--o) = c | mark[wr];
+		*(--o) = (uint8_t)c | mark[wr];
 		o += wr;
 	}
 
--- a/vorbis.c
+++ b/vorbis.c
@@ -9,17 +9,19 @@
 	int type;
 }t[] = {
 	{"album", Talbum},
-	{"title", Ttitle},
 	{"artist", Tartist},
-	{"tracknumber", Ttrack},
+	{"comment", Tcomment},
+	{"composer", Tcomposer},
 	{"date", Tdate},
-	{"replaygain_track_peak", Ttrackpeak},
-	{"replaygain_track_gain", Ttrackgain},
-	{"replaygain_album_peak", Talbumpeak},
-	{"replaygain_album_gain", Talbumgain},
 	{"genre", Tgenre},
-	{"composer", Tcomposer},
-	{"comment", Tcomment},
+	{"r128_album_gain", Talbumgain},
+	{"r128_track_gain", Ttrackgain},
+	{"replaygain_album_gain", Talbumgain},
+	{"replaygain_album_peak", Talbumpeak},
+	{"replaygain_track_gain", Ttrackgain},
+	{"replaygain_track_peak", Ttrackpeak},
+	{"title", Ttitle},
+	{"tracknumber", Ttrack},
 };
 
 void
@@ -29,7 +31,7 @@
 	if(*v == 0)
 		return;
 	for(i = 0; i < nelem(t); i++){
-		if(cistrcmp(k, t[i].s) == 0){
+		if(strcasecmp(k, t[i].s) == 0){
 			txtcb(ctx, t[i].type, k, v);
 			break;
 		}
@@ -42,10 +44,10 @@
 tagvorbis(Tagctx *ctx)
 {
 	char *v;
-	uchar *d, h[4];
+	uint8_t *d, h[4];
 	int sz, numtags, i, npages, pgend;
 
-	d = (uchar*)ctx->buf;
+	d = (uint8_t*)ctx->buf;
 	/* need to find vorbis frame with type=3 */
 	for(npages = pgend = 0; npages < 2; npages++){ /* vorbis comment is the second header */
 		int nsegs;
@@ -123,7 +125,7 @@
 			for(; v != nil && v < ctx->buf+sz;){
 				v = memchr(v, 'O', ctx->buf+sz - v - 14);
 				if(v != nil && v[1] == 'g' && v[2] == 'g' && v[3] == 'S' && (v[5] & 4) == 4){ /* last page */
-					uvlong g = leuint(v+6) | (uvlong)leuint(v+10)<<32;
+					uint64_t g = leuint(v+6) | (uint64_t)leuint(v+10)<<32;
 					ctx->duration = g * 1000 / ctx->samplerate;
 				}
 				if(v != nil)
--- a/wav.c
+++ b/wav.c
@@ -1,6 +1,6 @@
 #include "tagspriv.h"
 
-#define le16u(d) (u16int)((d)[0] | (d)[1]<<8)
+#define le16u(d) (uint16_t)((d)[0] | (d)[1]<<8)
 
 static const struct {
 	char *s;
@@ -19,12 +19,12 @@
 int
 tagwav(Tagctx *ctx)
 {
-	uchar *d;
+	uint8_t *d;
 	int i, n, info;
-	u32int csz, x;
-	uvlong sz;
+	uint32_t csz, x;
+	uint64_t sz;
 
-	d = (uchar*)ctx->buf;
+	d = (uint8_t*)ctx->buf;
 
 	sz = 1;
 	info = 0;
@@ -68,7 +68,7 @@
 		}else if(memcmp(d, "LIST", 4) == 0){
 			sz = csz - 4;
 			continue;
-		}else if(info && csz < (u32int)ctx->bufsz){
+		}else if(info && csz < (uint32_t)ctx->bufsz){
 			for(n = 0; n < nelem(t); n++){
 				if(memcmp(d, t[n].s, 4) == 0 || t[n].type == Tunknown){
 					if(ctx->read(ctx, d+5, csz) != (int)csz)
--- a/xm.c
+++ b/xm.c
@@ -5,7 +5,7 @@
 {
 	char d[17+20+1], o[20*UTFmax+1];
 
-	if(ctx->read(ctx, d, 17+20) != 17+20 || cistrncmp(d, "Extended Module: ", 17) != 0)
+	if(ctx->read(ctx, d, 17+20) != 17+20 || strncasecmp(d, "Extended Module: ", 17) != 0)
 		return -1;
 	d[17+20] = 0;
 	if(cp437toutf8(o, sizeof(o), d+17, 20) > 0)