shithub: sox

Download patch

ref: e1bb8ea335d3517f9b3153bdc56b237847e2c7cd
parent: 269fe345e41fbff0ef56c8095e3f1d752517345c
author: cbagwell <cbagwell>
date: Wed Feb 21 15:57:01 EST 2001

Major updates to error checking code to use errno.
Added file seeking support.

--- a/Changelog
+++ b/Changelog
@@ -6,6 +6,10 @@
 
 sox-12.17.2
 -----------
+  o Darrick Servis has made major cleanups in the code in regards
+    to error conditions.  Helps people using libst.
+  o Darrick Servis has added added optional seek functionality sox.
+    Several formats have been modified to make use of this.
   o Geoff Kuenning rewrote the average effect into a general-purpose
     parametric mapping from N channels to M channels.
   o Geoff Kuenning added an optional delay-time parameter to the compander
--- a/src/8svx.c
+++ b/src/8svx.c
@@ -15,10 +15,10 @@
 #include "st.h"
 
 /* Private data used by writer */
-struct svxpriv {
+typedef struct svxpriv {
 	ULONG nsamples;
 	FILE *ch[4];
-};
+}*svx_t;
 
 static void svxwriteheader(ft_t, LONG);
 
@@ -29,7 +29,7 @@
 int st_svxstartread(ft)
 ft_t ft;
 {
-	struct svxpriv *p = (struct svxpriv *) ft->priv;
+	svx_t p = (svx_t ) ft->priv;
 
 	char buf[12];
 	char *chunk_buf;
@@ -43,6 +43,11 @@
 
 	ULONG chan1_pos;
 
+	if (! ft->seekable)
+	{
+		st_fail_errno(ft,ST_EINVAL,"8svx input file must be a file, not a pipe");
+		return (ST_EOF);
+	}
 	/* 8svx is in big endian format. Swap whats
 	 * read in on little endian machines.
 	 */
@@ -215,7 +220,7 @@
 	int done = 0;
 	int i;
 
-	struct svxpriv *p = (struct svxpriv *) ft->priv;
+	svx_t p = (svx_t ) ft->priv;
 
 	while (done < nsamp) {
 		for (i = 0; i < ft->info.channels; i++) {
@@ -239,7 +244,7 @@
 {
 	int i;
 
-	struct svxpriv *p = (struct svxpriv *) ft->priv;
+	svx_t p = (svx_t ) ft->priv;
 
 	/* close channel files */
 	for (i = 1; i < ft->info.channels; i++) {
@@ -254,7 +259,7 @@
 int st_svxstartwrite(ft)
 ft_t ft;
 {
-	struct svxpriv *p = (struct svxpriv *) ft->priv;
+	svx_t p = (svx_t ) ft->priv;
 	int i;
 
 	/* 8svx is in big endian format.  Swaps wahst
@@ -292,7 +297,7 @@
 ft_t ft;
 LONG *buf, len;
 {
-	struct svxpriv *p = (struct svxpriv *) ft->priv;
+	svx_t p = (svx_t ) ft->priv;
 
 	unsigned char datum;
 	int done = 0;
@@ -318,7 +323,7 @@
 int st_svxstopwrite(ft)
 ft_t ft;
 {
-	struct svxpriv *p = (struct svxpriv *) ft->priv;
+	svx_t p = (svx_t ) ft->priv;
 
 	int i;
 	int len;
--- a/src/aiff.c
+++ b/src/aiff.c
@@ -53,9 +53,11 @@
 #include "st.h"
 
 /* Private data used by writer */
-struct aiffpriv {
+typedef struct aiffpriv {
 	ULONG nsamples;	/* number of 1-channel samples read or written */
-};
+					/*Decrements for read increments for write */
+    LONG dataStart;  /* need to for seeking */
+} *aiff_t;
 
 /* forward declarations */
 static double read_ieee_extended(ft_t);
@@ -67,10 +69,24 @@
 static int commentChunk(char **text, char *chunkDescription, ft_t ft);
 static void reportInstrument(ft_t ft);
 
+int st_aiffseek(ft,offset) 
+ft_t ft;
+LONG offset;
+{
+	aiff_t aiff = (aiff_t ) ft->priv;
+
+	ft->st_errno = st_seek(ft,offset*ft->info.size + aiff->dataStart,SEEK_SET);
+
+	if( ft->st_errno == ST_SUCCESS )
+		aiff->nsamples = ft->length - offset;
+
+	return(ft->st_errno);
+}
+
 int st_aiffstartread(ft) 
 ft_t ft;
 {
-	struct aiffpriv *p = (struct aiffpriv *) ft->priv;
+	aiff_t aiff = (aiff_t ) ft->priv;
 	char buf[5];
 	ULONG totalsize;
 	LONG chunksize;
@@ -100,11 +116,6 @@
 
 	int rc;
 
-	/* Needed because of st_rawread() */
-	rc = st_rawstartread(ft);
-	if (rc)
-	    return rc;
-
 	/* AIFF is in Big Endian format.  Swap whats read in on Little */
 	/* Endian machines.                                            */
 	if (ST_IS_LITTLEENDIAN)
@@ -115,7 +126,7 @@
 	/* FORM chunk */
 	if (st_reads(ft, buf, 4) == ST_EOF || strncmp(buf, "FORM", 4) != 0)
 	{
-		st_fail("AIFF header does not begin with magic word 'FORM'");
+		st_fail_errno(ft,ST_EHDR,"AIFF header does not begin with magic word 'FORM'");
 		return(ST_EOF);
 	}
 	st_readdw(ft, &totalsize);
@@ -122,7 +133,7 @@
 	if (st_reads(ft, buf, 4) == ST_EOF || (strncmp(buf, "AIFF", 4) != 0 && 
 	    strncmp(buf, "AIFC", 4) != 0))
 	{
-		st_fail("AIFF 'FORM' chunk does not specify 'AIFF' or 'AIFC' as type");
+		st_fail_errno(ft,ST_EHDR,"AIFF 'FORM' chunk does not specify 'AIFF' or 'AIFC' as type");
 		return(ST_EOF);
 	}
 
@@ -136,7 +147,7 @@
 				break;
 			else
 			{
-				st_fail("Missing SSND chunk in AIFF file");
+				st_fail_errno(ft,ST_EHDR,"Missing SSND chunk in AIFF file");
 				return(ST_EOF);
 			}
 		}
@@ -155,7 +166,7 @@
 			    if (strncmp(buf, "NONE", 4) != 0)
 			    {
 				buf[4] = 0;
-				st_fail("Can not support AIFC files that contain compressed data: %s",buf);
+				st_fail_errno(ft,ST_EHDR,"Can not support AIFC files that contain compressed data: %s",buf);
 				return(ST_EOF);
 			    }
 			}
@@ -338,7 +349,7 @@
 			fseek(ft->fp, seekto, SEEK_SET);
 		else
 		{
-			st_fail("AIFF: no sound data on input file");
+			st_fail_errno(ft,ST_EOF,"AIFF: no sound data on input file");
 			return(ST_EOF);
 		}
 	}
@@ -345,13 +356,13 @@
 	/* SSND chunk just read */
 	if (blocksize != 0)
 	{
-		st_fail("AIFF header specifies nonzero blocksize?!?!");
+		st_fail_errno(ft,ST_EHDR,"AIFF header specifies nonzero blocksize?!?!");
 		return(ST_EOF);
 	}
 	while ((LONG) (--offset) >= 0) {
 		if (st_readb(ft, (unsigned char *)&trash) == ST_EOF)
 		{
-			st_fail("unexpected EOF while skipping AIFF offset");
+			st_fail_errno(ft,errno,"unexpected EOF while skipping AIFF offset");
 			return(ST_EOF);
 		}
 	}
@@ -368,7 +379,7 @@
 			ft->info.size = ST_SIZE_WORD;
 			break;
 		default:
-			st_fail("unsupported sample size in AIFF header: %d", bits);
+			st_fail_errno(ft,ST_EFMT,"unsupported sample size in AIFF header: %d", bits);
 			return(ST_EOF);
 			/*NOTREACHED*/
 		}
@@ -379,22 +390,22 @@
 			|| (ft->info.size == -1)) {
 		  st_report("You must specify # channels, sample rate, signed/unsigned,\n");
 		  st_report("and 8/16 on the command line.");
-		  st_fail("Bogus AIFF file: no COMM section.");
+		  st_fail_errno(ft,ST_EFMT,"Bogus AIFF file: no COMM section.");
 		  return(ST_EOF);
 		}
 
 	}
 
-	p->nsamples = ssndsize / ft->info.size;	/* leave out channels */
+	aiff->nsamples = ssndsize / ft->info.size;	/* leave out channels */
 
 	if (foundmark && !foundinstr)
 	{
-		st_fail("Bogus AIFF file: MARKers but no INSTrument.");
+		st_fail_errno(ft,ST_EFMT,"Bogus AIFF file: MARKers but no INSTrument.");
 		return(ST_EOF);
 	}
 	if (!foundmark && foundinstr)
 	{
-		st_fail("Bogus AIFF file: INSTrument but no MARKers.");
+		st_fail_errno(ft,ST_EFMT,"Bogus AIFF file: INSTrument but no MARKers.");
 		return(ST_EOF);
 	}
 	if (foundmark && foundinstr) {
@@ -437,6 +448,14 @@
 	if (verbose)
 	  reportInstrument(ft);
 
+	/* Needed because of st_rawread() */
+	rc = st_rawstartread(ft);
+	if (rc)
+	    return rc;
+
+	ft->length = aiff->nsamples; 	/* for seeking */
+	aiff->dataStart = ftell(ft->fp);
+
 	return(ST_SUCCESS);
 }
 
@@ -479,12 +498,12 @@
   *text = (char *) malloc((size_t) chunksize + 1);
   if (*text == NULL)
   {
-    st_fail("AIFF: Couldn't allocate %s header", chunkDescription);
+    st_fail_errno(ft,ST_ENOMEM,"AIFF: Couldn't allocate %s header", chunkDescription);
     return(ST_EOF);
   }
   if (fread(*text, 1, chunksize, ft->fp) != chunksize)
   {
-    st_fail("AIFF: Unexpected EOF in %s header", chunkDescription);
+    st_fail_errno(ft,ST_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription);
     return(ST_EOF);
   }
   *(*text + chunksize) = '\0';
@@ -494,7 +513,7 @@
 		char c;
 		if (fread(&c, 1, 1, ft->fp) != 1)
 		{
-			st_fail("AIFF: Unexpected EOF in %s header", chunkDescription);
+    		st_fail_errno(ft,ST_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription);
 			return(ST_EOF);
 		}
 	}
@@ -537,11 +556,11 @@
     }
 
     if (*text == NULL) {
-	st_fail("AIFF: Couldn't allocate %s header", chunkDescription);
+	st_fail_errno(ft,ST_ENOMEM,"AIFF: Couldn't allocate %s header", chunkDescription);
 	return(ST_EOF);
     }
     if (fread(*text + totalCommentLength - commentLength, 1, commentLength, ft->fp) != commentLength) {
-	st_fail("AIFF: Unexpected EOF in %s header", chunkDescription);
+	st_fail_errno(ft,ST_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription);
 	return(ST_EOF);
     }
     *(*text + totalCommentLength) = '\0';
@@ -549,7 +568,7 @@
 	/* Read past pad byte */
 	char c;
 	if (fread(&c, 1, 1, ft->fp) != 1) {
-	    st_fail("AIFF: Unexpected EOF in %s header", chunkDescription);
+	    st_fail_errno(ft,ST_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription);
 	    return(ST_EOF);
 	}
     }
@@ -564,14 +583,17 @@
 ft_t ft;
 LONG *buf, len;
 {
-	struct aiffpriv *p = (struct aiffpriv *) ft->priv;
+	aiff_t aiff = (aiff_t ) ft->priv;
+	LONG done;
 
 	/* just read what's left of SSND chunk */
-	if (len > p->nsamples)
-		len = p->nsamples;
-	st_rawread(ft, buf, len);
-	p->nsamples -= len;
-	return len;
+	if (len > aiff->nsamples)
+		len = aiff->nsamples;
+	done = st_rawread(ft, buf, len);
+	if (done == 0 && aiff->nsamples != 0)
+		st_warn("Premature EOF on AIFF input file");
+	aiff->nsamples -= done;
+	return done;
 }
 
 int st_aiffstopread(ft) 
@@ -621,7 +643,7 @@
 int st_aiffstartwrite(ft)
 ft_t ft;
 {
-	struct aiffpriv *p = (struct aiffpriv *) ft->priv;
+	aiff_t aiff = (aiff_t ) ft->priv;
 	int rc;
 
 	/* Needed because st_rawwrite() */
@@ -636,7 +658,7 @@
 	    ft->swap = ft->swap ? 0 : 1;
 	}
 
-	p->nsamples = 0;
+	aiff->nsamples = 0;
 	if ((ft->info.encoding == ST_ENCODING_ULAW ||
 	     ft->info.encoding == ST_ENCODING_ALAW) && 
 	    ft->info.size == ST_SIZE_BYTE) {
@@ -658,8 +680,8 @@
 ft_t ft;
 LONG *buf, len;
 {
-	struct aiffpriv *p = (struct aiffpriv *) ft->priv;
-	p->nsamples += len;
+	aiff_t aiff = (aiff_t ) ft->priv;
+	aiff->nsamples += len;
 	st_rawwrite(ft, buf, len);
 	return(len);
 }
@@ -667,7 +689,7 @@
 int st_aiffstopwrite(ft)
 ft_t ft;
 {
-	struct aiffpriv *p = (struct aiffpriv *) ft->priv;
+	aiff_t aiff = (aiff_t ) ft->priv;
 	int rc;
 
 	/* Needed because of st_rawwrite().  Call now to flush
@@ -679,15 +701,15 @@
 
 	if (!ft->seekable)
 	{
-	    st_fail("Non-seekable file.");
+	    st_fail_errno(ft,ST_EOF,"Non-seekable file.");
 	    return(ST_EOF);
 	}
 	if (fseek(ft->fp, 0L, SEEK_SET) != 0)
 	{
-		st_fail("can't rewind output file to rewrite AIFF header");
+		st_fail_errno(ft,errno,"can't rewind output file to rewrite AIFF header");
 		return(ST_EOF);
 	}
-	return(aiffwriteheader(ft, p->nsamples / ft->info.channels));
+	return(aiffwriteheader(ft, aiff->nsamples / ft->info.channels));
 }
 
 static int aiffwriteheader(ft, nframes)
@@ -717,7 +739,7 @@
 		bits = 16;
 	else
 	{
-		st_fail("unsupported output encoding/size for AIFF header");
+		st_fail_errno(ft,ST_EFMT,"unsupported output encoding/size for AIFF header");
 		return(ST_EOF);
 	}
 
@@ -834,7 +856,7 @@
 	char buf[10];
 	if (fread(buf, 1, 10, ft->fp) != 10)
 	{
-		st_fail("EOF while reading IEEE extended number");
+		st_fail_errno(ft,ST_EOF,"EOF while reading IEEE extended number");
 		return(ST_EOF);
 	}
 	return ConvertFromIeeeExtended(buf);
--- a/src/alsa.c
+++ b/src/alsa.c
@@ -45,7 +45,7 @@
     ft->file.eof = 0;
     ft->file.size = c_info.buffer_size;
     if ((ft->file.buf = malloc (ft->file.size)) == NULL) {
-	st_fail("unable to allocate output buffer of size %d", ft->file.size);
+	st_fail_errno(ft,ST_ENOMEM,"unable to allocate output buffer of size %d", ft->file.size);
 	return(ST_EOF);
     }
     if (ft->info.rate < c_info.min_rate) ft->info.rate = 2 * c_info.min_rate;
@@ -94,7 +94,7 @@
     ft->file.eof = 0;
     ft->file.size = p_info.buffer_size;
     if ((ft->file.buf = malloc (ft->file.size)) == NULL) {
-	st_fail("unable to allocate output buffer of size %d", ft->file.size);
+	st_fail_errno(ft,ST_ENOMEM,"unable to allocate output buffer of size %d", ft->file.size);
 	return(ST_EOF);
     }
     if (ft->info.rate < p_info.min_rate) ft->info.rate = 2 * p_info.min_rate;
@@ -144,7 +144,7 @@
     ft->file.eof = 0;
     ft->file.size = c_info.buffer_size;
     if ((ft->file.buf = malloc (ft->file.size)) == NULL) {
-	st_fail("unable to allocate output buffer of size %d", ft->file.size);
+	st_fail_errno(ft,ST_ENOMEM,"unable to allocate output buffer of size %d", ft->file.size);
 	return(ST_EOF);
     }
     if (ft->info.rate < c_info.min_rate) ft->info.rate = 2 * c_info.min_rate;
@@ -194,7 +194,7 @@
     ft->file.eof = 0;
     ft->file.size = p_info.buffer_size;
     if ((ft->file.buf = malloc (ft->file.size)) == NULL) {
-	st_fail("unable to allocate output buffer of size %d", ft->file.size);
+	st_fail_errno(ft,ST_ENOMEM,"unable to allocate output buffer of size %d", ft->file.size);
 	return(ST_EOF);
     }
     if (ft->info.rate < p_info.min_rate) ft->info.rate = 2 * p_info.min_rate;
@@ -252,21 +252,21 @@
 	{
 	    case ST_ENCODING_SIGN2:
 		if (!(formats & SND_PCM_FMT_S8)) {
-		    st_fail("ALSA driver does not support signed byte samples");
-		    return -1;
+		    st_fail_errno(ft,ST_EFMT,"ALSA driver does not support signed byte samples");
+		    return ST_EOF;
 		}
 		*fmt = SND_PCM_SFMT_S8;
 		break;
 	    case ST_ENCODING_UNSIGNED:
 		if (!(formats & SND_PCM_FMT_U8)) {
-		    st_fail("ALSA driver does not support unsigned byte samples");
-		    return -1;
+		    st_fail_errno(ft,ST_EFMT,"ALSA driver does not support unsigned byte samples");
+		    return ST_EOF;
 		}
 		*fmt = SND_PCM_SFMT_U8;
 		break;
 	    default:
-		st_fail("Hardware does not support %s output", st_encodings_str[ft->info.encoding]);
-		return -1;
+		st_fail_errno(ft,ST_EFMT,"Hardware does not support %s output", st_encodings_str[ft->info.encoding]);
+		return ST_EOF;
 		break;
 	}
     }
@@ -275,21 +275,21 @@
 	{
 	    case ST_ENCODING_SIGN2:
 		if (!(formats & SND_PCM_FMT_S16)) {
-		    st_fail("ALSA driver does not support signed word samples");
-		    return -1;
+		    st_fail_errno(ft,ST_EFMT,"ALSA driver does not support signed word samples");
+		    return ST_EOF;
 		}
 		*fmt = SND_PCM_SFMT_S16_LE;
 		break;
 	    case ST_ENCODING_UNSIGNED:
 		if (!(formats & SND_PCM_FMT_U16)) {
-		    st_fail("ALSA driver does not support unsigned word samples");
-		    return -1;
+		    st_fail_errno(ft,ST_EFMT,"ALSA driver does not support unsigned word samples");
+		    return ST_EOF;
 		}
 		*fmt = SND_PCM_SFMT_U16_LE;
 		break;
 	    default:
-		st_fail("Hardware does not support %s output", st_encodings_str[ft->info.encoding]);
-		return -1;
+		st_fail_errno(ft,ST_EFMT,"Hardware does not support %s output", st_encodings_str[ft->info.encoding]);
+		return ST_EOF;
 		break;
 	}
     }
--- a/src/au.c
+++ b/src/au.c
@@ -45,9 +45,11 @@
 /* The other formats are not supported by sox at the moment */
 
 /* Private data */
-struct aupriv {
-	/* For writer: */
+typedef struct aupriv {
+	/* For writer: size in bytes */
 	ULONG data_size;
+	/* For seeking */
+	LONG dataStart;
 	/* For G72x decoding: */
 	struct g72x_state state;
 	int (*dec_routine)();
@@ -54,7 +56,7 @@
 	int dec_bits;
 	unsigned int in_buffer;
 	int in_bits;
-};
+} *au_t;
 
 static void auwriteheader(ft_t ft, ULONG data_size);
 
@@ -93,12 +95,25 @@
             break;
     default:
             st_report("encoding: 0x%lx", encoding);
-            st_fail("Unsupported encoding in Sun/NeXT header.\nOnly U-law, signed bytes, signed words, and ADPCM are supported.");
             return(ST_EOF);
     }
     return(ST_SUCCESS);
 }
 
