[Debburn-devel] Rewritten config parser

Eduard Bloch edi at gmx.de
Sat Sep 9 20:54:31 UTC 2006


#include <hallo.h>

As said on IRC, I have rewritten the config file parser of cdrkit to
make it more robust, more flexible and more user-friendly. You will
find the suggested change attaced, as files and as svn diff. Please
proofread and tell me if you find anythign suspicious, I hope that I
documented the code well enough.

Now it should accept all kinds of input which available before and
support more, like typical user mistakes: trailing spaces, spaces around
=, arbitrary number of whitespace instead of one single TAB, and, of
course, omiting the last values.

See attachement. I intend to commit it to the stable trunk RSN.

Eduard.

-- 
<Myon> TV ist Zeitverschwendung
* micsch muss auch nochmal seine TV-Karte einbauen
-------------- next part --------------
A non-text attachment was scrubbed...
Name: defaults.c
Type: text/x-csrc
Size: 7080 bytes
Desc: not available
Url : http://lists.alioth.debian.org/pipermail/debburn-devel/attachments/20060909/4ae31f31/defaults.c
-------------- next part --------------
A non-text attachment was scrubbed...
Name: defaults.h
Type: text/x-chdr
Size: 1423 bytes
Desc: not available
Url : http://lists.alioth.debian.org/pipermail/debburn-devel/attachments/20060909/4ae31f31/defaults.h
-------------- next part --------------
Index: cdrecord/defaults.c
===================================================================
--- cdrecord/defaults.c	(Revision 243)
+++ cdrecord/defaults.c	(Arbeitskopie)
@@ -1,24 +1,15 @@
-/*
- * This file has been modified for the cdrkit suite.
+/* 
+ * Copyright 2006 Eduard Bloch 
  *
- * The behaviour and appearence of the program code below can differ to a major
- * extent from the version distributed by the original author(s).
+ * This code emulates the interface of the original defaults.c file. However,
+ * it improves its behaviour and deals with corner cases: prepended and
+ * trailing spaces on variable and value, no requirement for using TABs
+ * anymore. No requirements to insert dummy values like -1 or "".
  *
- * For details, see Changelog file distributed with the cdrkit package. If you
- * received this file from another source then ask the distributing person for
- * a log of modifications.
- *
+ * FIXME, minor priority: implement alternative atoi function which returns
+ * custom values as "bad values" instead of 0
  */
-
-/* @(#)defaults.c	1.17 06/02/15 Copyright 1998-2005 J. Schilling */
-#ifndef lint
-static	char sccsid[] =
-	"@(#)defaults.c	1.17 06/02/15 Copyright 1998-2005 J. Schilling";
-#endif
 /*
- *	Copyright (c) 1998-2005 J. Schilling
- */
-/*
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2
  * as published by the Free Software Foundation.
@@ -34,217 +25,195 @@
  */
 
 #include <mconfig.h>
-#include <stdxlib.h>
-#include <unixstd.h>
-#include <strdefs.h>
+#include <stdlib.h>
 #include <stdio.h>
-#include <standard.h>
-#include <deflts.h>
-#include <utypes.h>
-#include <schily.h>
-#include "cdrecord.h"	/* only for getnum() */
 #include "defaults.h"
+#include <ctype.h>
+#include <string.h>
 
-LOCAL	int	open_cdrdefaults __PR((void));
-EXPORT	void	cdr_defaults	__PR((char **devp, int *speedp, long *fsp, char **drvoptp));
-LOCAL	void	cdr_xdefaults	__PR((char **devp, int *speedp, long *fsp, char **drvoptp));
-LOCAL	char *	strsv		__PR((char *s));
+#define CFGPATH "/etc/default/wodim"
+/* The better way would be exporting the meta functions to getnum.h or so */
+extern int	getnum		(char *arg, long *valp);
 
