From: Frank Goenninger
Subject: How to do config files?
Date: 
Message-ID: <u1xrgraf.fsf@goenninger.com>
Hi all!

Being in the design stage of an application the question
of how to implement config files for parameters of that
application came up for me. 

The obvious alternatives are to have the sort of 
"parameter = value" approach with several variants of
how to actually do the syntax and parameter grouping, i.e.
the .ini file approach, or the "emacs approach" as I call
it (to be able to speak to others in my community) with a
file having real code fragments in it.

Questions to this are:

1. Is there a most used way in Lisp envs?
2. Are there existing utilities around this? Where?

The pros and cons all go around flexibility and security.
The .ini file approach is the hard coded way of solving it.
Personally I don't like this. The emacs approach of
auto-loading a file with expression to be evaluated 
opens up a significant security leak. Any comments?

Thanks.

  Frank

From: Wade Humeniuk
Subject: Re: How to do config files?
Date: 
Message-ID: <9oqkcq$et0$1@news3.cadvision.com>
I use a file I have written a defstruct structure to store the configuration
parameters.  Use read/write to read and write the file.  Very simple, very
easy.  You can use defstruct to specify default values for slots and when
you add additional functionality you use defaulted slot values to initialize
new parameter values that old configuration files do not specify.  Here a
simple example.  The benefit is also you edit it by hand.

(defstruct (runner (:conc-name runner-))
  (name "Default")
  (distance 0)
  (shoes nil)
  (retired-shoes nil)
  (shoe-integer-id-counter 0)
  (plist nil))

(defstruct (running-shoe (:conc-name shoe-))
  (integer-id 0)
  model
  manufacturer
  start-date
  (distance 0)
  comments
  plist)

The contents of the "config" file:

#S(RUNNER
   NAME "Arline"
   DISTANCE 3505310
   SHOES (#S(RUNNING-SHOE
      INTEGER-ID 6
      MODEL "NikeAirMaxTriax"
      MANUFACTURER "Nike"
      START-DATE "June 1, 2001"
      DISTANCE 425100
      COMMENTS "Neutral shoe.  Used a few years ago."
      PLIST NIL)
   #S(RUNNING-SHOE
      INTEGER-ID 5
      MODEL "NB 829 March 01"
      MANUFACTURER ""
      START-DATE ""
      DISTANCE 358200
      COMMENTS ""
      PLIST NIL))
   RETIRED-SHOES NIL
   SHOE-INTEGER-ID-COUNTER 7
   PLIST (:MILESTONES NIL :PREFERRED-DISPLAY-UNITS :KILOMETERS))

Wade
From: ···@itasoftware.com
Subject: Re: How to do config files?
Date: 
Message-ID: <r8svtaog.fsf@itasoftware.com>
················@goenninger.com ("Frank Goenninger") writes:

> Hi all!
> 
> Being in the design stage of an application the question
> of how to implement config files for parameters of that
> application came up for me. 
> 
> The obvious alternatives are to have the sort of 
> "parameter = value" approach with several variants of
> how to actually do the syntax and parameter grouping, i.e.
> the .ini file approach, or the "emacs approach" as I call
> it (to be able to speak to others in my community) with a
> file having real code fragments in it.
> 
> Questions to this are:
> 
> 1. Is there a most used way in Lisp envs?
> 2. Are there existing utilities around this? Where?
> 
> The pros and cons all go around flexibility and security.
> The .ini file approach is the hard coded way of solving it.
> Personally I don't like this. The emacs approach of
> auto-loading a file with expression to be evaluated 
> opens up a significant security leak. Any comments?

It also opens up a significant opportunity for quick patches that
don't involve recompiles.  This has been *very* useful to me on many
occasions.  If the user protects the file, the security is not a
problem.