+int st_auseek(ft,offset) 
+ft_t ft;
+LONG offset;
+{
+	au_t au = (au_t ) ft->priv;
+
+	if (au->dec_routine != NULL)
+		st_fail_errno(ft,ST_ENOTSUP,"Sorry, DEC unsupported");
+	else 
+		return st_seek(ft,offset*ft->info.size + au->dataStart,SEEK_SET);
+
+	return(ft->st_errno);
+}
+
 int st_austartread(ft) 
 ft_t ft;
 {
@@ -116,15 +131,10 @@
 
 	register int i;
 	char *buf;
-	struct aupriv *p = (struct aupriv *) ft->priv;
+	au_t p = (au_t ) ft->priv;
 
 	int rc;
 
-	/* Needed for rawread() */
-	rc = st_rawstartread(ft);
-	if (rc)
-	    return rc;
-
 	/* AU is in big endian format.  Swap whats read
 	 * in onlittle endian machines.
 	 */
@@ -155,7 +165,7 @@
 	}
 	else
 	{
-		st_fail("Sun/NeXT/DEC header doesn't start with magic word\nTry the '.ul' file type with '-t ul -r 8000 filename'");
+		st_fail_errno(ft,ST_EHDR,"Sun/NeXT/DEC header doesn't start with magic word\nTry the '.ul' file type with '-t ul -r 8000 filename'");
 		return(ST_EOF);
 	}
 
@@ -163,8 +173,8 @@
 	st_readdw(ft, &hdr_size);
 	if (hdr_size < SUN_HDRSIZE)
 	{
-		st_fail("Sun/NeXT header size too small.");
-		return(0);
+		st_fail_errno(ft,ST_EHDR,"Sun/NeXT header size too small.");
+		return(ST_EOF);
 	}
 
 	/* Read the data size; may be ~0 meaning unspecified */
@@ -181,7 +191,10 @@
 	p->in_bits = 0;
         if(st_auencodingandsize(encoding, &(ft->info.encoding),
 			     &(ft->info.size)) == ST_EOF)
+	{
+            st_fail_errno(ft,ST_EFMT,"Unsupported encoding in Sun/NeXT header.\nOnly U-law, signed bytes, signed words, and ADPCM are supported.");
             return(ST_EOF);
+	}
 	switch (encoding) {
 	case SUN_G721:
 		g72x_init_state(&p->state);
@@ -217,7 +230,7 @@
 		    	st_readb(ft, &(buf[i]));
 			if (feof(ft->fp))
 			{
-				st_fail("Unexpected EOF in Sun/NeXT header info.");
+				st_fail_errno(ft,ST_EOF,"Unexpected EOF in Sun/NeXT header info.");
 				return(ST_EOF);
 			}
 		}
@@ -232,6 +245,16 @@
 		ft->comment = buf;
 		st_report("Input file %s: Sun header info: %s", ft->filename, buf);
 	}
+	/* Needed for seeking */
+	ft->length = data_size/ft->info.size;
+	if(ft->seekable)
+		p->dataStart = ftell(ft->fp);
+
+	/* Needed for rawread() */
+	rc = st_rawstartread(ft);
+	if (rc)
+	    return rc;
+
 	return(ST_SUCCESS);
 }
 
@@ -247,7 +270,7 @@
 int st_austartwrite(ft) 
 ft_t ft;
 {
-	struct aupriv *p = (struct aupriv *) ft->priv;
+	au_t p = (au_t ) ft->priv;
 	int rc;
 
 	/* Needed because of rawwrite(); */
@@ -278,7 +301,7 @@
 ft_t			ft;
 unsigned char		*code;
 {
-	struct aupriv		*p = (struct aupriv *) ft->priv;
+	au_t p = (au_t ) ft->priv;
 	unsigned char		in_byte;
 
 	if (p->in_bits < p->dec_bits) {
@@ -299,7 +322,7 @@
 ft_t ft;
 LONG *buf, samp;
 {
-	struct aupriv *p = (struct aupriv *) ft->priv;
+	au_t p = (au_t ) ft->priv;
 	unsigned char code;
 	int done;
 	if (p->dec_routine == NULL)
@@ -319,7 +342,7 @@
 ft_t ft;
 LONG *buf, samp;
 {
-	struct aupriv *p = (struct aupriv *) ft->priv;
+	au_t p = (au_t ) ft->priv;
 	p->data_size += samp * ft->info.size;
 	return(st_rawwrite(ft, buf, samp));
 }
@@ -327,7 +350,7 @@
 int st_austopwrite(ft)
 ft_t ft;
 {
-	struct aupriv *p = (struct aupriv *) ft->priv;
+	au_t p = (au_t ) ft->priv;
 	int rc;
 
 	/* Needed because of rawwrite(). Do now to flush
@@ -342,7 +365,7 @@
 	{
 	  if (fseek(ft->fp, 0L, 0) != 0)
 	  {
-		st_fail("Can't rewind output file to rewrite Sun header.");
+		st_fail_errno(ft,errno,"Can't rewind output file to rewrite Sun header.");
 		return(ST_EOF);
 	  }
 	  auwriteheader(ft, p->data_size);
--- a/src/auto.c
+++ b/src/auto.c
@@ -22,14 +22,15 @@
 {
 	char *type;
 	char header[132];
+	int rc;
 	if (!ft->seekable)
 	{
-		st_fail("Type AUTO input must be a file, not a pipe");
+		st_fail_errno(ft,ST_EOF,"Type AUTO input must be a file, not a pipe");
 		return(ST_EOF);
 	}
 	if (fread(header, 1, sizeof(header), ft->fp) != sizeof(header))
 	{
-		st_fail("Type AUTO detects short file");
+		st_fail_errno(ft,ST_EOF,"Type AUTO detects short file");
 		return(ST_EOF);
 	}
 	fseek(ft->fp, 0L - sizeof header, 1); /* Seek back */
@@ -69,8 +70,8 @@
 	}
 
   	if (type == 0) {
-  		printf("Type AUTO doesn't recognize this header\n");
-                printf("Trying: -t raw -r 44100 -s -w\n\n");
+  		st_warn("Type AUTO doesn't recognize this header\n");
+                st_warn("Trying: -t raw -r 44100 -s -w\n\n");
                 type = "raw";
                 ft->info.rate = 44100;
                 ft->info.size = ST_SIZE_WORD;
@@ -78,7 +79,9 @@
                 }
 	st_report("Type AUTO changed to %s", type);
 	ft->filetype = type;
-	st_gettype(ft); /* Change ft->h to the new format */
+	rc = st_gettype(ft); /* Change ft->h to the new format */
+	if(rc)
+		return (rc);
 	(* ft->h->startread)(ft);
 	return(ST_SUCCESS);
 }
@@ -86,6 +89,6 @@
 int st_autostartwrite(ft) 
 ft_t ft;
 {
-	st_fail("Type AUTO can only be used for input!");
+	st_fail_errno(ft,ST_EFMT,"Type AUTO can only be used for input!");
 	return(ST_EOF);
 }
--- a/src/avr.c
+++ b/src/avr.c
@@ -76,14 +76,10 @@
 	  ft->swap = ft->swap ? 0 : 1;
   }
 
-  rc = st_rawstartread (ft);
-  if (rc)
-      return rc;
-
   st_reads(ft, avr->magic, 4);
 
   if (strncmp (avr->magic, AVR_MAGIC, 4)) {
-    st_fail("AVR: unknown header");
+    st_fail_errno(ft,ST_EHDR,"AVR: unknown header");
     return(ST_EOF);
   }
 
@@ -105,8 +101,8 @@
     ft->info.size = ST_SIZE_WORD;
   }
   else {
-    st_fail("AVR: unsupported sample resolution");
-    return(0);
+    st_fail_errno(ft,ST_EFMT,"AVR: unsupported sample resolution");
+    return(ST_EOF);
   }
 
   st_readw (ft, &(avr->sign));
@@ -146,6 +142,10 @@
 
   fread(avr->user, 1, sizeof(avr->user), ft->fp);
 
+  rc = st_rawstartread (ft);
+  if (rc)
+      return rc;
+
   return(ST_SUCCESS);
 }
 
@@ -163,7 +163,7 @@
   }
 
   if (!ft->seekable) {
-    st_fail("AVR: file is not seekable");
+    st_fail_errno(ft,ST_EOF,"AVR: file is not seekable");
     return(ST_EOF);
   }
 
@@ -192,7 +192,7 @@
     st_writew (ft, 0xffff);
   }
   else {
-    st_fail("AVR: number of channels not supported");
+    st_fail_errno(ft,ST_EFMT,"AVR: number of channels not supported");
     return(0);
   }
 
@@ -204,7 +204,7 @@
     st_writew (ft, 16);
   }
   else {
-    st_fail("AVR: unsupported sample resolution");
+    st_fail_errno(ft,ST_EFMT,"AVR: unsupported sample resolution");
     return(ST_EOF);
   }
 
@@ -216,7 +216,7 @@
     st_writew (ft, 0);
   }
   else {
-    st_fail("AVR: unsupported encoding");
+    st_fail_errno(ft,ST_EFMT,"AVR: unsupported encoding");
     return(ST_EOF);
   }
 
--- a/src/cdr.c
+++ b/src/cdr.c
@@ -62,6 +62,13 @@
 	ft->info.channels = 2;
 	ft->comment = NULL;
 
+/* Need length for seeking */
+	if(ft->seekable){
+		ft->length = st_filelength(ft)/2;
+	} else {
+		ft->length = 0;
+	}
+	
 	return(ST_SUCCESS);
 }
 