-LOCAL int
-open_cdrdefaults()
-{
-	/*
-	 * WARNING you are only allowed to change this filename if you also
-	 * change the documentation and add a statement that makes clear
-	 * where the official location of the file is why you did choose a
-	 * nonstandard location and that the nonstandard location only refers
-	 * to inofficial cdrecord versions.
-	 *
-	 * I was forced to add this because some people change cdrecord without
-	 * rational reason and then publish the result. As those people
-	 * don't contribute work and don't give support, they are causing extra
-	 * work for me and this way slow down the cdrecord development.
-	 */
-	return (defltopen("/etc/default/wodim"));
-}
+/*
+ * Warning, uses static line buffer, not reentrant. NULL returned if the key isn't found.
+ */
+static char *get_value(FILE *srcfile, char *key) {
+   static char linebuf[256];
 
-EXPORT void
-cdr_defaults(devp, speedp, fsp, drvoptp)
-	char	**devp;
-	int	*speedp;
-	long	*fsp;
-	char	**drvoptp;
-{
-	char	*dev	= NULL;
-	int	speed	= 0;
-	long	fs	= 0L;
+   if(!srcfile)
+      return NULL;
 
-	if (devp != NULL)
-		dev = *devp;
-	if (speedp != NULL)
-		speed = *speedp;
-	if (fsp != NULL)
-		fs = *fsp;
+   rewind(srcfile);
+next_line:
+   while(fgets(linebuf, 256, srcfile)) {
+      int i;
+      int keybeg;
+      int s=0; /* state */
+      char *ret=NULL;
+      int lastchar=0;
 
-	if (!dev && devp != NULL) {
-		*devp = getenv("CDR_DEVICE");
+      for(i=0;i<256;) {
+         switch(s) {
+            case(0):
+               {
+                  if(isspace(linebuf[i]))
+                     i++;
+                  else if(linebuf[i]=='\0' || linebuf[i] == '#')
+                     goto next_line;
+                  else {
+                     s=1;
+                     keybeg=i;
+                  }
+               }
+               break;
+            case(1): /* compare the key */
+               {
+                  if(key[i-keybeg]=='\0') 
+                     /* end of key, next state decides what to do on this position */
+                     s=2;
+                  else {
+                     if(linebuf[i-keybeg]!=key[i-keybeg])
+                        goto next_line;
+                     else
+                        i++;
+                  }
+               }
+               break;
+            case(2): /* skip whitespace, stop on =, break on anything else */
+               {
+                  if(isspace(linebuf[i]))
+                     i++;
+                  else if(linebuf[i]=='=') {
+                     s=3;
+                     i++;
+                  }
+                  else
+                     goto next_line;
+               }
+               break;
+            case(3):
+               {
+                  if(isspace(linebuf[i]))
+                     i++;
+                  else { /* beginning of value found */
+                     lastchar=i;
+                     ret= & linebuf[i];
+                     s=4;
+                  }
+               }
+               break;
+            case(4):
+               {
+                  if(linebuf[i]) {
+                     if(!isspace(linebuf[i]))
+                        lastchar=i;
+                  }
+                  else { /* got string end, terminate after the last seen char */
+                     linebuf[lastchar+1]='\0';
+                     if(! *ret) // instead of empty string
+                        return NULL;
+                     return ret;
+                  }
+                  i++;
+               }
+               break;
+         }
+      }
+   }
+   return NULL;
+}
 
-		if (!*devp && open_cdrdefaults() == 0) {
-			dev = defltread("CDR_DEVICE=");
-			if (dev != NULL)
-				*devp = strsv(dev);
-		}
-	}
-	if (devp != NULL && *devp)
-		cdr_xdefaults(devp, &speed, &fs, drvoptp);
+void
+cdr_defaults(char **ppszDevice, int *piSpeed, long *plFifoSize, char *ppszDriverOptions) {
+   FILE *stream;
+   char *t; /* tmp */
+   int wc=0;
+   char loc[256], sSpeed[10], sFs[10], sOpts[80];
+   char *devcand=NULL;
 
-	if (speed < 0) {
-		char	*p = getenv("CDR_SPEED");
+   stream=fopen(CFGPATH, "r");
 
-		if (!p) {
-			if (open_cdrdefaults() == 0) {
-				p = defltread("CDR_SPEED=");
-			}
-		}
-		if (p) {
-			speed = atoi(p);
-			if (speed < 0 && speed != -1) {
-				comerrno(EX_BAD,
-					"Bad speed environment (%s).\n", p);
-			}
-		}
-	}
-	if (speed >= 0 && speedp != NULL)
-		*speedp = speed;
+   if(ppszDevice && *ppszDevice)
+      devcand=*ppszDevice;
+   else if(NULL!=(t=getenv("CDR_DEVICE")))
+      devcand=t;
+   else if(NULL!=(t=get_value(stream, "CDR_DEVICE")))
+      devcand=strdup(t); // needs to use it as a key later, same stat. memory
 
-	if (fs < 0L) {
-		char	*p = getenv("CDR_FIFOSIZE");
+   if(devcand && NULL != (t=get_value(stream,devcand))) {
+      /* extract them now, may be used later */
+      wc=sscanf(t, "%256s %10s %10s %80s", loc, sSpeed, sFs, sOpts);
+   }
 
-		if (!p) {
-			if (open_cdrdefaults() == 0) {
-				p = defltread("CDR_FIFOSIZE=");
-			}
-		}
-		if (p) {
-			if (getnum(p, &fs) != 1) {
-				comerrno(EX_BAD,
-					"Bad fifo size environment (%s).\n", p);
-			}
-		}
-	}
-	if (fs > 0L && fsp != NULL) {
-		char	*p = NULL;
-		long	maxfs;
+   if(ppszDevice) {
+      if(wc>0)
+         *ppszDevice = strdup(loc);
+      else if(devcand) // small mem. leak possible, does not matter, checks for that would require more code size than we loose
+         *ppszDevice=strdup(devcand);
+   }
+   if(piSpeed) { // sth. to write back
+      if(*piSpeed>0) { 
+         /* ok, already set by the user */
+      }
+      else if(NULL!=(t=getenv("CDR_SPEED"))) {
+         *piSpeed=atoi(t);
+         if(*piSpeed<-1) {
+            fprintf(stderr, "Bad CDR_SPEED environment (%s).\n", t);
+            exit(EXIT_FAILURE);
+         }
+      }
+      else if(wc>1) {
+         *piSpeed=atoi(sSpeed);
+         if(*piSpeed<-1) {
+            fprintf(stderr, "Bad speed (%s) in the config, drive description.\n", sSpeed);
+            exit(EXIT_FAILURE);
+         }
+      }
+      else if(NULL!=(t=get_value(stream, "CDR_SPEED"))) {
+         *piSpeed=atoi(t);
+         if(*piSpeed<-1) {
+            fprintf(stderr, "Bad default CDR_SPEED setting (%s).\n", t);
+            exit(EXIT_FAILURE);
+         }
+      }
+   }
+   if(plFifoSize) { // sth. to write back
+      if(*plFifoSize>0) { 
+         /* ok, already set by the user */
+      }
+      else if(NULL!=(t=getenv("CDR_FIFOSIZE"))) {
+         if(getnum(t, plFifoSize)!=1 || *plFifoSize<-1) {
+            fprintf(stderr, "Bad CDR_FIFOSIZE environment (%s).\n", t);
+            exit(EXIT_FAILURE);
+         }
+      }
+      else if(wc>2) {
+         if(getnum(sFs, plFifoSize)!=1 || *plFifoSize<-1) {
+            fprintf(stderr, "Bad fifo size (%s) in the config, device description.\n", sSpeed);
+            exit(EXIT_FAILURE);
+         }
+      }
+      else if(NULL!=(t=get_value(stream, "CDR_FIFOSIZE"))) {
+         if(getnum(t, plFifoSize)!=1 || *plFifoSize<-1) {
+            fprintf(stderr, "Bad speed default setting (%s).\n", t);
+            exit(EXIT_FAILURE);
+         }
+      }
+      /* undocumented option. Most likely to prevent killing Schily's underpowered
+       * machines (see docs) by allocating to much memory after doing a mistake
+       * in the config. */
+      if(NULL!=(t=get_value(stream, "CDR_MAXFIFOSIZE"))) {
+         long max;
+         if(getnum(t, &max)!=1 || *plFifoSize<-1) {
+            fprintf(stderr, "Bad CDR_MAXFIFOSIZE setting (%s).\n", t);
+            exit(EXIT_FAILURE);
+         }
+         if(*plFifoSize>max)
+            *plFifoSize=max;
+      }
+   }
+   if(ppszDriverOptions && !*ppszDriverOptions && wc>3 && strcmp(sOpts, "\"\""))
+      *ppszDriverOptions=strdup(sOpts);
 
-		if (open_cdrdefaults() == 0) {
-			p = defltread("CDR_MAXFIFOSIZE=");
-		}
-		if (p) {
-			if (getnum(p, &maxfs) != 1) {
-				comerrno(EX_BAD,
-					"Bad max fifo size default (%s).\n", p);
-			}
-			if (fs > maxfs)
-				fs = maxfs;
-		}
-		*fsp = fs;
-	}
-
-
-	defltclose();
 }
-
-/*
- * All args execpt "drvoptp" are granted to be non NULL pointers.
- */
-LOCAL void
-cdr_xdefaults(devp, speedp, fsp, drvoptp)
-	char	**devp;
-	int	*speedp;
-	long	*fsp;
-	char	**drvoptp;
-{
-	char	dname[256];
-	char	*p = *devp;
-	char	*x = ",:/@";
-
-	while (*x) {
-		if (strchr(p, *x))
-			return;
-		x++;
-	}
-	js_snprintf(dname, sizeof (dname), "%s=", p);
-	if (open_cdrdefaults() != 0)
-		return;
-
-	p = defltread(dname);
-	if (p != NULL) {
-		while (*p == '\t' || *p == ' ')
-			p++;
-		if ((x = strchr(p, '\t')) != NULL)
-			*x = '\0';
-		else if ((x = strchr(p, ' ')) != NULL)
-			*x = '\0';
-		*devp = strsv(p);
-		if (x) {
-			p = ++x;
-			while (*p == '\t' || *p == ' ')
-				p++;
-			if ((x = strchr(p, '\t')) != NULL)
-				*x = '\0';
-			else if ((x = strchr(p, ' ')) != NULL)
-				*x = '\0';
-			if (*speedp < 0)
-				*speedp = atoi(p);
-			if (*speedp < 0 && *speedp != -1) {
-				comerrno(EX_BAD,
-					"Bad speed in defaults (%s).\n", p);
-			}
-		}
-		if (x) {
-			p = ++x;
-			while (*p == '\t' || *p == ' ')
-				p++;
-			if ((x = strchr(p, '\t')) != NULL)
-				*x = '\0';
-			else if ((x = strchr(p, ' ')) != NULL)
-				*x = '\0';
-			if (*fsp < 0L) {
-				if (getnum(p, fsp) != 1) {
-					comerrno(EX_BAD,
-					"Bad fifo size in defaults (%s).\n",
-					p);
-				}
-			}
-		}
-		if (x) {
-			p = ++x;
-			while (*p == '\t' || *p == ' ')
-				p++;
-			if ((x = strchr(p, '\t')) != NULL)
-				*x = '\0';
-			else if ((x = strchr(p, ' ')) != NULL)
-				*x = '\0';
-			if (strcmp(p, "\"\"") != '\0') {
-				/*
-				 * Driver opts found.
-				 */
-				if (drvoptp && *drvoptp == NULL)
-					*drvoptp = strsv(p);
-			}
-		}
-	}
-}
-
-LOCAL char *
-strsv(s)
-	char	*s;
-{
-	char	*p;
-	int len = strlen(s);
-
-	p = malloc(len+1);
-	if (p)
-		strcpy(p, s);
-	return (p);
-}
Index: cdrecord/defaults.h
===================================================================
--- cdrecord/defaults.h	(Revision 243)
+++ cdrecord/defaults.h	(Arbeitskopie)
@@ -36,6 +36,6 @@
 /*
  * defaults.c
  */
-extern	void	cdr_defaults	__PR((char **devp, int *speedp, long *fsp, char **drvoptp));
+//extern	void	cdr_defaults	__PR((char **devp, int *speedp, long *fsp, char **drvoptp));
 
 #endif	/* _DEFAULTS_H */


More information about the Debburn-devel mailing list