The `ini' file approach is inferior in many ways.  It provides no easy
way to distinguish between strings and literals (is that the number 42
or the string "42").  I've never seen a rigorous explanation of
escaping (foo=bar=baz  does this assign "BAR=BAZ"  to "FOO" or "BAZ"
ot "FOO=BAR"?  What if I want the other?  Can I embed newlines?  Are
spaces optional or required?  How do I escape a quote?)
From: Tim Bradshaw
Subject: Re: How to do config files?
Date: 
Message-ID: <ey3d74euy71.fsf@cley.com>
* Frank Goenninger wrote:
> The obvious alternatives are to have the sort of 
> "parameter = value" approach with several variants of
> how to actually do the syntax and parameter grouping, i.e.
> the .ini file approach, or the "emacs approach" as I call
> it (to be able to speak to others in my community) with a
> file having real code fragments in it.

I use a mixed approach: use s-expressions for the syntax so you don't
have to low-level parse everything, but then deal with the semantics
yourself.  It's fairly easy to make READ be reasonably secure (not,
probably, bombproof, merely hundreds of times more secure than IIS or
something).

If you want to load patches I tend to put them in FASL files and then
have then init file able to load them, even though it can't evaluate
(in the sense of EVAL) things itself.  This gives you the chance to do
something like digitally sign the patches or something, thus being
fairly sure that you're loading what you think.

You also get to claim that the syntax is equivalent to XML, and if
someone complains, you can write a little hack to emit an XML
equivalent, and then use some parser and start using XML for real
(this is a solution of last resort, of course).

All this presupposes that there are serious arguments for not using
the LOAD approach, which may well be very adequate.

--tim
From: Dr. Edmund Weitz
Subject: Re: How to do config files?
Date: 
Message-ID: <m3eloul1z1.fsf@bird.agharta.de>
Tim Bradshaw <···@cley.com> writes:

> It's fairly easy to make READ be reasonably secure (not,
> probably, bombproof, merely hundreds of times more secure than IIS or
> something).

I have recently thought about this and have no idea where to
start. Could you provide some quick hints about which direction to
choose? (Attention: newbie alert!)

Thanks in advance,
Edi.
From: Tim Bradshaw
Subject: Re: How to do config files?
Date: 
Message-ID: <ey3n13itg52.fsf@cley.com>
* Edmund Weitz wrote:

> I have recently thought about this and have no idea where to
> start. Could you provide some quick hints about which direction to
> choose? (Attention: newbie alert!)

Turn off *READ-EVAL*, make sure the readtable is standard.  Make sure
your implementation does actually signal errors if it sees bad things
(pump a few million random strings as well as some carefully chosen
nasty ones at it to convince yourself, obviously this is *not* a
proof, but it might help you feel better).

I *think* that at this point your remaining problems are symbols being
interned that you don't want and structural problems with the input.

You can't really fix the former, because there's no way of stopping
interning happening (portably).  You can alleviate the problem by
making sure you are in a suitable package when reading, and `cleaning'
that package after use.  However without knowing the complete package
state of the system before and after the call you can't be really sure
it has not interned something.  You *can* check that all symbols in
whatever you get back are `good' though.

Structural problems: once read returns *something* you want to check
it is what you want.  So you need to write a little parser to check
that things are OK.  You can easily do a recursive-descent thing using
CLOS.

Before you do this you may want to check basic sanity - be sure that
there aren't any unexpected types in there (maybe you only expect
conses, a known set of symbols, numbers, strings?) which you can do
just by walking over the form.  The big thing to check here is
circularity - you need an occurs check to make sure you aren't looking
at something you've already seen and (in the case of a cons or
something) complain if you are.

Compile all this stuff with safety all the way up and wrap an
error-catcher around it all! (I always love it when I compile critical
C programs and watch all the gcc -O9000 invocations, just to minimise
the error checking and maximise the chance of tickling a compiler bug).

I have probably missed something, and even if I have not I don't think
that READ is secure in the formal sense.  In practice I think you can
do pretty well.
From: Dr. Edmund Weitz
Subject: Re: How to do config files?
Date: 
Message-ID: <m3g09a2qtg.fsf@bird.agharta.de>
Thanks!! 

Tim Bradshaw <···@cley.com> writes:

> * Edmund Weitz wrote:
> 
> > I have recently thought about this and have no idea where to
> > start. Could you provide some quick hints about which direction to
> > choose? (Attention: newbie alert!)
> 
> Turn off *READ-EVAL*, make sure the readtable is standard.  Make sure
> your implementation does actually signal errors if it sees bad things
> (pump a few million random strings as well as some carefully chosen
> nasty ones at it to convince yourself, obviously this is *not* a
> proof, but it might help you feel better).
> 
> I *think* that at this point your remaining problems are symbols being
> interned that you don't want and structural problems with the input.
> 
> You can't really fix the former, because there's no way of stopping
> interning happening (portably).  You can alleviate the problem by
> making sure you are in a suitable package when reading, and `cleaning'
> that package after use.  However without knowing the complete package
> state of the system before and after the call you can't be really sure
> it has not interned something.  You *can* check that all symbols in
> whatever you get back are `good' though.
> 
> Structural problems: once read returns *something* you want to check
> it is what you want.  So you need to write a little parser to check
> that things are OK.  You can easily do a recursive-descent thing using
> CLOS.
> 
> Before you do this you may want to check basic sanity - be sure that
> there aren't any unexpected types in there (maybe you only expect
> conses, a known set of symbols, numbers, strings?) which you can do
> just by walking over the form.  The big thing to check here is
> circularity - you need an occurs check to make sure you aren't looking
> at something you've already seen and (in the case of a cons or
> something) complain if you are.
> 
> Compile all this stuff with safety all the way up and wrap an
> error-catcher around it all! (I always love it when I compile critical
> C programs and watch all the gcc -O9000 invocations, just to minimise
> the error checking and maximise the chance of tickling a compiler bug).
> 
> I have probably missed something, and even if I have not I don't think
> that READ is secure in the formal sense.  In practice I think you can
> do pretty well.
From: Paolo Amoroso
Subject: Re: How to do config files?
Date: 
Message-ID: <CyWyO78rtkqHNwi3ER1R7AWiFBve@4ax.com>
On 26 Sep 2001 11:12:25 +0100, Tim Bradshaw <···@cley.com> wrote:

> Turn off *READ-EVAL*, make sure the readtable is standard.  Make sure

Concerning the latter: do you mean using WITH-STANDARD-IO-SYNTAX?


Paolo
-- 
EncyCMUCLopedia * Extensive collection of CMU Common Lisp documentation
http://web.mclink.it/amoroso/ency/README
[http://cvs2.cons.org:8000/cmucl/doc/EncyCMUCLopedia/]
From: Tim Bradshaw
Subject: Re: How to do config files?
Date: 
Message-ID: <ey31yktt2b8.fsf@cley.com>
* Paolo Amoroso wrote:
> On 26 Sep 2001 11:12:25 +0100, Tim Bradshaw <···@cley.com> wrote:
>> Turn off *READ-EVAL*, make sure the readtable is standard.  Make sure

> Concerning the latter: do you mean using WITH-STANDARD-IO-SYNTAX?

Yes, at least that (you need to bind *READ-EVAL* inside the
WITH-STANDARD-IO-SYNTAX).

--tim
From: Erik Naggum
Subject: Re: How to do config files?
Date: 
Message-ID: <3210495003252941@naggum.net>
* Dr. Edmund Weitz
> I have recently thought about this and have no idea where to
> start. Could you provide some quick hints about which direction to
> choose? (Attention: newbie alert!)

  If you are newbie, I think it is instructive to read up on read and
  readtables and all this and see if you understand enough of what it does
  to implement your own (simple) reader, skipping some things on purpose.
  You may find that the full generality of the reader is harder to harness
  than writing an optimized little thing that knows about the things you
  want it to know about.

///
-- 
  Why did that stupid George W. Bush turn to Christian fundamentalism to
  fight Islamic fundamentalism?  Why use terms like "crusade", which only
  invokes fear of a repetition of that disgraceful period of Christianity
  with its _sustained_ terrorist attacks on Islam?  He is _such_ an idiot.
From: Janis Dzerins
Subject: Re: How to do config files?
Date: 
Message-ID: <87d74e48o8.fsf@asaka.latnet.lv>
················@goenninger.com ("Frank Goenninger") writes:

> Hi all!
> 
> Being in the design stage of an application the question
> of how to implement config files for parameters of that
> application came up for me. 
> 
> The obvious alternatives are to have the sort of 
> "parameter = value" approach with several variants of
> how to actually do the syntax and parameter grouping, i.e.
> the .ini file approach, or the "emacs approach" as I call
> it (to be able to speak to others in my community) with a
> file having real code fragments in it.
> 
> Questions to this are:
> 
> 1. Is there a most used way in Lisp envs?

Can't say about this.

> 2. Are there existing utilities around this? Where?

read/write.

> The pros and cons all go around flexibility and security.
> The .ini file approach is the hard coded way of solving it.

If all you need is to store values of some parameters, you can write
them like a plist. For example, if you have three parameters: foo,
bar, baz -- you get following list in your file:

(foo 1 bar 2 baz 3)

If you need to group them, you can put a group name as the first
symbol of the list, like:

(group-1 foo 1 bar 2 baz 3)
(group-2 foo 4.8
         bar 5/6
         baz "a string")

Note that you can easily write and read these to/from a file. Be
careful also about current package when reading (or use keywords for
parameter names). Don't forget to bind *read-eval* to nil (and check
out with-standard-io-syntax macro).

You could also use alists instead of plists. You could also not use
lists at all. Just use write and read.

-- 
Janis Dzerins

  If million people say a stupid thing it's still a stupid thing.