--- a/src/cvsd.c
+++ b/src/cvsd.c
@@ -263,7 +263,7 @@
 	if (!dbg.f1) {
 		if (!(dbg.f1 = fopen("dbg1", "w")))
 		{
-			st_fail("debugging");
+			st_fail_errno(ft,errno,"debugging");
 			return (0);
 		}
 		fprintf(dbg.f1, "\"input\"\n");
@@ -271,7 +271,7 @@
 	if (!dbg.f2) {
 		if (!(dbg.f2 = fopen("dbg2", "w")))
 		{
-			st_fail("debugging");
+			st_fail_errno(ft,errno,"debugging");
 			return (0);
 		}
 		fprintf(dbg.f2, "\"recon\"\n");
@@ -345,7 +345,7 @@
 	if (!dbg.f1) {
 		if (!(dbg.f1 = fopen("dbg1", "w")))
 		{
-			st_fail("debugging");
+			st_fail_errno(ft,errno,"debugging");
 			return (0);
 		}
 		fprintf(dbg.f1, "\"input\"\n");
@@ -353,7 +353,7 @@
 	if (!dbg.f2) {
 		if (!(dbg.f2 = fopen("dbg2", "w")))
 		{
-			st_fail("debugging");
+			st_fail_errno(ft,errno,"debugging");
 			return (0);
 		}
 		fprintf(dbg.f2, "\"recon\"\n");
@@ -490,7 +490,6 @@
 
 	if (fread(hdrbuf, sizeof(hdrbuf), 1, f) != 1)
 	{
-		st_fail("unable to read DVMS header\n");
 		return (ST_EOF);
 	}
 	for(i = sizeof(hdrbuf), sum = 0; i > /*2*/3; i--) /* Deti bug */
@@ -515,7 +514,7 @@
 	hdr->Crc = get16(&pch);
 	if (sum != hdr->Crc) 
 	{
-		st_fail("DVMS header checksum error, read %u, calculated %u\n",
+		st_report("DVMS header checksum error, read %u, calculated %u\n",
 		     hdr->Crc, sum);
 		return (ST_EOF);
 	}
@@ -559,12 +558,12 @@
 	put16(&pch, hdr->Crc);
 	if (fseek(f, 0, SEEK_SET) < 0)
 	{
-		st_fail("cannot write DVMS header, seek failed\n");
+		st_report("seek failed\n: %s",strerror(errno));
 		return (ST_EOF);
 	}
 	if (fwrite(hdrbuf, sizeof(hdrbuf), 1, f) != 1)
 	{
-		st_fail("cannot write DVMS header\n");
+		st_report("%s\n",strerror(errno));
 		return (ST_EOF);
 	}
 	return (ST_SUCCESS);
@@ -608,8 +607,10 @@
 	int rc;
 
 	rc = dvms_read_header(ft->fp, &hdr);
-	if (rc)
+	if (rc){
+	    st_fail_errno(ft,ST_EHDR,"unable to read DVMS header\n");
 	    return rc;
+	}
 
 	st_report("DVMS header of source file \"%s\":");
 	st_report("  filename  \"%.14s\"",ft->filename);
@@ -651,8 +652,10 @@
 
 	make_dvms_hdr(ft, &hdr);
 	rc = dvms_write_header(ft->fp, &hdr);
-	if (rc)
+	if (rc){
+		st_fail_errno(ft,rc,"cannot write DVMS header\n");
 	    return rc;
+	}
 
 	if (!ft->seekable)
 	       st_warn("Length in output .DVMS header will wrong since can't seek to fix it");
@@ -677,11 +680,15 @@
 	}
 	if (fseek(ft->fp, 0L, 0) != 0)
 	{
-		st_fail("Can't rewind output file to rewrite DVMS header.");
+		st_fail_errno(ft,errno,"Can't rewind output file to rewrite DVMS header.");
 		return(ST_EOF);
 	}
 	make_dvms_hdr(ft, &hdr);
 	rc = dvms_write_header(ft->fp, &hdr);
+	if(rc){
+	    st_fail_errno(ft,rc,"cannot write DVMS header\n");
+	    return rc;
+	}	
 	return rc;
 }
 
--- a/src/dat.c
+++ b/src/dat.c
@@ -47,7 +47,7 @@
       sscanf(inpstr," %c",&sc);
       if (sc != ';') 
       {
-	  st_fail("Cannot determine sample rate.");
+	  st_fail_errno(ft,ST_EHDR,"Cannot determine sample rate.");
 	  return (ST_EOF);
       }
 #ifdef __alpha__
@@ -116,7 +116,7 @@
         retc = sscanf(inpstr,"%*s %lg",&sampval);
         if (retc != 1) 
 	{
-	    st_fail("Unable to read sample.");
+	    st_fail_errno(ft,ST_EOF,"Unable to read sample.");
 	    return (0);
 	}
         *buf++ = roundoff(sampval * 2.147483648e9);
--- a/src/gsm.c
+++ b/src/gsm.c
@@ -66,7 +66,7 @@
 	p->channels = ft->info.channels;
 	if (p->channels > MAXCHANS || p->channels <= 0)
 	{
-		st_fail("gsm: channels(%d) must be in 1-16", ft->info.channels);
+		st_fail_errno(ft,ST_EFMT,"gsm: channels(%d) must be in 1-16", ft->info.channels);
 		return(ST_EOF);
 	}
 
@@ -74,7 +74,7 @@
 		p->handle[ch] = gsm_create();
 		if (!p->handle[ch])
 		{
-			st_fail("unable to create GSM stream");
+			st_fail_errno(ft,errno,"unable to create GSM stream");
 			return (ST_EOF);
 		}
 	}
@@ -133,7 +133,7 @@
 			gbuff = p->sampleTop;
 			if (gsm_decode(p->handle[ch], p->frames + ch*FRAMESIZE, gbuff) < 0)
 			{
-				st_fail("error during GSM decode");
+				st_fail_errno(ft,errno,"error during GSM decode");
 				return (0);
 			}
 			
@@ -175,7 +175,7 @@
 		r = fwrite(p->frames, FRAMESIZE, 1, ft->fp);
 		if (r != 1)
 		{
-			st_fail("write error");
+			st_fail_errno(ft,errno,"write error");
 			return(ST_EOF);
 		}
 	}
--- a/src/handlers.c
+++ b/src/handlers.c
@@ -27,6 +27,7 @@
 extern int  st_aiffstartwrite();
 extern LONG st_aiffwrite();
 extern int  st_aiffstopwrite();
+extern int  st_aiffseek();
 
 static char *alnames[] = {
 	"al",
@@ -57,6 +58,7 @@
 extern int  st_austartwrite();
 extern LONG st_auwrite();
 extern int  st_austopwrite();
+extern int  st_auseek();
 
 static char *autonames[] = {
 	"auto",
@@ -191,6 +193,7 @@
 
 extern int st_sfstartread();
 extern int st_sfstartwrite();
+extern int st_sfseek();
 
 static char *slnames[] = {
 	"sl",
@@ -210,6 +213,7 @@
 extern LONG st_smpwrite();
 extern int  st_smpstartwrite();
 extern int  st_smpstopwrite();
+extern int  st_smpseek();
 
 static char *sndtnames[] = {
 	"sndt",
@@ -223,6 +227,7 @@
 extern int  st_sndtstartwrite();
 extern LONG st_sndtwrite();
 extern int  st_sndtstopwrite();
+extern int  st_sndseek();
 
 static char *spherenames[] = {
 	"sph",
@@ -328,6 +333,7 @@
 extern int  st_wavstartwrite();
 extern LONG st_wavwrite();
 extern int  st_wavstopwrite();
+extern int  st_wavseek();
 
 static char *wvenames[] = {
       "wve",
@@ -339,112 +345,113 @@
 extern int  st_wvestartwrite();
 extern LONG st_wvewrite();
 extern int  st_wvestopwrite();
+extern int  st_wveseek();
 
 extern int  st_nothing();
 extern LONG st_nothing_success();
 
 st_format_t st_formats[] = {
-	{aiffnames, ST_FILE_STEREO,		/* SGI/Apple AIFF */
+	{aiffnames, ST_FILE_STEREO | ST_FILE_SEEK,		/* SGI/Apple AIFF */
 		st_aiffstartread, st_aiffread, st_aiffstopread,
-		st_aiffstartwrite, st_aiffwrite, st_aiffstopwrite},
+		st_aiffstartwrite, st_aiffwrite, st_aiffstopwrite, st_aiffseek},
 	{alnames, ST_FILE_STEREO,		/* a-law byte raw */
 		st_alstartread, st_rawread, st_rawstopread,
-		st_alstartwrite, st_rawwrite, st_rawstopwrite},	
+		st_alstartwrite, st_rawwrite, st_rawstopwrite, st_nothing},	
 #if	defined(ALSA_PLAYER)
 	{alsanames, ST_FILE_STEREO,		/* /dev/snd/pcmXX */
 		st_alsastartread, st_rawread, st_rawstopread,
-		st_alsastartwrite, st_rawwrite, st_rawstopwrite},
+		st_alsastartwrite, st_rawwrite, st_rawstopwrite, st_nothing},
 #endif
-	{aunames, ST_FILE_STEREO,		/* SPARC .au w/header */
+	{aunames, ST_FILE_STEREO | ST_FILE_SEEK,		/* SPARC .au w/header */
 		st_austartread, st_auread, st_rawstopread,
-		st_austartwrite, st_auwrite, st_austopwrite},	
+		st_austartwrite, st_auwrite, st_austopwrite, st_auseek},	
 	{autonames, ST_FILE_STEREO,		/* Guess from header */
 		st_autostartread, st_nothing_success, st_nothing,
-		st_autostartwrite, st_nothing_success, st_nothing},
+		st_autostartwrite, st_nothing_success, st_nothing, st_nothing},
 	{avrnames, ST_FILE_STEREO,		/* AVR format */
 		st_avrstartread, st_rawread, st_nothing,	
-		st_avrstartwrite, st_avrwrite, st_avrstopwrite},
-	{cdrnames, ST_FILE_STEREO,		/* CD-R format */
+		st_avrstartwrite, st_avrwrite, st_avrstopwrite, st_nothing},
+	{cdrnames, ST_FILE_STEREO | ST_FILE_SEEK,		/* CD-R format */
 		st_cdrstartread, st_cdrread, st_cdrstopread,
-		st_cdrstartwrite, st_cdrwrite, st_cdrstopwrite},
+		st_cdrstartwrite, st_cdrwrite, st_cdrstopwrite, st_rawseek},
 	{cvsdnames, 0,			/* Cont. Variable Slope Delta */
 	        st_cvsdstartread, st_cvsdread, st_cvsdstopread,
-	        st_cvsdstartwrite, st_cvsdwrite, st_cvsdstopwrite},
+	        st_cvsdstartwrite, st_cvsdwrite, st_cvsdstopwrite, st_nothing},
 	{datnames, 0,				/* Text data samples */
 		st_datstartread, st_datread, st_nothing,
-		st_datstartwrite, st_datwrite, st_nothing},
+		st_datstartwrite, st_datwrite, st_nothing, st_nothing},
 	{dvmsnames, 0,			/* Cont. Variable Solot Delta */
 	        st_dvmsstartread, st_cvsdread, st_cvsdstopread,
-	        st_dvmsstartwrite, st_cvsdwrite, st_dvmsstopwrite},
+	        st_dvmsstartwrite, st_cvsdwrite, st_dvmsstopwrite, st_nothing},
 #ifdef HAVE_LIBGSM
 	{gsmnames, 0,				/* GSM 06.10 */
 	        st_gsmstartread, st_gsmread, st_gsmstopread,
-	        st_gsmstartwrite, st_gsmwrite, st_gsmstopwrite},
+	        st_gsmstartwrite, st_gsmwrite, st_gsmstopwrite, st_nothing},
 #endif
 	{hcomnames, 0,				/* Mac FSSD/HCOM */
 		st_hcomstartread, st_hcomread, st_hcomstopread, 
-		st_hcomstartwrite, st_hcomwrite, st_hcomstopwrite},
+		st_hcomstartwrite, st_hcomwrite, st_hcomstopwrite, st_nothing},
         {maudnames, ST_FILE_STEREO,    		/* Amiga MAUD */
 		st_maudstartread, st_maudread, st_maudstopread,
-		st_maudstartwrite, st_maudwrite, st_maudstopwrite},
+		st_maudstartwrite, st_maudwrite, st_maudstopwrite, st_nothing},
 #if	defined(OSS_PLAYER)
 	{ossdspnames, ST_FILE_STEREO,		/* OSS /dev/dsp player */
 		st_ossdspstartread, st_rawread, st_rawstopread,
-		st_ossdspstartwrite, st_rawwrite, st_rawstopwrite},
+		st_ossdspstartwrite, st_rawwrite, st_rawstopwrite, st_nothing},
 #endif
-	{rawnames, ST_FILE_STEREO,		/* Raw format */
+	{rawnames, ST_FILE_STEREO | ST_FILE_SEEK,		/* Raw format */
 		st_rawstartread, st_rawread, st_rawstopread,
-		st_rawstartwrite, st_rawwrite, st_rawstopwrite},
+		st_rawstartwrite, st_rawwrite, st_rawstopwrite, st_rawseek},
 	{sbnames, ST_FILE_STEREO,		/* signed byte raw */
 		st_sbstartread, st_rawread, st_rawstopread,
-		st_sbstartwrite, st_rawwrite, st_rawstopwrite},	
-	{sfnames, ST_FILE_STEREO,		/* IRCAM Sound File */
+		st_sbstartwrite, st_rawwrite, st_rawstopwrite, st_nothing},	
+	{sfnames, ST_FILE_STEREO | ST_FILE_SEEK,		/* IRCAM Sound File */
 		st_sfstartread, st_rawread, st_rawstopread,
-		st_sfstartwrite, st_rawwrite, st_rawstopwrite},
+		st_sfstartwrite, st_rawwrite, st_rawstopwrite, st_sfseek},
 	{ slnames, ST_FILE_STEREO,		/* signed long raw */
 	    	st_slstartread, st_rawread, st_rawstopread,
-		st_slstartwrite, st_rawwrite, st_rawstopwrite },
-	{smpnames, ST_FILE_STEREO | ST_FILE_LOOPS,/* SampleVision sound */
+		st_slstartwrite, st_rawwrite, st_rawstopwrite, st_nothing },
+	{smpnames, ST_FILE_STEREO | ST_FILE_LOOPS | ST_FILE_SEEK,/* SampleVision sound */
 		st_smpstartread, st_smpread, st_nothing,
-		st_smpstartwrite, st_smpwrite, st_smpstopwrite},
-	{sndtnames, ST_FILE_STEREO,		/* Sndtool Sound File */
+		st_smpstartwrite, st_smpwrite, st_smpstopwrite, st_smpseek},
+	{sndtnames, ST_FILE_STEREO | ST_FILE_SEEK,		/* Sndtool Sound File */
 		st_sndtstartread, st_rawread, st_rawstopread, 
-		st_sndtstartwrite, st_sndtwrite, st_sndtstopwrite},
+		st_sndtstartwrite, st_sndtwrite, st_sndtstopwrite, st_sndseek},
 	{spherenames, ST_FILE_STEREO,		/* NIST Sphere File */
 	        st_spherestartread, st_sphereread, st_rawstopread,
-		st_spherestartwrite, st_spherewrite, st_spherestopwrite},
+		st_spherestartwrite, st_spherewrite, st_spherestopwrite, st_nothing},
 #if	defined(SUNAUDIO_PLAYER)
 	{sunnames, ST_FILE_STEREO,		/* Sun /dev/audio player */
 		st_sunstartread, st_rawread, st_rawstopread,
-		st_sunstartwrite, st_rawwrite, st_rawstopwrite},
+		st_sunstartwrite, st_rawwrite, st_rawstopwrite, st_nothing},
 #endif
 	{svxnames, ST_FILE_STEREO,		/* Amiga 8SVX */
 		st_svxstartread, st_svxread, st_svxstopread,
-		st_svxstartwrite, st_svxwrite, st_svxstopwrite},
+		st_svxstartwrite, st_svxwrite, st_svxstopwrite, st_nothing},
 	{swnames, ST_FILE_STEREO,		/* signed word raw */
 		st_swstartread, st_rawread, st_rawstopread,
-		st_swstartwrite, st_rawwrite, st_rawstopwrite},
+		st_swstartwrite, st_rawwrite, st_rawstopwrite, st_nothing},
 	{txwnames, 0,			/* Yamaha TX16W and SY99 waves */
 	        st_txwstartread, st_txwread, st_txwstopread, 
-	        st_txwstartwrite, st_txwwrite, st_txwstopwrite},
+	        st_txwstartwrite, st_txwwrite, st_txwstopwrite, st_nothing},
 	{ubnames, ST_FILE_STEREO,		/* unsigned byte raw */
 		st_ubstartread, st_rawread, st_rawstopread,
-		st_ubstartwrite, st_rawwrite, st_rawstopwrite},
+		st_ubstartwrite, st_rawwrite, st_rawstopwrite, st_nothing},
 	{ulnames, ST_FILE_STEREO,		/* u-law byte raw */
 		st_ulstartread, st_rawread, st_rawstopread,
-		st_ulstartwrite, st_rawwrite, st_rawstopwrite},	
+		st_ulstartwrite, st_rawwrite, st_rawstopwrite, st_nothing},	
 	{uwnames, ST_FILE_STEREO,		/* unsigned word raw */
 		st_uwstartread, st_rawread, st_rawstopread,
-		st_uwstartwrite, st_rawwrite, st_rawstopwrite},	
+		st_uwstartwrite, st_rawwrite, st_rawstopwrite, st_nothing},	
 	{vocnames, ST_FILE_STEREO,		/* Sound Blaster .VOC */
 		st_vocstartread, st_vocread, st_vocstopread,
-		st_vocstartwrite, st_vocwrite, st_vocstopwrite},
-	{wavnames, ST_FILE_STEREO,		/* Microsoftt RIFF */
+		st_vocstartwrite, st_vocwrite, st_vocstopwrite, st_nothing},
+	{wavnames, ST_FILE_STEREO | ST_FILE_SEEK,		/* Microsoftt RIFF */
 		st_wavstartread, st_wavread, st_nothing,
-		st_wavstartwrite, st_wavwrite, st_wavstopwrite},	
-	{wvenames, 0,				/* Psion .wve */
+		st_wavstartwrite, st_wavwrite, st_wavstopwrite, st_wavseek},	
+	{wvenames, ST_FILE_SEEK,				/* Psion .wve */
 		st_wvestartread, st_wveread, st_rawstopread,
-		st_wvestartwrite, st_wvewrite, st_wvestopwrite},
+		st_wvestartwrite, st_wvewrite, st_wvestopwrite, st_wveseek},
 	{0, 0,
 	 0, 0, 0, 0, 0, 0}
 };
@@ -660,7 +667,7 @@
 	{"null", 0, 			/* stand-in, never gets called */
 		st_nothing, st_nothing, st_nothing, 
 		st_null_drain, st_nothing},
-	{"avg", ST_EFF_MCHAN, 
+	{"avg", ST_EFF_CHAN, 
 		st_avg_getopts, st_avg_start, st_avg_flow, 
 		st_null_drain, st_avg_stop},
 	{"band", 0, 
--- a/src/hcom.c
+++ b/src/hcom.c
@@ -77,7 +77,7 @@
 	/* Check the file type (bytes 65-68) */
 	if (st_reads(ft, buf, 4) == ST_EOF || strncmp(buf, "FSSD", 4) != 0)
 	{
-		st_fail("Mac header type is not FSSD");
+		st_fail_errno(ft,ST_EHDR,"Mac header type is not FSSD");
 		return (ST_EOF);
 	}
 
@@ -98,7 +98,7 @@
 	/* The data fork must contain a "HCOM" header */
 	if (st_reads(ft, buf, 4) == ST_EOF || strncmp(buf, "HCOM", 4) != 0)
 	{
-		st_fail("Mac data fork is not HCOM");
+		st_fail_errno(ft,ST_EHDR,"Mac data fork is not HCOM");
 		return (ST_EOF);
 	}
 
@@ -108,13 +108,13 @@
 	st_readdw(ft, &compresstype);
 	if (compresstype > 1)
 	{
-		st_fail("Bad compression type in HCOM header");
+		st_fail_errno(ft,ST_EHDR,"Bad compression type in HCOM header");
 		return (ST_EOF);
 	}
 	st_readdw(ft, &divisor);
 	if (divisor == 0 || divisor > 4)
 	{
-		st_fail("Bad sampling rate divisor in HCOM header");
+		st_fail_errno(ft,ST_EHDR,"Bad sampling rate divisor in HCOM header");
 		return (ST_EOF);
 	}
 	st_readw(ft, &dictsize);
@@ -129,8 +129,8 @@
 	p->dictionary = (dictent *) malloc(511 * sizeof(dictent));
 	if (p->dictionary == NULL)
 	{
-		st_fail("can't malloc memory for Huffman dictionary");
-		return (0);
+		st_fail_errno(ft,ST_ENOMEM,"can't malloc memory for Huffman dictionary");
+		return (ST_EOF);
 	}
 
 	/* Read dictionary */
@@ -169,7 +169,7 @@
 	while (--n >= 0) {
 	    	if (st_readb(ft, &trash) == ST_EOF)
 		{
-			st_fail("unexpected EOF in Mac header");
+			st_fail_errno(ft,ST_EOF,"unexpected EOF in Mac header");
 			return(ST_EOF);
 		}
 	}
@@ -190,7 +190,7 @@
 			return 0; /* Don't know if this can happen... */
 		if (st_readb(ft, &sample_rate) == ST_EOF)
 		{
-			st_fail("unexpected EOF at start of HCOM data");
+			st_fail_errno(ft,ST_EOF,"unexpected EOF at start of HCOM data");
 			return (0);
 		}
 		p->sample = sample_rate;
@@ -208,7 +208,7 @@
 			st_readdw(ft, &(p->current));
 			if (feof(ft->fp))
 			{
-				st_fail("unexpected EOF in HCOM data");
+				st_fail_errno(ft,ST_EOF,"unexpected EOF in HCOM data");
 				return (0);
 			}
 			p->cksum += p->current;
@@ -252,12 +252,12 @@
 
 	if (p->huffcount != 0)
 	{
-		st_fail("not all HCOM data read");
+		st_fail_errno(ft,ST_EFMT,"not all HCOM data read");
 		return (ST_EOF);
 	}
 	if(p->cksum != p->checksum)
 	{
-		st_fail("checksum error in HCOM data");
+		st_fail_errno(ft,ST_EFMT,"checksum error in HCOM data");
 		return (ST_EOF);
 	}
 	free((char *)p->dictionary);
@@ -293,7 +293,7 @@
 	case 22050/4:
 		break;
 	default:
-		st_fail("unacceptable output rate for HCOM: try 5512, 7350, 11025 or 22050 hertz");
+		st_fail_errno(ft,ST_EFMT,"unacceptable output rate for HCOM: try 5512, 7350, 11025 or 22050 hertz");
 		return (ST_EOF);
 	}
 	ft->info.size = ST_SIZE_BYTE;
@@ -305,7 +305,7 @@
 	p->data = (unsigned char *) malloc(p->size);
 	if (p->data == NULL)
 	{
-		st_fail("can't malloc buffer for uncompressed HCOM data");
+		st_fail_errno(ft,ST_ENOMEM,"can't malloc buffer for uncompressed HCOM data");
 		return (ST_EOF);
 	}
 	return (ST_SUCCESS);
@@ -327,7 +327,7 @@
 		p->data = (unsigned char *) realloc(p->data, p->size);
 		if (p->data == NULL)
 		{
-		    st_fail("can't realloc buffer for uncompressed HCOM data");
+		    st_fail_errno(ft,ST_ENOMEM,"can't realloc buffer for uncompressed HCOM data");
 		    return (0);
 		}
 	}
@@ -495,8 +495,7 @@
   st_report("Compressed size: %6d bytes", l);
   if((datafork = (unsigned char *)malloc((unsigned)l)) == NULL)
   {
-    st_fail("can't malloc buffer for compressed HCOM data");
-    return (ST_EOF);
+    return (ST_ENOMEM);
   }
   ddf = datafork + 22;
   for(i = 0; i < dictsize; i++) {
@@ -553,8 +552,10 @@
 	rc = compress(&compressed_data, &compressed_len, (double) ft->info.rate);
 	free((char *) p->data);
 
-	if (rc)
+	if (rc){
+    	st_fail_errno(ft, rc,"can't malloc buffer for compressed HCOM data");
 	    return 0;
+	}
 
 	/* Write the header */
 	fwrite("\000\001A", 1, 3, ft->fp); /* Dummy file name "A" */
@@ -566,7 +567,7 @@
 	padbytes(ft, 128 - 91);
 	if (ferror(ft->fp))
 	{
-		st_fail("write error in HCOM header");
+		st_fail_errno(ft,errno,"write error in HCOM header");
 		return (ST_EOF);
 	}
 
@@ -573,7 +574,7 @@
 	/* Write the compressed_data fork */
 	if (fwrite((char *) compressed_data, 1, (int)compressed_len, ft->fp) != compressed_len)
 	{
-		st_fail("can't write compressed HCOM data");
+		st_fail_errno(ft,errno,"can't write compressed HCOM data");
 		rc = ST_EOF;
 	}
 	else
--- a/src/maud.c
+++ b/src/maud.c
@@ -73,7 +73,7 @@
 	/* read FORM chunk */
 	if (st_reads(ft, buf, 4) == ST_EOF || strncmp(buf, "FORM", 4) != 0)
 	{
-		st_fail("MAUD: header does not begin with magic word 'FORM'");
+		st_fail_errno(ft,ST_EHDR,"MAUD: header does not begin with magic word 'FORM'");
 		return (ST_EOF);
 	}
 	
@@ -81,7 +81,7 @@
 	
 	if (st_reads(ft, buf, 4) == ST_EOF || strncmp(buf, "MAUD", 4) != 0)
 	{
-		st_fail("MAUD: 'FORM' chunk does not specify 'MAUD' as type");
+		st_fail_errno(ft,ST_EHDR,"MAUD: 'FORM' chunk does not specify 'MAUD' as type");
 		return(ST_EOF);
 	}
 	
@@ -99,8 +99,8 @@
 			st_readdw(ft, &chunksize);
 			if (chunksize != 8*4) 
 			{
-			    st_fail("MAUD: MHDR chunk has bad size");
-			    return(0);
+			    st_fail_errno(ft,ST_EHDR,"MAUD: MHDR chunk has bad size");
+			    return(ST_EOF);
 			}
 			
 			/* fseek(ft->fp,12,SEEK_CUR); */
@@ -118,7 +118,7 @@
 			st_readw(ft, &denom);       /* clock devide           */
 			if (denom == 0) 
 			{
-			    st_fail("MAUD: frequency denominator == 0, failed");
+			    st_fail_errno(ft,ST_EHDR,"MAUD: frequency denominator == 0, failed");
 			    return (ST_EOF);
 			}
 			
@@ -133,7 +133,7 @@
 				ft->info.channels = 2;
 				break;
 			default:
-				st_fail("MAUD: unsupported number of channels in file");
+				st_fail_errno(ft,ST_EFMT,"MAUD: unsupported number of channels in file");
 				return (ST_EOF);
 			}
 			
@@ -140,7 +140,7 @@
 			st_readw(ft, &chaninf); /* number of channels (mono: 1, stereo: 2, ...) */
 			if (chaninf != ft->info.channels) 
 			{
-			    st_fail("MAUD: unsupported number of channels in file");
+				st_fail_errno(ft,ST_EFMT,"MAUD: unsupported number of channels in file");
 			    return(ST_EOF);
 			}
 			
@@ -168,7 +168,7 @@
 			}
 			else 
 			{
-				st_fail("MAUD: unsupported compression type detected");
+				st_fail_errno(ft,ST_EFMT,"MAUD: unsupported compression type detected");
 				return(ST_EOF);
 			}
 			
@@ -184,13 +184,13 @@
 			chunk_buf = (char *) malloc(chunksize + 1);
 			if (!chunk_buf)
 			{
-			    st_fail("Couldn't alloc resources");
+			    st_fail_errno(ft,ST_ENOMEM,"Couldn't alloc resources");
 			    return(ST_EOF);
 			}
 			if (fread(chunk_buf,1,(int)chunksize,ft->fp) 
 					!= chunksize)
 			{
-				st_fail("MAUD: Unexpected EOF in ANNO header");
+				st_fail_errno(ft,ST_EOF,"MAUD: Unexpected EOF in ANNO header");
 				return(ST_EOF);
 			}
 			chunk_buf[chunksize] = '\0';
@@ -211,7 +211,7 @@
 	
 	if (strncmp(buf,"MDAT",4) != 0) 
 	{
-	    st_fail("MAUD: MDAT chunk not found");
+	    st_fail_errno(ft,ST_EFMT,"MAUD: MDAT chunk not found");
 	    return(ST_EOF);
 	}
 	st_readdw(ft, &(p->nsamples));
@@ -265,12 +265,12 @@
 	/* If you have to seek around the output file */
 	if (! ft->seekable) 
 	{
-	    st_fail("Output .maud file must be a file, not a pipe");
+	    st_fail_errno(ft,ST_EOF,"Output .maud file must be a file, not a pipe");
 	    return (ST_EOF);
 	}
 	
 	if (ft->info.channels != 1 && ft->info.channels != 2) {
-		st_fail("MAUD: unsupported number of channels, unable to store");
+		st_fail_errno(ft,ST_EFMT,"MAUD: unsupported number of channels, unable to store");
 		return(ST_EOF);
 	}
 	if (ft->info.size == ST_SIZE_WORD) ft->info.encoding = ST_ENCODING_SIGN2;
@@ -311,7 +311,7 @@
 	
 	if (fseek(ft->fp, 0L, 0) != 0) 
 	{
-	    st_fail("can't rewind output file to rewrite MAUD header");
+	    st_fail_errno(ft,errno,"can't rewind output file to rewrite MAUD header");
 	    return(ST_EOF);
 	}
 	
--- a/src/misc.c
+++ b/src/misc.c
@@ -18,6 +18,10 @@
 #include <time.h>
 #include <string.h>
 
+/* for fstat */
+#include <sys/stat.h>
+#include <unistd.h>
+
 const char *st_sizes_str[] = {
 	"NONSENSE!",
 	"bytes",
@@ -92,6 +96,7 @@
 	if (fread(&in, 1, 1, ft->fp) != 1)
 	{
 	    *sc = 0;
+		st_fail_errno(ft,errno,readerr);
 	    return (ST_EOF);
 	}
 	if (in == 0 || in == '\n')
@@ -114,7 +119,7 @@
 {
 	if (fwrite(c, 1, strlen(c), ft->fp) != strlen(c))
 	{
-		st_fail(writerr);
+		st_fail_errno(ft,errno,writerr);
 		return(ST_EOF);
 	}
 	return(ST_SUCCESS);
@@ -128,6 +133,7 @@
 {
 	if (fread(uc, 1, 1, ft->fp) != 1)
 	{
+		st_fail_errno(ft,errno,readerr);
 	    return(ST_EOF);
 	}
 	return ST_SUCCESS;
@@ -141,7 +147,7 @@
 {
 	if (fwrite(&uc, 1, 1, ft->fp) != 1)
 	{
-		st_fail(writerr);
+		st_fail_errno(ft,errno,writerr);
 		return(ST_EOF);
 	}
 	return(ST_SUCCESS);
@@ -155,6 +161,7 @@
 {
 	if (fread(us, 2, 1, ft->fp) != 1)
 	{
+		st_fail_errno(ft,errno,readerr);
 	    return (ST_EOF);
 	}
 	if (ft->swap)
@@ -172,7 +179,7 @@
 		us = st_swapw(us);
 	if (fwrite(&us, 2, 1, ft->fp) != 1)
 	{
-		st_fail(writerr);
+		st_fail_errno(ft,errno,writerr);
 		return (ST_EOF);
 	}
 	return(ST_SUCCESS);
@@ -186,6 +193,7 @@
 {
 	if (fread(ul, 4, 1, ft->fp) != 1)
 	{
+		st_fail_errno(ft,errno,readerr);
 	    return (ST_EOF);
 	}
 	if (ft->swap)
@@ -203,7 +211,7 @@
 		ul = st_swapl(ul);
 	if (fwrite(&ul, 4, 1, ft->fp) != 1)
 	{
-		st_fail(writerr);
+		st_fail_errno(ft,errno,writerr);
 		return (ST_EOF);
 	}
 	return(ST_SUCCESS);
@@ -236,7 +244,7 @@
 		t = st_swapf(t);
 	if (fwrite(&t, sizeof(float), 1, ft->fp) != 1)
 	{
-		st_fail(writerr);
+		st_fail_errno(ft,errno,writerr);
 		return (ST_EOF);
 	}
 	return (ST_SUCCESS);
@@ -267,7 +275,7 @@
 		d = st_swapd(d);
 	if (fwrite(&d, sizeof(double), 1, ft->fp) != 1)
 	{
-		st_fail(writerr);
+		st_fail_errno(ft,errno,writerr);
 		return (ST_EOF);
 	}
 	return (ST_SUCCESS);
@@ -468,3 +476,61 @@
 	}
 }
 #endif
+
+/* Sets file offset
+ * offset in bytes 
+ */
+int st_seek(ft,offset,whence) 
+ft_t ft;
+LONG offset;
+int whence;
+{
+	if( ft->seekable == 0 ){
+/* 
+ * If a stream peel off chars else 
+ * EPERM 	"Operation not permitted" 
+ */
+		if(whence == SEEK_CUR ){
+			if( offset < 0 ){
+				st_fail_errno(ft,ST_EINVAL,"Can't seek backwards in pipe");
+			} else {
+    			while ( offset > 0 && !feof(ft->fp) )
+    			{
+					getc(ft->fp);
+					offset--;
+    			}
+				if(offset)
+					st_fail_errno(ft,ST_EOF,"offset past eof");
+				else 
+					ft->st_errno = ST_SUCCESS;
+			}
+		} else {
+			st_fail_errno(ft,ST_EPERM,"File not seekable");
+		}
+	} else {
+		if( fseek(ft->fp,offset,whence) == -1 )
+			st_fail_errno(ft,errno,strerror(errno));
+		else
+			ft->st_errno = ST_SUCCESS;
+	}	
+		 
+/* Empty the st file buffer */
+	if( ft->st_errno == ST_SUCCESS ){
+		ft->file.count = 0;
+		ft->file.pos = 0;
+		ft->file.eof = 0;
+	}
+
+	return(ft->st_errno);
+}
+
+LONG st_filelength(ft)
+ft_t ft;
+{
+	
+	struct stat st;
+
+	fstat(fileno(ft->fp), &st);
+
+	return (LONG)st.st_size;
+}
--- a/src/oss.c
+++ b/src/oss.c
@@ -84,12 +84,12 @@
 
     if (ioctl(fileno(ft->fp), SNDCTL_DSP_RESET, 0) < 0)
     {
-	st_fail("Unable to reset OSS driver.  Possibly accessing an invalid file/device");
+	st_fail_errno(ft,ST_EOF,"Unable to reset OSS driver.  Possibly accessing an invalid file/device");
 	return(ST_EOF);
     }
 
     if (ioctl(fileno(ft->fp), SNDCTL_DSP_SYNC, NULL) < 0) {
-	st_fail("Unable to sync dsp");
+	st_fail_errno(ft,ST_EOF,"Unable to sync dsp");
 	return (ST_EOF);
     }
 
@@ -136,7 +136,7 @@
     /* Give up and exit */
     if (rc < 0 || tmp != sampletype)
     {
-	st_fail("Unable to set the sample size to %d", samplesize);
+	st_fail_errno(ft,ST_EOF,"Unable to set the sample size to %d", samplesize);
 	return (ST_EOF);
     }
 
@@ -181,7 +181,7 @@
     ft->file.size = 0;
     ioctl (fileno(ft->fp), SNDCTL_DSP_GETBLKSIZE, &ft->file.size);
     if (ft->file.size < 4 || ft->file.size > 65536) {
-	    st_fail("Invalid audio buffer size %d", ft->file.size);
+	    st_fail_errno(ft,ST_EOF,"Invalid audio buffer size %d", ft->file.size);
 	    return (ST_EOF);
     }
     ft->file.count = 0;
@@ -189,7 +189,7 @@
     ft->file.eof = 0;
 
     if ((ft->file.buf = malloc (ft->file.size)) == NULL) {
-	st_fail("Unable to allocate input/output buffer of size %d", ft->file.size);
+	st_fail_errno(ft,ST_EOF,"Unable to allocate input/output buffer of size %d", ft->file.size);
 	return (ST_EOF);
     }
 
--- a/src/raw.c
+++ b/src/raw.c
@@ -33,6 +33,36 @@
 
 static void rawdefaults(ft_t ft);
 
+
+int st_rawseek(ft,offset) 
+ft_t ft;
+LONG offset;
+{
+	int sample_size = 0;
+
+	switch(ft->info.size) {
+		case ST_SIZE_BYTE:
+			sample_size = 1;
+		break;
+		case ST_SIZE_WORD:
+			sample_size = sizeof(short);
+		break;
+		case ST_SIZE_DWORD:
+			sample_size = sizeof(LONG);
+		break;
+		case ST_SIZE_FLOAT:
+			sample_size = sizeof(float);
+		break;
+		default:
+			st_fail_errno(ft,ST_ENOTSUP,"Can't seek this data size");
+			return(ft->st_errno);
+	}
+
+	ft->st_errno = st_seek(ft,offset*sample_size,SEEK_SET);
+
+	return(ft->st_errno);
+}
+
 int st_rawstartread(ft) 
 ft_t ft;
 {
@@ -39,7 +69,7 @@
 	ft->file.buf = malloc(BUFSIZ);
 	if (!ft->file.buf)
 	{
-	    st_fail("Unable to alloc resources");
+	    st_fail_errno(ft,ST_ENOMEM,"Unable to alloc resources");
 	    return(ST_EOF);
 	}
 	ft->file.size = BUFSIZ;
@@ -56,7 +86,7 @@
 	ft->file.buf = malloc(BUFSIZ);
 	if (!ft->file.buf)
 	{
-	    st_fail("Unable to alloc resources");
+	    st_fail_errno(ft,ST_ENOMEM,"Unable to alloc resources");
 	    return(ST_EOF);
 	}
 	ft->file.size = BUFSIZ;
@@ -241,10 +271,10 @@
 				}
 				return done;
 			case ST_ENCODING_ULAW:
-				st_fail("No U-Law support for shorts");
+				st_fail_errno(ft,ST_EFMT,"No U-Law support for shorts");
 				return 0;
 			case ST_ENCODING_ALAW:
-				st_fail("No A-Law support for shorts");
+				st_fail_errno(ft,ST_EFMT,"No A-Law support for shorts");
 				return 0;
 		    }
 		    break;
@@ -276,7 +306,11 @@
 		default:
 			break;
 	}
-	st_fail("Sorry, don't have code to read %s, %s",
+/* Someone could send a really bad ft. i.e. ft->info.encoding = -145677 
+ * i should know I've done this.  It will segment fault st_fail_errno.
+ */
+
+	st_fail_errno(ft,ST_EFMT,"Sorry, don't have code to read %s, %s",
 		st_encodings_str[ft->info.encoding], st_sizes_str[ft->info.size]);
 	return(0);
 }
@@ -294,7 +328,7 @@
 {
 	if (fwrite(ft->file.buf, 1, ft->file.pos, ft->fp) != ft->file.pos)
 	{
-		st_fail("Error writing data to file");
+		st_fail_errno(ft,errno,"Error writing data to file");
 	}
 	ft->file.pos = 0;
 }
@@ -452,10 +486,10 @@
 				}
 				return done;
 			case ST_ENCODING_ULAW:
-				st_fail("No U-Law support for shorts");
+				st_fail_errno(ft,ST_EFMT,"No U-Law support for shorts");
 				return 0;
 			case ST_ENCODING_ALAW:
-				st_fail("No A-Law support for shorts");
+				st_fail_errno(ft,ST_EFMT,"No A-Law support for shorts");
 				return 0;
 		    }
 		    break;
@@ -484,7 +518,8 @@
 		default:
 			break;
 	}
-	st_fail("Sorry, don't have code to write %s, %s",
+	/* Possible overflow */
+	st_fail_errno(ft,ST_EFMT,"Sorry, don't have code to write %s, %s",
 		st_encodings_str[ft->info.encoding], st_sizes_str[ft->info.size]);
 	return 0;
 }
--- a/src/sf.c
+++ b/src/sf.c
@@ -26,6 +26,8 @@
 /* Private data for SF file */
 typedef struct sfstuff {
 	struct sfinfo info;
+	/* needed for seek */
+	LONG dataStart;
 } *sf_t;
 
 /*
@@ -68,6 +70,16 @@
 		ft->comment = commentbuf;
 }
 
+int st_sfseek(ft,offset) 
+ft_t ft;
+LONG offset;
+{
+	sf_t sf = (sf_t ) ft->priv;
+
+	return st_seek(ft,offset*ft->info.size + sf->dataStart,SEEK_SET);
+
+}
+
 /*
  * Do anything required before you start reading samples.
  * Read file header. 
@@ -81,12 +93,8 @@
 	sf_t sf = (sf_t) ft->priv;
 	SFHEADER sfhead;
 	int rc;
+	int samplesize = 0;	
 
-	/* Needed for rawread() */
-	rc = st_rawstartread(ft);
-	if (rc)
-	    return rc;
-	
 	if (fread(&sfhead, 1, sizeof(sfhead), ft->fp) != sizeof(sfhead))
 	{
 		st_fail("unexpected EOF in SF header");
@@ -114,10 +122,12 @@
 		case SF_SHORT:
 			ft->info.size = ST_SIZE_WORD;
 			ft->info.encoding = ST_ENCODING_SIGN2;
+			samplesize = ft->info.size;
 			break;
 		case SF_FLOAT:
 			ft->info.size = ST_SIZE_FLOAT;
 			ft->info.encoding = ST_ENCODING_SIGN2;
+			samplesize = sizeof(float);
 			break;
 		default:
 			st_fail("Soundfile input: unknown format 0x%x\n",
@@ -129,7 +139,18 @@
 	/* Read codes and print as comments. */
 	readcodes(ft, &sfhead);
 
-	return(ST_SUCCESS);
+	/* Needed for rawread() */
+	rc = st_rawstartread(ft);
+
+/* Need length for seeking */
+	if(ft->seekable){
+		ft->length = st_filelength(ft)/samplesize;
+		sf->dataStart = ftell(ft->fp);
+	} else {
+		ft->length = 0;
+	}
+	
+	return(rc);
 }
 
 int st_sfstartwrite(ft) 
--- a/src/skel.c
+++ b/src/skel.c
@@ -34,7 +34,7 @@
 	/* If you need to seek around the input file. */
 	if (! ft->seekable)
 	{
-		st_fail("SKEL input file must be a file, not a pipe");
+		st_fail_errno(ft,ST_EVALUE,"SKEL input file must be a file, not a pipe");
 		return (ST_EOF);
 	}
 
@@ -103,7 +103,7 @@
 	/* If you have to seek around the output file */
 	if (! ft->seekable)
 	{
-		st_fail("Output .skel file must be a file, not a pipe");
+		st_fail_errno(ft,ST_EVALUE,"Output .skel file must be a file, not a pipe");
 		return (ST_EOF);
 	}
 
@@ -130,7 +130,7 @@
 	while(len--)
 	    st_writeb(ft, (*buf++ >> 24) ^ 0x80);
 	/* If you cannot write out all of the supplied samples, */
-	/*	st_fail("SKEL: Can't write all samples to %s", ft->filename); */
+	/*	st_fail_errno(ft,ST_EVALUE,"SKEL: Can't write all samples to %s", ft->filename); */
 	/*      return (ST_EOF); */
 	return (ST_SUCCESS);
 	
--- a/src/smp.c
+++ b/src/smp.c
@@ -60,6 +60,7 @@
 /* Private data for SMP file */
 typedef struct smpstuff {
   ULONG NoOfSamps;		/* Sample data count in words */
+	LONG dataStart;
   /* comment memory resides in private data because it's small */
   char comment[COMMENTLEN + NAMELEN + 3];
 } *smp_t;
@@ -92,7 +93,7 @@
 	for(i = 0; i < 8; i++) {	/* read the 8 markers */
 	        if (fread(trailer->markers[i].name, 1, 10, ft->fp) != 10)
 		{
-		    st_fail("EOF in SMP");
+		    st_fail_errno(ft,ST_EHDR,"EOF in SMP");
 		    return(ST_EOF);
 		}
 		st_readdw(ft, &(trailer->markers[i].position));
@@ -160,7 +161,7 @@
 	for(i = 0; i < 8; i++) {	/* write the 8 markers */
 		if (st_writes(ft, trailer->markers[i].name) == ST_EOF)
 		{
-		    st_fail("EOF in SMP");
+		    st_fail_errno(ft,ST_EHDR,"EOF in SMP");
 	 	    return(ST_EOF);
 		}
 		st_writedw(ft, trailer->markers[i].position);
@@ -172,6 +173,19 @@
 	return(ST_SUCCESS);
 }
 
+int st_smpseek(ft,offset) 
+ft_t ft;
+LONG offset;
+{
+	smp_t smp = (smp_t) ft->priv;
+
+	ft->st_errno = st_seek(ft,offset*ft->info.size + smp->dataStart,SEEK_SET);
+
+	if( ft->st_errno == ST_SUCCESS )
+		smp->NoOfSamps = ft->length - offset;
+
+	return(ft->st_errno);
+}
 /*
  * Do anything required before you start reading samples.
  * Read file header. 
@@ -199,7 +213,7 @@
 	/* If you need to seek around the input file. */
 	if (! ft->seekable)
 	{
-		st_fail("SMP input file must be a file, not a pipe");
+		st_fail_errno(ft,ST_EOF,"SMP input file must be a file, not a pipe");
 		return(ST_EOF);
 	}
 
@@ -206,17 +220,17 @@
 	/* Read SampleVision header */
 	if (fread((char *) &header, 1, HEADERSIZE, ft->fp) != HEADERSIZE)
 	{
-		st_fail("unexpected EOF in SMP header");
+		st_fail_errno(ft,ST_EHDR,"unexpected EOF in SMP header");
 		return(ST_EOF);
 	}
 	if (strncmp(header.Id, SVmagic, 17) != 0)
 	{
-		st_fail("SMP header does not begin with magic word %s\n", SVmagic);
+		st_fail_errno(ft,ST_EHDR,"SMP header does not begin with magic word %s\n", SVmagic);
 		return(ST_EOF);
 	}
 	if (strncmp(header.version, SVvers, 4) != 0)
 	{
-		st_fail("SMP header is not version %s\n", SVvers);
+		st_fail_errno(ft,ST_EHDR,"SMP header is not version %s\n", SVvers);
 		return(ST_EOF);
 	}
 
@@ -243,12 +257,12 @@
 	/* NoOfSamps * 2 */
 	if (fseek(ft->fp, smp->NoOfSamps * 2L, 1) == -1)
 	{
-		st_fail("SMP unable to seek to trailer");
+		st_fail_errno(ft,errno,"SMP unable to seek to trailer");
 		return(ST_EOF);
 	}
 	if (readtrailer(ft, &trailer))
 	{
-		st_fail("unexpected EOF in SMP trailer");
+		st_fail_errno(ft,ST_EHDR,"unexpected EOF in SMP trailer");
 		return(ST_EOF);
 	}
 
@@ -255,7 +269,7 @@
 	/* seek back to the beginning of the data */
 	if (fseek(ft->fp, samplestart, 0) == -1) 
 	{
-		st_fail("SMP unable to seek back to start of sample data");
+		st_fail_errno(ft,errno,"SMP unable to seek back to start of sample data");
 		return(ST_EOF);
 	}
 
@@ -263,6 +277,8 @@
 	ft->info.size = ST_SIZE_WORD;
 	ft->info.encoding = ST_ENCODING_SIGN2;
 	ft->info.channels = 1;
+	smp->dataStart = samplestart;
+	ft->length = smp->NoOfSamps;
 
 	st_report("SampleVision trailer:\n");
 	for(i = 0; i < 8; i++) if (1 || trailer.loops[i].count) {
@@ -351,7 +367,7 @@
 	/* If you have to seek around the output file */
 	if (! ft->seekable)
 	{
-		st_fail("Output .smp file must be a file, not a pipe");
+		st_fail_errno(ft,ST_EOF,"Output .smp file must be a file, not a pipe");
 		return(ST_EOF);
 	}
 
@@ -368,7 +384,7 @@
 	/* Write file header */
 	if(fwrite(&header, 1, HEADERSIZE, ft->fp) != HEADERSIZE)
 	{
-	    st_fail("SMP: Can't write header completely");
+	    st_fail_errno(ft,errno,"SMP: Can't write header completely");
 	    return(ST_EOF);
 	}
 	st_writedw(ft, 0);	/* write as zero length for now, update later */
@@ -406,7 +422,7 @@
 	writetrailer(ft, &trailer);
 	if (fseek(ft->fp, 112, 0) == -1)
 	{
-		st_fail("SMP unable to seek back to save size");
+		st_fail_errno(ft,errno,"SMP unable to seek back to save size");
 		return(ST_EOF);
 	}
 	st_writedw(ft, smp->NoOfSamps);
--- a/src/sndrtool.c
+++ b/src/sndrtool.c
@@ -18,9 +18,10 @@
 #include "st.h"
 
 /* Private data used by writer */
-struct sndpriv {
+typedef struct sndpriv {
         ULONG nsamples;
-};
+		LONG dataStart;
+} *snd_t;
 
 #ifndef	SEEK_CUR
 #define	SEEK_CUR	1
@@ -28,6 +29,15 @@
 
 static void  sndtwriteheader(ft_t ft,LONG nsamples);
 
+int st_sndseek(ft,offset) 
+ft_t ft;
+LONG offset;
+{
+	snd_t snd = (snd_t ) ft->priv;
+
+	return st_seek(ft,offset*ft->info.size + snd->dataStart,SEEK_SET);
+
+}
 /*======================================================================*/
 /*                         SNDSTARTREAD                                */
 /*======================================================================*/
@@ -35,6 +45,8 @@
 int st_sndtstartread(ft)
 ft_t ft;
 {
+	snd_t snd = (snd_t ) ft->priv;
+
         char buf[97];
 
         unsigned short rate;
@@ -63,7 +75,7 @@
 
 	if (fread(buf, 1, 2, ft->fp) != 2)
 	{
-		st_fail("SND: unexpected EOF");
+		st_fail_errno(ft,errno,"SND: unexpected EOF");
 		return(ST_EOF);
 	}
 	if (strncmp(buf,"\0\0",2) == 0)
@@ -72,7 +84,7 @@
 	st_readw(ft, &rate);
 	if (rate < 4000 || rate > 25000 )
 	{
-		st_fail("SND: sample rate out of range");
+		st_fail_errno(ft,ST_EFMT,"SND: sample rate out of range");
 		return(ST_EOF);
 	}
 	fseek(ft->fp,4,SEEK_CUR);
@@ -83,7 +95,7 @@
 	fread(&buf[2], 1, 6, ft->fp);
 	if (strncmp(buf,"SOUND",5))
 	{
-		st_fail("SND: unrecognized SND format");
+		st_fail_errno(ft,ST_EFMT,"SND: unrecognized SND format");
 		return(ST_EOF);
 	}
 	fseek(ft->fp,12,SEEK_CUR);
@@ -91,7 +103,7 @@
 	fseek(ft->fp,6,SEEK_CUR);
 	if (st_reads(ft, buf, 96) == ST_EOF)
 	{
-		st_fail("SND: unexpected EOF in SND header");
+		st_fail_errno(ft,ST_EHDR,"SND: unexpected EOF in SND header");
 		return(ST_EOF);
 	}
 	st_report("%s",buf);
@@ -102,6 +114,9 @@
 ft->info.encoding = ST_ENCODING_UNSIGNED;
 ft->info.size = ST_SIZE_BYTE;
 
+snd->dataStart = ftell(ft->fp);
+ft->length = st_filelength(ft) - snd->dataStart;
+
 return (ST_SUCCESS);
 }
 
@@ -111,7 +126,7 @@
 int st_sndtstartwrite(ft)
 ft_t ft;
 {
-	struct sndpriv *p = (struct sndpriv *) ft->priv;
+	snd_t p = (snd_t ) ft->priv;
 	int rc;
 
 	/* Needed for rawwrite() */
@@ -179,7 +194,7 @@
 ft_t ft;
 LONG *buf, len;
 {
-	struct sndpriv *p = (struct sndpriv *) ft->priv;
+	snd_t p = (snd_t ) ft->priv;
 	p->nsamples += len;
 	return st_rawwrite(ft, buf, len);
 }
@@ -191,7 +206,7 @@
 int st_sndtstopwrite(ft)
 ft_t ft;
 {
-	struct sndpriv *p = (struct sndpriv *) ft->priv;
+	snd_t p = (snd_t ) ft->priv;
 	int rc;
 
 	/* Flush remaining buffer out */
@@ -200,9 +215,13 @@
 	    return rc;
 
 	/* fixup file sizes in header */
-	if (fseek(ft->fp, 0L, 0) != 0)
-		st_fail("can't rewind output file to rewrite SND header");
+	if (fseek(ft->fp, 0L, 0) != 0){
+		st_fail_errno(ft,errno,"can't rewind output file to rewrite SND header");
+		return ST_EOF;
+	}
+		
 	sndtwriteheader(ft, p->nsamples);
+		
 
 	return(ST_SUCCESS);
 }
--- a/src/sox.c
+++ b/src/sox.c
@@ -414,9 +414,11 @@
 static void process(void) {
     int e, f, havedata, flowstatus;
 
-    st_gettype(&informat);
+    if( st_gettype(&informat) )
+		st_fail("bad input format");	
     if (writing)
-	st_gettype(&outformat);
+	if ( st_gettype(&outformat) )
+		st_fail("bad output format");	
     
     /* Read and write starters can change their formats. */
     if ((* informat.h->startread)(&informat) == ST_EOF)
@@ -423,7 +425,8 @@
     {
         st_fail(informat.st_errstr);
     }
-    st_checkformat(&informat);
+    if ( st_checkformat(&informat) )
+		st_fail("bad input format");
     
     if (dovolume)
 	st_report("Volume factor: %f\n", volume);
@@ -479,7 +482,8 @@
 	{
 	    st_fail(outformat.st_errstr);
 	}
-	st_checkformat(&outformat);
+	if (st_checkformat(&outformat))
+		st_fail("bad output format");
 	st_cmpformats(&informat, &outformat);
 	st_report("Output file: using sample rate %lu\n\tsize %s, encoding %s, %d %s",
 	       outformat.info.rate, st_sizes_str[outformat.info.size], 
@@ -528,6 +532,7 @@
     /* Prime while() loop by reading initial chunk of input data. */
     efftab[0].olen = (*informat.h->read)(&informat, 
                                          efftab[0].obuf, (LONG) BUFSIZ);
+
     efftab[0].odone = 0;
 
     /* Change the volume of this initial input data if needed. */
--- a/src/sphere.c
+++ b/src/sphere.c
@@ -43,14 +43,13 @@
 	/* Magic header */
 	if (st_reads(ft, buf, 8) == ST_EOF || strncmp(buf, "NIST_1A", 7) != 0)
 	{
-	    st_fail("Sphere header does not begin with magic mord 'NIST_1A'");
+	    st_fail_errno(ft,ST_EHDR,"Sphere header does not begin with magic mord 'NIST_1A'");
 	    return(ST_EOF);
 	}
 
 	if (st_reads(ft, fldsval, 8) == ST_EOF)
 	{
-	    printf("%s\n",fldsval);
-	    st_fail("Error reading Sphere header");
+	    st_fail_errno(ft,ST_EHDR,"Error reading Sphere header %s",fldsval);
 	    return(ST_EOF);
 	}
 
@@ -61,7 +60,7 @@
 
 	if (st_reads(ft, buf, 255) == ST_EOF)
 	{
-	    st_fail("Error reading Sphere header");
+	    st_fail_errno(ft,ST_EHDR,"Error reading Sphere header");
 	    return(ST_EOF);
 	}
 
@@ -122,7 +121,7 @@
 
 	    if (st_reads(ft, buf, 255) == ST_EOF)
 	    {
-	        st_fail("Error reading Sphere header");
+	        st_fail_errno(ft,ST_EHDR,"Error reading Sphere header");
 	        return(ST_EOF);
 	    }
 
@@ -165,7 +164,7 @@
 
 	if (!strcmp(sphere->shorten_check,"ajkg"))
 	{
-	    st_fail("File uses shorten compression, can not handle this.\n");
+	    st_fail_errno(ft,ST_EFMT,"File uses shorten compression, can not handle this.\n");
 	    return(ST_EOF);
 	}
 #endif
@@ -205,7 +204,7 @@
 
     if (!ft->seekable)
     {
-	st_fail("File must be seekable for sphere file output");
+	st_fail_errno(ft,ST_EOF,"File must be seekable for sphere file output");
 	return (ST_EOF);
     }
 
@@ -216,7 +215,7 @@
 	case ST_ENCODING_UNSIGNED:
 	    break;
 	default:
-	    st_fail("SPHERE format only supports ulaw and PCM data.");
+	    st_fail_errno(ft,ST_EFMT,"SPHERE format only supports ulaw and PCM data.");
 	    return(ST_EOF);
     }
 
@@ -259,7 +258,7 @@
 
     if (fseek(ft->fp, 0L, 0) != 0)
     {
-	st_fail("Could not rewird output file to rewrite sphere header.\n");
+	st_fail_errno(ft,errno,"Could not rewird output file to rewrite sphere header.\n");
 	return (ST_EOF);
     }
 
--- a/src/st.h
+++ b/src/st.h
@@ -63,22 +63,22 @@
 /* Signal parameters */
 
 /* FIXME: Change to typedef */
-struct  st_signalinfo {
+typedef struct  st_signalinfo {
 	LONG		rate;		/* sampling rate */
 	int		size;		/* word length of data */
 	int		encoding;	/* format of sample numbers */
 	int		channels;	/* number of sound channels */
-};
+} st_signalinfo_t;
 
 /* Loop parameters */
 
 /* FIXME: Change to typedef */
-struct  st_loopinfo {
+typedef struct  st_loopinfo {
 	int		start;		/* first sample */
 	int		length;		/* length */
 	int		count;		/* number of repeats, 0=forever */
 	int		type;		/* 0=no, 1=forward, 2=forward/back */
-};
+}st_loopinfo_t;
 
 /* Instrument parameters */
 
@@ -85,7 +85,7 @@
 /* vague attempt at generic information for sampler-specific info */
 
 /* FIXME: Change to typedef */
-struct  st_instrinfo {
+typedef struct  st_instrinfo {
 	char 		MIDInote;	/* for unity pitch playback */
 	char		MIDIlow, MIDIhi;/* MIDI pitch-bend range */
 	char		loopmode;	/* semantics of loop data */
@@ -92,7 +92,7 @@
 	char		nloops;		/* number of active loops */
 	unsigned char	smpte[4];	/* SMPTE offset (hour:min:sec:frame) */
 					/* this is a film audio thing */
-};
+} st_instrinfo_t;
 
 
 #define ST_MIDI_UNITY 60	/* MIDI note number to play sample at unity */
@@ -108,13 +108,13 @@
  */
 
 /* FIXME: Change to typedef */
-struct st_fileinfo {
+typedef struct st_fileinfo {
 	char	*buf;			/* Pointer to data buffer */
 	int	size;			/* Size of buffer */
 	int	count;			/* Count read in to buffer */
 	int	pos;			/* Position in buffer */
 	int	eof;			/* Marker that EOF has been reached */
-};
+}st_fileinfo_t;
 
 
 /*
@@ -140,24 +140,26 @@
 	int	(*startwrite)(ft_t ft);
 	LONG	(*write)(ft_t ft, LONG *buf, LONG len);
 	int	(*stopwrite)(ft_t ft);
+	int	(*seek)(ft_t ft, LONG offset);
 } st_format_t;
 
 struct st_soundstream {
-	struct	st_signalinfo info;	/* signal specifications */
-	struct  st_instrinfo instr;	/* instrument specification */
-	struct  st_loopinfo loops[ST_MAX_NLOOPS]; /* Looping specification */
+	st_signalinfo_t info;	/* signal specifications */
+	st_instrinfo_t instr;	/* instrument specification */
+	st_loopinfo_t loops[ST_MAX_NLOOPS]; /* Looping specification */
 	char	swap;			/* do byte- or word-swap */
 	char	seekable;		/* can seek on this file */
+	LONG	length;			/* estimate of total samples in file - for seeking*/
 	char	*filename;		/* file name */
 	char	*filetype;		/* type of file */
 	char	*comment;		/* comment string */
 	FILE	*fp;			/* File stream pointer */
-	struct	st_fileinfo file;	/* File data block */
+	st_fileinfo_t file;	/* File data block */
 	int     st_errno;		/* Failure error codes */
 	char	st_errstr[256];		/* Extend Failure text */
 	st_format_t *h;			/* format struct for this file */
 	/* FIXME: I perfer void * or char * */
-	double	priv[ST_MAX_PRIVSIZE/8]; /* format's private data area */
+	char	priv[ST_MAX_PRIVSIZE]; /* format's private data area */
 };
 
 extern st_format_t st_formats[];
@@ -166,6 +168,7 @@
 #define ST_FILE_STEREO	1	/* does file format support stereo? */
 #define ST_FILE_LOOPS	2	/* does file format support loops? */
 #define ST_FILE_INSTR	4	/* does file format support instrument specificications? */
+#define ST_FILE_SEEK	8	/* does file format support seeking? */
 
 /* Size field */ 
 /* SJB: note that the 1st 3 are sometimes used as sizeof(type) */
@@ -227,8 +230,10 @@
 	st_effect_t 	*h;		/* effects driver */
 	LONG		*obuf;		/* output buffer */
 	LONG		odone, olen;	/* consumed, total length */
-	/* FIXME: I perfer void * or char * */
-	double		priv[ST_MAX_PRIVSIZE]; /* private area for effect */
+	/* FIXME: I perfer void * or char * 
+	* Why was this private area 8 times bigger then the soundstream one?
+	* Someone forget to divide ST_MAX_PRIVSIZE by 8 ? */
+	char		priv[ST_MAX_PRIVSIZE*8]; /* private area for effect */
 };
 
 extern st_effect_t st_effects[]; /* declared in handlers.c */
@@ -276,6 +281,8 @@
 int	st_writef(ft_t ft, double f);
 int	st_readdf(ft_t ft, double *d);
 int	st_writedf(ft_t ft, double d);
+int st_seek(ft_t ft, LONG offset, int whence);
+LONG st_filelength(ft_t ft);
 
 /* FIXME: raw routines are used by so many formats their prototypes are defined
  * here for convience.  This wont last for long so application software
@@ -286,6 +293,7 @@
 int st_rawstartwrite(ft_t ft);
 int st_rawstopread(ft_t ft);
 int st_rawstopwrite(ft_t ft);
+int st_rawseek(ft_t ft, LONG offset);
 LONG st_rawread(ft_t ft, LONG *buf, LONG nsamp);
 LONG st_rawwrite(ft_t ft, LONG *buf, LONG nsamp);
 
@@ -321,8 +329,8 @@
 int st_geteffect_opt(eff_t, int, char **);
 int st_geteffect(eff_t, char *);
 int st_updateeffect(eff_t, ft_t, ft_t, int);
-void st_gettype(ft_t);
-void st_checkformat(ft_t);
+int st_gettype(ft_t);
+int st_checkformat(ft_t);
 void st_copyformat(ft_t, ft_t);
 void st_cmpformats(ft_t, ft_t);
 double st_parsetime(char *);
@@ -338,6 +346,7 @@
 extern int verbose;	/* be noisy on stderr */
 extern char *myname;
 
+extern int errno;
 /* Warning, this is a MAX value used in the library.  Each format and
  * effect may have its own limitations of rate.
  */
@@ -368,8 +377,11 @@
 /* ST specific error codes.  The rest directly map from errno. */
 #define ST_EHDR 2000		/* Invalid Audio Header */
 #define ST_EFMT 2001		/* Unsupported data format */
-#define ST_ERATE 20002		/* Unsupported rate for format */
+#define ST_ERATE 2002		/* Unsupported rate for format */
 #define ST_ENOMEM 2003		/* Can't alloc memory */
+#define ST_EPERM 2004		/* Operation not permitted */
+#define ST_ENOTSUP 2005		/* Operation not supported */
+#define ST_EINVAL 2006		/* Invalid argument */
 
 #ifdef __cplusplus
 } /* end of extern "C" */
--- a/src/sunaudio.c
+++ b/src/sunaudio.c
@@ -55,7 +55,7 @@
     ft->file.eof = 0;
     ft->file.size = 1024;
     if ((ft->file.buf = malloc (ft->file.size)) == NULL) {
-	st_fail("unable to allocate input buffer of size %d", ft->file.size);
+	st_fail_errno(ft,ST_ENOMEM,"unable to allocate input buffer of size %d", ft->file.size);
 	return ST_EOF;
     }
 
@@ -66,7 +66,7 @@
 #ifdef __SVR4
     /* Read in old values, change to what we need and then send back */
     if (ioctl(fileno(ft->fp), AUDIO_GETDEV, &audio_dev) < 0) {
-	st_fail("Unable to get device information.");
+	st_fail_errno(ft,errno,"Unable to get device information.");
 	return(ST_EOF);
     }
     st_report("Hardware detected:  %s\n",audio_dev.name);
@@ -101,7 +101,8 @@
 	if (ft->info.encoding != ST_ENCODING_ULAW &&
 	    ft->info.encoding != ST_ENCODING_ALAW &&
 	    ft->info.encoding != ST_ENCODING_SIGN2) {
-	    st_fail("Sun Audio driver only supports ULAW, ALAW, and Signed Linear for bytes.");
+	    st_fail_errno(ft,ST_EFMT,"Sun Audio driver only supports ULAW, ALAW, and Signed Linear for bytes.");
+		return (ST_EOF);
 	}
 	if ((ft->info.encoding == ST_ENCODING_ULAW || 
 	     ft->info.encoding == ST_ENCODING_ALAW) && ft->info.channels == 2)
@@ -113,12 +114,12 @@
     else if (ft->info.size == ST_SIZE_WORD) {
 	samplesize = 16;
 	if (ft->info.encoding != ST_ENCODING_SIGN2) {
-	    st_fail("Sun Audio driver only supports Signed Linear for words.");
+	    st_fail_errno(ft,ST_EFMT,"Sun Audio driver only supports Signed Linear for words.");
 	    return(ST_EOF);
 	}
     }
     else {
-	st_fail("Sun Audio driver only supports bytes and words");
+	st_fail_errno(ft,ST_EFMT,"Sun Audio driver only supports bytes and words");
 	return(ST_EOF);
     }
 
@@ -134,7 +135,7 @@
 
     /* Read in old values, change to what we need and then send back */
     if (ioctl(fileno(ft->fp), AUDIO_GETINFO, &audio_if) < 0) {
-	st_fail("Unable to initialize /dev/audio");
+	st_fail_errno(ft,errno,"Unable to initialize /dev/audio");
 	return(ST_EOF);
     }
     audio_if.record.precision = samplesize;
@@ -150,19 +151,19 @@
     
     ioctl(fileno(ft->fp), AUDIO_SETINFO, &audio_if);
     if (audio_if.record.precision != samplesize) {
-        st_fail("Unable to initialize sample size for /dev/audio");
+        st_fail_errno(ft,errno,"Unable to initialize sample size for /dev/audio");
 	return(ST_EOF);
     }
     if (audio_if.record.channels != ft->info.channels) {
-	st_fail("Unable to initialize number of channels for /dev/audio");
+	st_fail_errno(ft,errno,"Unable to initialize number of channels for /dev/audio");
 	return(ST_EOF);
     }
     if (audio_if.record.sample_rate != ft->info.rate) {
-	st_fail("Unable to initialize rate for /dev/audio");
+	st_fail_errno(ft,errno,"Unable to initialize rate for /dev/audio");
 	return(ST_EOF);
     }
     if (audio_if.record.encoding != encoding) {
-	st_fail("Unable to initialize encoding for /dev/audio");
+	st_fail_errno(ft,errno,"Unable to initialize encoding for /dev/audio");
 	return(ST_EOF);
     }
     /* Change to non-buffered I/O*/
@@ -188,7 +189,7 @@
     ft->file.eof = 0;
     ft->file.size = 1024;
     if ((ft->file.buf = malloc (ft->file.size)) == NULL) {
-	st_fail("unable to allocate output buffer of size %d", ft->file.size);
+	st_fail_errno(ft,ST_ENOMEM,"unable to allocate output buffer of size %d", ft->file.size);
 	return(ST_EOF);
     }
 
@@ -195,7 +196,7 @@
 #ifdef __SVR4
     /* Read in old values, change to what we need and then send back */
     if (ioctl(fileno(ft->fp), AUDIO_GETDEV, &audio_dev) < 0) {
-	st_fail("Unable to get device information.");
+	st_fail_errno(ft,errno,"Unable to get device information.");
 	return(ST_EOF);
     }
     st_report("Hardware detected:  %s\n",audio_dev.name);
@@ -264,7 +265,7 @@
 
     /* Read in old values, change to what we need and then send back */
     if (ioctl(fileno(ft->fp), AUDIO_GETINFO, &audio_if) < 0) {
-	st_fail("Unable to initialize /dev/audio");
+	st_fail_errno(ft,errno,"Unable to initialize /dev/audio");
 	return(ST_EOF);
     }
     audio_if.play.precision = samplesize;
@@ -280,19 +281,19 @@
     
     ioctl(fileno(ft->fp), AUDIO_SETINFO, &audio_if);
     if (audio_if.play.precision != samplesize) {
-	st_fail("Unable to initialize sample size for /dev/audio");
+	st_fail_errno(ft,errno,"Unable to initialize sample size for /dev/audio");
 	return(ST_EOF);
     }
     if (audio_if.play.channels != ft->info.channels) {
-	st_fail("Unable to initialize number of channels for /dev/audio");
+	st_fail_errno(ft,errno,"Unable to initialize number of channels for /dev/audio");
 	return(ST_EOF);
     }
     if (audio_if.play.sample_rate != ft->info.rate) {
-	st_fail("Unable to initialize rate for /dev/audio");
+	st_fail_errno(ft,errno,"Unable to initialize rate for /dev/audio");
 	return(ST_EOF);
     }
     if (audio_if.play.encoding != encoding) {
-	st_fail("Unable to initialize encoding for /dev/audio");
+	st_fail_errno(ft,errno,"Unable to initialize encoding for /dev/audio");
 	return(ST_EOF);
     }
     /* Change to non-buffered I/O */
--- a/src/tx16w.c
+++ b/src/tx16w.c
@@ -90,7 +90,7 @@
   /* If you need to seek around the input file. */
   if (! ft->seekable)
   {
-    st_fail("txw input file must be a file, not a pipe");
+    st_fail_errno(ft,ST_EOF,"txw input file must be a file, not a pipe");
     return(ST_EOF);
   }
 
@@ -127,7 +127,7 @@
   st_report("Found header filetype %s",filetype);
   if(strcmp(filetype,"LM8953"))
   {
-    st_fail("Invalid filetype ID in input file header, != LM8953");
+    st_fail_errno(ft,ST_EHDR,"Invalid filetype ID in input file header, != LM8953");
     return(ST_EOF);
   }
   /*
@@ -267,7 +267,7 @@
   /* If you have to seek around the output file */
   if (! ft->seekable)
   {
-      st_fail("Output .txw file must be a file, not a pipe");
+      st_fail_errno(ft,ST_EOF,"Output .txw file must be a file, not a pipe");
       return(ST_EOF);
   }
 
@@ -331,7 +331,7 @@
     else                            WH.sample_rate = 2;
     
     if (tx16w_len >= TXMAXLEN) {
-        fprintf(stderr,"Sound too large for TX16W. Truncating, Loop Off\n");
+        st_warn("Sound too large for TX16W. Truncating, Loop Off\n");
         AttackLength       = TXMAXLEN/2;
         LoopLength         = TXMAXLEN/2;
     }
--- a/src/util.c
+++ b/src/util.c
@@ -83,6 +83,8 @@
 
 /* Warning: no error checking is done with errstr.  Be sure not to
  * go over the array limit ourself!
+ * Note:  Changing vsprintf to vsnprintf should help that but bad
+ * references to strings can still cause overflow.
  */
 void
 st_fail_errno(ft_t ft, int st_errno, const char *fmt, ...)
@@ -92,8 +94,9 @@
 	ft->st_errno = st_errno;
 
 	va_start(args, fmt);
-	vsprintf(ft->st_errstr, fmt, args);
+	vsnprintf(ft->st_errstr, 255,fmt, args);
 	va_end(args);
+	ft->st_errstr[255] = '\0';
 }
 
 int st_is_bigendian(void)
@@ -133,7 +136,7 @@
 /*
  * Check that we have a known format suffix string.
  */
-void
+int
 st_gettype(formp)
 ft_t formp;
 {
@@ -140,9 +143,11 @@
 	char **list;
 	int i;
 
-	if (! formp->filetype)
-st_fail("Must give file type for %s file, either as suffix or with -t option",
+	if (! formp->filetype){
+st_fail_errno(formp,ST_EFMT,"Must give file type for %s file, either as suffix or with -t option",
 formp->filename);
+		return(ST_EFMT);
+	}
 	for(i = 0; st_formats[i].names; i++) {
 		for(list = st_formats[i].names; *list; list++) {
 			char *s1 = *list, *s2 = formp->filetype;
@@ -153,7 +158,7 @@
 			continue;
 		/* Found it! */
 		formp->h = &st_formats[i];
-		return;
+		return ST_SUCCESS;
 	}
 	if (! strcmpcase(formp->filetype, "snd")) {
 		verbose = 1;
@@ -164,10 +169,12 @@
 		st_report("If it came from a PC, it's probably a Soundtool file.");
 		st_report("Use the sequence '-t .sndt file.snd'");
 		st_report("If it came from a NeXT, it's probably a .au file.");
-		st_fail("Use the sequence '-t .au file.snd'\n");
+		st_fail_errno(formp,ST_EFMT,"Use the sequence '-t .au file.snd'\n");
+		return ST_EFMT;
 	}
-	st_fail("File type '%s' of %s file is not known!",
+	st_fail_errno(formp,ST_EFMT,"File type '%s' of %s file is not known!",
 		formp->filetype, formp->filename);
+	return ST_EFMT;
 }
 
 /*
@@ -371,23 +378,37 @@
 }
 
 /* check that all settings have been given */
-void st_checkformat(ft) 
+int st_checkformat(ft) 
 ft_t ft;
 {
+
+	ft->st_errno = ST_SUCCESS;
+
 	if (ft->info.rate == 0)
-		st_fail("Sampling rate for %s file was not given\n", ft->filename);
+		st_fail_errno(ft,ST_EFMT,"Sampling rate for %s file was not given\n", ft->filename);
 	if ((ft->info.rate < 100) || (ft->info.rate > 999999L))
-		st_fail("Sampling rate %lu for %s file is bogus\n", 
+		st_fail_errno(ft,ST_EFMT,"Sampling rate %lu for %s file is bogus\n", 
 			ft->info.rate, ft->filename);
 	if (ft->info.size == -1)
-		st_fail("Data size was not given for %s file\nUse one of -b/-w/-l/-f/-d/-D", ft->filename);
+		st_fail_errno(ft,ST_EFMT,"Data size was not given for %s file\nUse one of -b/-w/-l/-f/-d/-D", ft->filename);
 	if (ft->info.encoding == -1 && ft->info.size != ST_SIZE_FLOAT)
-		st_fail("Data encoding was not given for %s file\nUse one of -s/-u/-U/-A", ft->filename);
+		st_fail_errno(ft,ST_EFMT,"Data encoding was not given for %s file\nUse one of -s/-u/-U/-A", ft->filename);
+/* I put these here because some modules call st_fail_errno with 
+ *	st_sizes_str[ft->info.size] etc.  I don't think the library should 
+ *	seg fault even if the app using doesn't init ft properly or overflows 
+ *	into it. 
+ *  anyway to check length on st_sizes_str[] ? */ 
+	if ((ft->info.size < 0) || (ft->info.size > 7))
+		st_fail_errno(ft,ST_EFMT,"Data size %i for %s file is bogus\n", ft->filename,ft->info.size);
+	/* anyway to check length on st_encoding_str[] ? */ 
+	if (ft->info.encoding < -1 || ft->info.encoding > 7)
+		st_fail_errno(ft,ST_EFMT,"Data encoding %i for %s file is bogus\n", ft->filename,ft->info.encoding);
 	/* it's so common, might as well default */
 	if (ft->info.channels == -1)
 		ft->info.channels = 1;
 	/*	st_fail("Number of output channels was not given for %s file",
 			ft->filename); */
+	return ft->st_errno;
 }
 
 static ft_t ft_queue[2];
--- a/src/voc.c
+++ b/src/voc.c
@@ -186,19 +186,21 @@
 		ft->swap = ft->swap ? 0 : 1;
 	}
 
+
 	if (! ft->seekable)
 	{
-		st_fail("VOC input file must be a file, not a pipe");
+		st_fail_errno(ft,ST_EOF,"VOC input file must be a file, not a pipe");
 		return(ST_EOF);
 	}
+
 	if (fread(header, 1, 20, ft->fp) != 20)
 	{
-		st_fail("unexpected EOF in VOC header");
+		st_fail_errno(ft,ST_EHDR,"unexpected EOF in VOC header");
 		return(ST_EOF);
 	}
 	if (strncmp(header, "Creative Voice File\032", 19))
 	{
-		st_fail("VOC file header incorrect");
+		st_fail_errno(ft,ST_EHDR,"VOC file header incorrect");
 		return(ST_EOF);
 	}
 
@@ -213,7 +215,7 @@
 	    return rc;
 	if (v->rate == -1)
 	{
-		st_fail("Input .voc file had no sound!");
+		st_fail_errno(ft,ST_EOF,"Input .voc file had no sound!");
 		return(ST_EOF);
 	}
 
@@ -313,7 +315,7 @@
 
 	if (! ft->seekable)
 	{
-		st_fail("Output .voc file must be a file, not a pipe");
+		st_fail_errno(ft,ST_EOF,"Output .voc file must be a file, not a pipe");
 		return(ST_EOF);
 	}
 
@@ -414,12 +416,12 @@
 		        if (!v->extended) {
 			  if (uc == 0)
 			  {
-			    st_fail("File %s: Sample rate is zero?");
+			    st_fail_errno(ft,ST_EFMT,"File %s: Sample rate is zero?");
 			    return(ST_EOF);
 			  }
 			  if ((v->rate != -1) && (uc != v->rate))
 			  {
-			    st_fail("File %s: sample rate codes differ: %d != %d",
+			    st_fail_errno(ft,ST_EFMT,"File %s: sample rate codes differ: %d != %d",
 				 ft->filename,v->rate, uc);
 			    return(ST_EOF);
 			  }
@@ -430,7 +432,7 @@
 			st_readb(ft, &uc);
 			if (uc != 0)
 			{
-			  st_fail("File %s: only interpret 8-bit data!",
+			  st_fail_errno(ft,ST_EFMT,"File %s: only interpret 8-bit data!",
 			       ft->filename);
 			  return(ST_EOF);
 			}
@@ -442,12 +444,12 @@
 			st_readdw(ft, &new_rate_long);
 			if (new_rate_long == 0)
 			{
-			    st_fail("File %s: Sample rate is zero?",ft->filename);
+			    st_fail_errno(ft,ST_EFMT,"File %s: Sample rate is zero?",ft->filename);
 			    return(ST_EOF);
 			}
 			if ((v->rate != -1) && (new_rate_long != v->rate))
 			{
-			    st_fail("File %s: sample rate codes differ: %d != %d",
+			    st_fail_errno(ft,ST_EFMT,"File %s: sample rate codes differ: %d != %d",
 				ft->filename, v->rate, new_rate_long);
 			    return(ST_EOF);
 			}
@@ -459,7 +461,7 @@
 			    case 8:	v->size = ST_SIZE_BYTE; break;
 			    case 16:	v->size = ST_SIZE_WORD; break;
 			    default:	
-					st_fail("Don't understand size %d", uc);
+					st_fail_errno(ft,ST_EFMT,"Don't understand size %d", uc);
 					return(ST_EOF);
 			}
 			st_readb(ft, &(v->channels));
@@ -482,7 +484,7 @@
 			st_readb(ft, &uc);
 			if (uc == 0)
 			{
-				st_fail("File %s: Silence sample rate is zero");
+				st_fail_errno(ft,ST_EFMT,"File %s: Silence sample rate is zero");
 				return(ST_EOF);
 			}
 			/* 
@@ -525,12 +527,12 @@
 			st_readw(ft, &new_rate_short);
 			if (new_rate_short == 0)
 			{
-			   st_fail("File %s: Sample rate is zero?");
+			   st_fail_errno(ft,ST_EFMT,"File %s: Sample rate is zero?");
 			   return(ST_EOF);
 			}
 			if ((v->rate != -1) && (new_rate_short != v->rate))
 			{
-			   st_fail("File %s: sample rate codes differ: %d != %d",
+			   st_fail_errno(ft,ST_EFMT,"File %s: sample rate codes differ: %d != %d",
 					ft->filename, v->rate, new_rate_short);
 			   return(ST_EOF);
 			}
@@ -538,7 +540,7 @@
 			st_readb(ft, &uc);
 			if (uc != 0)
 			{
-				st_fail("File %s: only interpret 8-bit data!",
+				st_fail_errno(ft,ST_EFMT,"File %s: only interpret 8-bit data!",
 					ft->filename);
 				return(ST_EOF);
 			}
--- a/src/wav.c
+++ b/src/wav.c
@@ -80,12 +80,13 @@
 
 /* Private data for .wav file */
 typedef struct wavstuff {
-    LONG	   numSamples;     /* reading: starts at total count and decremented  */
+    LONG	   numSamples;     /* samples/channel reading: starts at total count and decremented  */
     		                   /* writing: starts at 0 and counts samples written */
     LONG	   dataLength;     /* needed for ADPCM writing */
     unsigned short formatTag;	   /* What type of encoding file is using */
     unsigned short samplesPerBlock;
     unsigned short blockAlign;
+    LONG dataStart;  /* need to for seeking */
     
     /* following used by *ADPCM wav files */
     unsigned short nCoefs;	    /* ADPCM: number of coef sets */
@@ -225,7 +226,7 @@
 	/* write the compressed packet */
 	if (fwrite(wav->packet, wav->blockAlign, 1, ft->fp) != 1)
 	{
-	    st_fail("write error");
+	    st_fail_errno(ft,ST_EOF,"write error");
 	    return (ST_EOF);
 	}
 	/* update lengths and samplePtr */
@@ -254,18 +255,18 @@
     wav->gsmhandle=gsm_create();
     if (!wav->gsmhandle)
     {
-	st_fail("cannot create GSM object");
+	st_fail_errno(ft,ST_EOF,"cannot create GSM object");
 	return (ST_EOF);
     }
 	
     if(gsm_option(wav->gsmhandle,GSM_OPT_WAV49,&valueP) == -1){
-	st_fail("error setting gsm_option for WAV49 format. Recompile gsm library with -DWAV49 option and relink sox");
+	st_fail_errno(ft,ST_EOF,"error setting gsm_option for WAV49 format. Recompile gsm library with -DWAV49 option and relink sox");
 	return (ST_EOF);
     }
 
     wav->gsmsample=malloc(sizeof(gsm_signal)*160*2);
     if (wav->gsmsample == NULL){
-	st_fail("error allocating memory for gsm buffer");
+	st_fail_errno(ft,ST_ENOMEM,"error allocating memory for gsm buffer");
 	return (ST_EOF);
     }
     wav->gsmindex=0;
@@ -290,6 +291,8 @@
     int bytes;
     gsm_byte	frame[65];
 
+	ft->st_errno = ST_SUCCESS;
+
   /* copy out any samples left from the last call */
     while(wav->gsmindex && (wav->gsmindex<160*2) && (done < len))
 	buf[done++]=LEFT(wav->gsmsample[wav->gsmindex++],16);
@@ -307,13 +310,13 @@
 	/* decode the long 33 byte half */
 	if(gsm_decode(wav->gsmhandle,frame, wav->gsmsample)<0)
 	{
-	    st_fail("error during gsm decode");
+	    st_fail_errno(ft,ST_EOF,"error during gsm decode");
 	    return 0;
 	}
 	/* decode the short 32 byte half */
 	if(gsm_decode(wav->gsmhandle,frame+33, wav->gsmsample+160)<0)
 	{
-	    st_fail("error during gsm decode");
+	    st_fail_errno(ft,ST_EOF,"error during gsm decode");
 	    return 0;
 	}
 
@@ -342,7 +345,7 @@
     gsm_encode(wav->gsmhandle, wav->gsmsample+160, frame+32);
     if (fwrite(frame, 1, 65, ft->fp) != 65)
     {
-	st_fail("write error");
+	st_fail_errno(ft,ST_EOF,"write error");
 	return (ST_EOF);
     }
     wav->gsmbytecount += 65;
@@ -353,7 +356,7 @@
 	/* pad output to an even number of bytes */
 	if(st_writeb(ft, 0))
 	{
-	    st_fail("write error");
+	    st_fail_errno(ft,ST_EOF,"write error");
 	    return (ST_EOF);
 	}
 	wav->gsmbytecount += 1;
@@ -369,6 +372,8 @@
     int done = 0;
     int rc;
 
+	ft->st_errno = ST_SUCCESS;
+
     while (done < len) {
 	while ((wav->gsmindex < 160*2) && (done < len))
 	    wav->gsmsample[(wav->gsmindex)++] = RIGHT(buf[done++], 16);
@@ -389,6 +394,8 @@
 {
     wav_t	wav = (wav_t) ft->priv;
 
+	ft->st_errno = ST_SUCCESS;
+
     if (wav->gsmindex)
 	wavgsmflush(ft, 1);
 
@@ -399,7 +406,10 @@
 /* General Sox WAV file code                                                */
 /****************************************************************************/
 
-/* FIXME: Use common misc.c skip code */
+/* FIXME: Use common misc.c skip code 
+
+moved to misc.c using st_seek(ft,len,SEEK_CUR) instead
+
 static void fSkip(FILE *fp, ULONG len)
 {
     while (len > 0 && !feof(fp))
@@ -408,7 +418,7 @@
 	len--;
     }
 }
-
+*/
 static ULONG findChunk(ft_t ft, const char *Label)
 {
     char magic[5];
@@ -417,14 +427,16 @@
     {
 	if (st_reads(ft, magic, 4) == ST_EOF)
 	{
-	    st_fail("WAVE file has missing %s chunk", Label);
-	    return 0;
+	    st_fail_errno(ft,ST_EHDR,"WAVE file has missing %s chunk", Label);
+	    return ST_EOF;
 	}
 	st_readdw(ft, &len);
+	st_report("Chunk %s",magic);
 	if (strncmp(Label, magic, 4) == 0)
 	    break;		/* Found the data chunk */
+
 	
-	fSkip(ft->fp, len); 	/* skip to next chunk */
+	st_seek(ft, len, SEEK_CUR); 	/* skip to next chunk */
     }
     return len;
 }
@@ -456,12 +468,15 @@
     ULONG    wDataLength;	    /* length of sound data in bytes */
     ULONG    bytesPerBlock = 0;
     ULONG    bytespersample;	    /* bytes per sample (per channel */
+	char text[256];
 
+	ft->st_errno = ST_SUCCESS;
+
     if (ST_IS_BIGENDIAN) ft->swap = ft->swap ? 0 : 1;
 
     if (st_reads(ft, magic, 4) == ST_EOF || strncmp("RIFF", magic, 4))
     {
-	st_fail("WAVE: RIFF header not found");
+	st_fail_errno(ft,ST_EHDR,"WAVE: RIFF header not found");
 	return ST_EOF;
     }
 
@@ -469,7 +484,7 @@
 
     if (st_reads(ft, magic, 4) == ST_EOF || strncmp("WAVE", magic, 4))
     {
-	st_fail("WAVE header not found");
+	st_fail_errno(ft,ST_EHDR,"WAVE header not found");
 	return ST_EOF;
     }
 
@@ -479,7 +494,7 @@
     
     if (wFmtSize < 16)
     {
-	st_fail("WAVE file fmt chunk is too short");
+	st_fail_errno(ft,ST_EHDR,"WAVE file fmt chunk is too short");
 	return ST_EOF;
     }
 
@@ -494,7 +509,7 @@
     switch (wav->formatTag)
     {
     case WAVE_FORMAT_UNKNOWN:
-	st_fail("WAVE file is in unsupported Microsoft Official Unknown format.");
+	st_fail_errno(ft,ST_EHDR,"WAVE file is in unsupported Microsoft Official Unknown format.");
 	return ST_EOF;
 	
     case WAVE_FORMAT_PCM:
@@ -525,7 +540,7 @@
 	break;
 
     case WAVE_FORMAT_IEEE_FLOAT:
-	st_fail("Sorry, this WAV file is in IEEE Float format.");
+	st_fail_errno(ft,ST_EHDR,"Sorry, this WAV file is in IEEE Float format.");
 	return ST_EOF;
 	
     case WAVE_FORMAT_ALAW:
@@ -555,16 +570,16 @@
 	break;
 	
     case WAVE_FORMAT_OKI_ADPCM:
-	st_fail("Sorry, this WAV file is in OKI ADPCM format.");
+	st_fail_errno(ft,ST_EHDR,"Sorry, this WAV file is in OKI ADPCM format.");
 	return ST_EOF;
     case WAVE_FORMAT_DIGISTD:
-	st_fail("Sorry, this WAV file is in Digistd format.");
+	st_fail_errno(ft,ST_EHDR,"Sorry, this WAV file is in Digistd format.");
 	return ST_EOF;
     case WAVE_FORMAT_DIGIFIX:
-	st_fail("Sorry, this WAV file is in Digifix format.");
+	st_fail_errno(ft,ST_EHDR,"Sorry, this WAV file is in Digifix format.");
 	return ST_EOF;
     case WAVE_FORMAT_DOLBY_AC2:
-	st_fail("Sorry, this WAV file is in Dolby AC2 format.");
+	st_fail_errno(ft,ST_EHDR,"Sorry, this WAV file is in Dolby AC2 format.");
 	return ST_EOF;
     case WAVE_FORMAT_GSM610:
 #ifdef HAVE_LIBGSM
@@ -574,34 +589,34 @@
 	    st_warn("User options overriding encoding read in .wav header");
 	break;
 #else
-	st_fail("Sorry, this WAV file is in GSM6.10 format and no GSM support present, recompile sox with gsm library");
+	st_fail_errno(ft,ST_EOF,"Sorry, this WAV file is in GSM6.10 format and no GSM support present, recompile sox with gsm library");
 	return ST_EOF;
 #endif
     case WAVE_FORMAT_ROCKWELL_ADPCM:
-	st_fail("Sorry, this WAV file is in Rockwell ADPCM format.");
+	st_fail_errno(ft,ST_EOF,"Sorry, this WAV file is in Rockwell ADPCM format.");
 	return ST_EOF;
     case WAVE_FORMAT_ROCKWELL_DIGITALK:
-	st_fail("Sorry, this WAV file is in Rockwell DIGITALK format.");
+	st_fail_errno(ft,ST_EOF,"Sorry, this WAV file is in Rockwell DIGITALK format.");
 	return ST_EOF;
     case WAVE_FORMAT_G721_ADPCM:
-	st_fail("Sorry, this WAV file is in G.721 ADPCM format.");
+	st_fail_errno(ft,ST_EOF,"Sorry, this WAV file is in G.721 ADPCM format.");
 	return ST_EOF;
     case WAVE_FORMAT_G728_CELP:
-	st_fail("Sorry, this WAV file is in G.728 CELP format.");
+	st_fail_errno(ft,ST_EOF,"Sorry, this WAV file is in G.728 CELP format.");
 	return ST_EOF;
     case WAVE_FORMAT_MPEG:
-	st_fail("Sorry, this WAV file is in MPEG format.");
+	st_fail_errno(ft,ST_EOF,"Sorry, this WAV file is in MPEG format.");
 	return ST_EOF;
     case WAVE_FORMAT_MPEGLAYER3:
-	st_fail("Sorry, this WAV file is in MPEG Layer 3 format.");
+	st_fail_errno(ft,ST_EOF,"Sorry, this WAV file is in MPEG Layer 3 format.");
 	return ST_EOF;
     case WAVE_FORMAT_G726_ADPCM:
-	st_fail("Sorry, this WAV file is in G.726 ADPCM format.");
+	st_fail_errno(ft,ST_EOF,"Sorry, this WAV file is in G.726 ADPCM format.");
 	return ST_EOF;
     case WAVE_FORMAT_G722_ADPCM:
-	st_fail("Sorry, this WAV file is in G.722 ADPCM format.");
+	st_fail_errno(ft,ST_EOF,"Sorry, this WAV file is in G.722 ADPCM format.");
 	return ST_EOF;
-    default:	st_fail("WAV file has unknown format type of %x",wav->formatTag);
+    default:	st_fail_errno(ft,ST_EOF,"WAV file has unknown format type of %x",wav->formatTag);
 		return ST_EOF;
     }
 
@@ -633,7 +648,7 @@
 
     if (wExtSize > len)
     {
-	st_fail("wave header error: wExtSize inconsistent with wFmtLen");
+	st_fail_errno(ft,ST_EOF,"wave header error: wExtSize inconsistent with wFmtLen");
 	return ST_EOF;
     }
 
@@ -643,7 +658,7 @@
     case WAVE_FORMAT_ADPCM:
 	if (wExtSize < 4)
 	{
-	    st_fail("format[%s]: expects wExtSize >= %d",
+	    st_fail_errno(ft,ST_EOF,"format[%s]: expects wExtSize >= %d",
 			wav_format_str(wav->formatTag), 4);
 	    return ST_EOF;
 	}
@@ -650,7 +665,7 @@
 
 	if (wBitsPerSample != 4)
 	{
-	    st_fail("Can only handle 4-bit MS ADPCM in wav files");
+	    st_fail_errno(ft,ST_EOF,"Can only handle 4-bit MS ADPCM in wav files");
 	    return ST_EOF;
 	}
 
@@ -658,7 +673,7 @@
 	bytesPerBlock = AdpcmBytesPerBlock(ft->info.channels, wav->samplesPerBlock);
 	if (bytesPerBlock > wav->blockAlign)
 	{
-	    st_fail("format[%s]: samplesPerBlock(%d) incompatible with blockAlign(%d)",
+	    st_fail_errno(ft,ST_EOF,"format[%s]: samplesPerBlock(%d) incompatible with blockAlign(%d)",
 		wav_format_str(wav->formatTag), wav->samplesPerBlock, wav->blockAlign);
 	    return ST_EOF;
 	}
@@ -665,13 +680,13 @@
 
 	st_readw(ft, &(wav->nCoefs));
 	if (wav->nCoefs < 7 || wav->nCoefs > 0x100) {
-	    st_fail("ADPCM file nCoefs (%.4hx) makes no sense\n", wav->nCoefs);
+	    st_fail_errno(ft,ST_EOF,"ADPCM file nCoefs (%.4hx) makes no sense\n", wav->nCoefs);
 	    return ST_EOF;
 	}
 	wav->packet = (unsigned char *)malloc(wav->blockAlign);
 	if (!wav->packet)
 	{
-	    st_fail("Unable to alloc resources");
+	    st_fail_errno(ft,ST_EOF,"Unable to alloc resources");
 	    return ST_EOF;
 	}
 
@@ -679,7 +694,7 @@
 
 	if (wExtSize < 4 + 4*wav->nCoefs)
 	{
-	    st_fail("wave header error: wExtSize(%d) too small for nCoefs(%d)", wExtSize, wav->nCoefs);
+	    st_fail_errno(ft,ST_EOF,"wave header error: wExtSize(%d) too small for nCoefs(%d)", wExtSize, wav->nCoefs);
 	    return ST_EOF;
 	}
 
@@ -686,7 +701,7 @@
 	wav->samples = (short *)malloc(wChannels*wav->samplesPerBlock*sizeof(short));
 	if (!wav->samples)
 	{
-	    st_fail("Unable to alloc resources");
+	    st_fail_errno(ft,ST_EOF,"Unable to alloc resources");
 	    return ST_EOF;
 	}
 
@@ -694,7 +709,7 @@
 	wav->iCoefs = (short *)malloc(wav->nCoefs * 2 * sizeof(short));
 	if (!wav->iCoefs)
 	{
-	    st_fail("Unable to alloc resources");
+	    st_fail_errno(ft,ST_EOF,"Unable to alloc resources");
 	    return ST_EOF;
 	}
 	{
@@ -714,7 +729,7 @@
     case WAVE_FORMAT_IMA_ADPCM:
 	if (wExtSize < 2)
 	{
-	    st_fail("format[%s]: expects wExtSize >= %d",
+	    st_fail_errno(ft,ST_EOF,"format[%s]: expects wExtSize >= %d",
 		    wav_format_str(wav->formatTag), 2);
 	    return ST_EOF;
 	}
@@ -721,7 +736,7 @@
 
 	if (wBitsPerSample != 4)
 	{
-	    st_fail("Can only handle 4-bit IMA ADPCM in wav files");
+	    st_fail_errno(ft,ST_EOF,"Can only handle 4-bit IMA ADPCM in wav files");
 	    return ST_EOF;
 	}
 
@@ -729,7 +744,7 @@
 	bytesPerBlock = ImaBytesPerBlock(ft->info.channels, wav->samplesPerBlock);
 	if (bytesPerBlock > wav->blockAlign || wav->samplesPerBlock%8 != 1)
 	{
-	    st_fail("format[%s]: samplesPerBlock(%d) incompatible with blockAlign(%d)",
+	    st_fail_errno(ft,ST_EOF,"format[%s]: samplesPerBlock(%d) incompatible with blockAlign(%d)",
 		wav_format_str(wav->formatTag), wav->samplesPerBlock, wav->blockAlign);
 	    return ST_EOF;
 	}
@@ -737,7 +752,7 @@
 	wav->packet = (unsigned char *)malloc(wav->blockAlign);
 	if (!wav->packet)
 	{
-	    st_fail("Unable to alloc resources");
+	    st_fail_errno(ft,ST_EOF,"Unable to alloc resources");
 	    return ST_EOF;
 	}
 	len -= 2;
@@ -745,7 +760,7 @@
 	wav->samples = (short *)malloc(wChannels*wav->samplesPerBlock*sizeof(short));
 	if (!wav->samples)
 	{
-	    st_fail("Unable to alloc resources");
+	    st_fail_errno(ft,ST_EOF,"Unable to alloc resources");
 	    return ST_EOF;
 	}
 
@@ -757,7 +772,7 @@
     case WAVE_FORMAT_GSM610:
 	if (wExtSize < 2)
 	{
-	    st_fail("format[%s]: expects wExtSize >= %d",
+	    st_fail_errno(ft,ST_EOF,"format[%s]: expects wExtSize >= %d",
 		    wav_format_str(wav->formatTag), 2);
 	    return ST_EOF;
 	}
@@ -765,13 +780,13 @@
 	bytesPerBlock = 65;
 	if (wav->blockAlign != 65)
 	{
-	    st_fail("format[%s]: expects blockAlign(%d) = %d",
+	    st_fail_errno(ft,ST_EOF,"format[%s]: expects blockAlign(%d) = %d",
 		    wav_format_str(wav->formatTag), wav->blockAlign, 65);
 	    return ST_EOF;
 	}
 	if (wav->samplesPerBlock != 320)
 	{
-	    st_fail("format[%s]: expects samplesPerBlock(%d) = %d",
+	    st_fail_errno(ft,ST_EOF,"format[%s]: expects samplesPerBlock(%d) = %d",
 		    wav_format_str(wav->formatTag), wav->samplesPerBlock, 320);
 	    return ST_EOF;
 	}
@@ -823,12 +838,12 @@
 	break;
 	
     default:
-	st_fail("Sorry, don't understand .wav size");
+	st_fail_errno(ft,ST_EOF,"Sorry, don't understand .wav size");
 	return ST_EOF;
     }
 
     /* Skip anything left over from fmt chunk */
-    fSkip(ft->fp, len);
+    st_seek(ft, len, SEEK_CUR);
 
     /* for non-PCM formats, there's a 'fact' chunk before
      * the upcoming 'data' chunk */
@@ -837,6 +852,9 @@
     wDataLength = len = findChunk(ft, "data");
     /* findChunk() only returns if chunk was found */
 
+	/* Data starts here */
+	wav->dataStart = ftell(ft->fp);
+
     switch (wav->formatTag)
     {
 
@@ -845,6 +863,7 @@
 	    AdpcmSamplesIn(wDataLength, ft->info.channels, wav->blockAlign, wav->samplesPerBlock);
 	/*st_report("datalen %d, numSamples %d",wDataLength, wav->numSamples);*/
 	wav->blockSamplesRemaining = 0;	       /* Samples left in buffer */
+	ft->length = wav->numSamples*ft->info.channels;
 	break;
 
     case WAVE_FORMAT_IMA_ADPCM:
@@ -855,6 +874,7 @@
 	/*st_report("datalen %d, numSamples %d",wDataLength, wav->numSamples);*/
 	wav->blockSamplesRemaining = 0;	       /* Samples left in buffer */
 	initImaTable();
+	ft->length = wav->numSamples*ft->info.channels;
 	break;
 
 #ifdef HAVE_LIBGSM
@@ -861,11 +881,13 @@
     case WAVE_FORMAT_GSM610:
 	wav->numSamples = (((wDataLength / wav->blockAlign) * wav->samplesPerBlock) * ft->info.channels);
 	wavgsminit(ft);
+	ft->length = wav->numSamples;
 	break;
 #endif
 
     default:
 	wav->numSamples = wDataLength/ft->info.size;	/* total samples */
+	ft->length = wav->numSamples;
 
     }
 
@@ -898,6 +920,60 @@
     default:
 	break;
     }
+/* Horrible way to find Cool Edit marker points. Taken from Quake source*/
+	ft->loops[0].start = -1;
+	if(ft->seekable){
+    /* Skip over data */
+/*Got this from the quake source.  I think it 32bit aligns the chunks 
+ * doubt any machine writing Cool Edit Chunks writes them at an odd 
+ * offset */
+	len = (len + 1) & ~1;
+    st_seek(ft, len, SEEK_CUR);
+    if( findChunk(ft, "LIST") != ST_EOF){
+	ft->comment = (char*)malloc(256);
+	while(!feof(ft->fp)){
+		st_reads(ft,magic,4);
+		if(strncmp(magic,"INFO",4) == 0){
+			/*Skip*/
+		} else if(strncmp(magic,"ICRD",4) == 0){
+			st_readdw(ft,&len); 
+			len = (len + 1) & ~1;
+			st_reads(ft,text,len);
+			strcat(ft->comment,text);
+			strcat(ft->comment,"\n");
+		} else if(strncmp(magic,"ISFT",4) == 0){
+			st_readdw(ft,&len); 
+			len = (len + 1) & ~1;
+			st_reads(ft,text,len);
+			strcat(ft->comment,text);
+			strcat(ft->comment,"\n");
+		} else if(strncmp(magic,"cue ",4) == 0){
+			st_readdw(ft,&len);
+			len = (len + 1) & ~1;
+			st_seek(ft,len-4,SEEK_CUR);
+			st_readdw(ft,(ULONG*)&ft->loops[0].start); 
+		} else if(strncmp(magic,"note",4) == 0){
+			/*Skip*/
+			st_readdw(ft,&len);
+			len = (len + 1) & ~1;
+			st_seek(ft,len-4,SEEK_CUR);
+		} else if(strncmp(magic,"adtl",4) == 0){
+			/*Skip*/
+		} else if(strncmp(magic,"ltxt",4) == 0){
+			st_seek(ft,4,SEEK_CUR);
+			st_readdw(ft,(ULONG*)&ft->loops[0].length); 
+			ft->loops[0].length = ft->loops[0].length - ft->loops[0].start;
+		} else if(strncmp(magic,"labl",4) == 0){
+			/*Skip*/
+			st_readdw(ft,&len);
+			len = (len + 1) & ~1;
+			st_seek(ft,len-4,SEEK_CUR);
+		}
+	}
+	}
+	clearerr(ft->fp);
+	st_seek(ft,wav->dataStart,SEEK_SET);
+	}	
     return ST_SUCCESS;
 }
 
@@ -915,6 +991,8 @@
 {
 	wav_t	wav = (wav_t) ft->priv;
 	LONG	done;
+
+	ft->st_errno = ST_SUCCESS;
 	
 	/* If file is in ADPCM encoding then read in multiple blocks else */
 	/* read as much as possible and return quickly. */
@@ -1009,6 +1087,8 @@
     wav_t	wav = (wav_t) ft->priv;
     int		rc = ST_SUCCESS;
 
+	ft->st_errno = ST_SUCCESS;
+
     if (wav->packet) free(wav->packet);
     if (wav->samples) free(wav->samples);
     if (wav->iCoefs) free(wav->iCoefs);
@@ -1036,6 +1116,8 @@
 	wav_t	wav = (wav_t) ft->priv;
 	int	rc;
 
+	ft->st_errno = ST_SUCCESS;
+
 	if (ST_IS_BIGENDIAN) ft->swap = ft->swap ? 0 : 1;
 
 	wav->numSamples = 0;
@@ -1063,7 +1145,7 @@
 	    wav->samples = (short *)malloc(sbsize*sizeof(short));
 	    if (!wav->packet || !wav->samples)
 	    {
-		st_fail("Unable to alloc resources");
+		st_fail_errno(ft,ST_EOF,"Unable to alloc resources");
 		return ST_EOF;
 	    }
 	    wav->sampleTop = wav->samples + sbsize;
@@ -1260,7 +1342,7 @@
 		case ST_ENCODING_IMA_ADPCM:
 			if (wChannels>16)
 			{
-			    st_fail("Channels(%d) must be <= 16\n",wChannels);
+			    st_fail_errno(ft,ST_EOF,"Channels(%d) must be <= 16\n",wChannels);
 			    return ST_EOF;
 			}
 			wFormatTag = WAVE_FORMAT_IMA_ADPCM;
@@ -1272,7 +1354,7 @@
 		case ST_ENCODING_ADPCM:
 			if (wChannels>16)
 			{
-			    st_fail("Channels(%d) must be <= 16\n",wChannels);
+			    st_fail_errno(ft,ST_EOF,"Channels(%d) must be <= 16\n",wChannels);
 			    return ST_EOF;
 			}
 			wFormatTag = WAVE_FORMAT_ADPCM;
@@ -1285,7 +1367,7 @@
 #ifdef HAVE_LIBGSM
 		    if (wChannels!=1)
 		    {
-			st_fail("Channels(%d) must be == 1\n",wChannels);
+			st_fail_errno(ft,ST_EOF,"Channels(%d) must be == 1\n",wChannels);
 			return ST_EOF;
 		    }
 		    wFormatTag = WAVE_FORMAT_GSM610;
@@ -1295,7 +1377,7 @@
 		    wExtSize=2;        /* length of format extension */
 		    wSamplesPerBlock = 320;
 #else
-		    st_fail("sorry, no GSM6.10 support, recompile sox with gsm library");
+		    st_fail_errno(ft,ST_EOF,"sorry, no GSM6.10 support, recompile sox with gsm library");
 		    return ST_EOF;
 #endif
 		    break;
@@ -1422,6 +1504,8 @@
 	wav_t	wav = (wav_t) ft->priv;
 	LONG	save_len = len;
 
+	ft->st_errno = ST_SUCCESS;
+
 	switch (wav->formatTag)
 	{
 	case WAVE_FORMAT_IMA_ADPCM:
@@ -1459,14 +1543,16 @@
 ft_t ft;
 {
 	wav_t	wav = (wav_t) ft->priv;
-	int	rc = ST_SUCCESS;
 
+	ft->st_errno = ST_SUCCESS;
+
+
 	/* Call this to flush out any remaining data. */
 	switch (wav->formatTag)
 	{
 	case WAVE_FORMAT_IMA_ADPCM:
 	case WAVE_FORMAT_ADPCM:
-	    rc = xxxAdpcmWriteBlock(ft);
+	    xxxAdpcmWriteBlock(ft);
 	    break;
 #ifdef HAVE_LIBGSM
 	case WAVE_FORMAT_GSM610:
@@ -1474,7 +1560,7 @@
 	    break;
 #endif
 	default:
-	    rc = st_rawstopwrite(ft);
+	    st_rawstopwrite(ft);
 	}
 	if (wav->packet) free(wav->packet);
  	if (wav->samples) free(wav->samples);
@@ -1481,8 +1567,8 @@
  	if (wav->iCoefs) free(wav->iCoefs);
 
 	/* Now that we've free()'d memory, return with errors if needed */
-	if (rc)
-	    return rc;
+	if (ft->st_errno)
+	    return ST_EOF;
 
 	/* All samples are already written out. */
 	/* If file header needs fixing up, for example it needs the */
@@ -1492,7 +1578,7 @@
 
 	if (fseek(ft->fp, 0L, SEEK_SET) != 0)
 	{
-		st_fail("Sorry, can't rewind output file to rewrite .wav header.");
+		st_fail_errno(ft,ST_EOF,"Sorry, can't rewind output file to rewrite .wav header.");
 		return ST_EOF;
 	}
 	wavwritehdr(ft, 1);
@@ -1551,4 +1637,29 @@
 		default:
 			return "Unknown";
 	}
+}
+
+int st_wavseek(ft,offset) 
+ft_t ft;
+LONG offset;
+{
+	wav_t	wav = (wav_t) ft->priv;
+
+	switch (wav->formatTag)
+	{
+	case WAVE_FORMAT_IMA_ADPCM:
+	case WAVE_FORMAT_ADPCM:
+#ifdef HAVE_LIBGSM
+	case WAVE_FORMAT_GSM610:
+#endif
+		st_fail_errno(ft,ST_ENOTSUP,"Only PCM Supported");
+	    break;
+	default:
+		ft->st_errno = st_seek(ft,offset*ft->info.size + wav->dataStart, SEEK_SET);
+	}
+
+	if( ft->st_errno == ST_SUCCESS )
+		wav->numSamples = ft->length - offset;
+
+	return(ft->st_errno);
 }
--- a/src/wve.c
+++ b/src/wve.c
@@ -13,19 +13,30 @@
 #define PSION_INV_VERSION   ((short)4111)
 #define PSION_HDRSIZE	32
 
-struct wvepriv
+typedef struct wvepriv
     {
     ULONG length;
     short padding;
     short repeats;
-    };
+/* For seeking */
+	LONG dataStart;
+    } *wve_t;
 
 static void wvewriteheader(ft_t ft);
 
+int st_wveseek(ft,offset) 
+ft_t ft;
+LONG offset;
+{
+	wve_t wve = (wve_t ) ft->priv;
+
+	return st_seek(ft,offset*ft->info.size + wve->dataStart,SEEK_SET);
+}
+
 int st_wvestartread(ft) 
 ft_t ft;
 {
-	struct wvepriv *p = (struct wvepriv *) ft->priv;
+	wve_t p = (wve_t ) ft->priv;
 	char magic[16];
 	short version;
 	int rc;
@@ -52,7 +63,7 @@
 	}
 	else
 	{
-		st_fail("Psion header doesn't start with magic word\nTry the '.al' file type with '-t al -r 8000 filename'");
+		st_fail_errno(ft,ST_EHDR,"Psion header doesn't start with magic word\nTry the '.al' file type with '-t al -r 8000 filename'");
 		return (ST_EOF);
 	}
 
@@ -74,7 +85,7 @@
 	}
 	else
 	{
-	    st_fail("Wrong version in Psion header");
+	    st_fail_errno(ft,ST_EHDR,"Wrong version in Psion header");
 	    return(ST_EOF);
 	}
 
@@ -94,6 +105,10 @@
 	ft->info.rate = 8000;
 
 	ft->info.channels = 1;
+
+	p->dataStart = ftell(ft->fp);
+	ft->length = p->length/ft->info.size;
+
 	return (ST_SUCCESS);
 }
 
@@ -109,7 +124,7 @@
 int st_wvestartwrite(ft) 
 ft_t ft;
 {
-	struct wvepriv *p = (struct wvepriv *) ft->priv;
+	wve_t p = (wve_t ) ft->priv;
 	int rc;
 
 	/* Needed for rawwrite() */
@@ -148,7 +163,7 @@
 ft_t ft;
 LONG *buf, samp;
 {
-	struct wvepriv *p = (struct wvepriv *) ft->priv;
+	wve_t p = (wve_t ) ft->priv;
 	p->length += samp * ft->info.size;
 	return st_rawwrite(ft, buf, samp);
 }
@@ -164,7 +179,7 @@
 
 	if (fseek(ft->fp, 0L, 0) != 0)
 	{
-		st_fail("Can't rewind output file to rewrite Psion header.");
+		st_fail_errno(ft,errno,"Can't rewind output file to rewrite Psion header.");
 		return(ST_EOF);
 	}
 	wvewriteheader(ft);
@@ -180,7 +195,7 @@
     char magic[16];
     short version;
     short zero;
-    struct wvepriv *p = (struct wvepriv *) ft->priv;
+    wve_t p = (wve_t ) ft->priv;
 
     strcpy(magic,PSION_MAGIC);
     version=PSION_VERSION;