Dr Andrew Scott G7VAV

My photo
 
May 2024
Mo Tu We Th Fr Sa Su
29 30 1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31 1 2
3 4 5 6 7 8 9


obstack.h
001: /* obstack.h - object stack macros
002:    Copyright (C) 1988-1994,1996-1999,2003,2004,2005,2009,2011
003:         Free Software Foundation, Inc.
004:    This file is part of the GNU C Library.
005: 
006:    The GNU C Library is free software; you can redistribute it and/or
007:    modify it under the terms of the GNU Lesser General Public
008:    License as published by the Free Software Foundation; either
009:    version 2.1 of the License, or (at your option) any later version.
010: 
011:    The GNU C Library is distributed in the hope that it will be useful,
012:    but WITHOUT ANY WARRANTY; without even the implied warranty of
013:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014:    Lesser General Public License for more details.
015: 
016:    You should have received a copy of the GNU Lesser General Public
017:    License along with the GNU C Library; if not, write to the Free
018:    Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
019:    Boston, MA 02110-1301, USA.  */
020: 
021: /* Summary:
022: 
023: All the apparent functions defined here are macros. The idea
024: is that you would use these pre-tested macros to solve a
025: very specific set of problems, and they would run fast.
026: Caution: no side-effects in arguments please!! They may be
027: evaluated MANY times!!
028: 
029: These macros operate a stack of objects.  Each object starts life
030: small, and may grow to maturity.  (Consider building a word syllable
031: by syllable.)  An object can move while it is growing.  Once it has
032: been "finished" it never changes address again.  So the "top of the
033: stack" is typically an immature growing object, while the rest of the
034: stack is of mature, fixed size and fixed address objects.
035: 
036: These routines grab large chunks of memory, using a function you
037: supply, called `obstack_chunk_alloc'.  On occasion, they free chunks,
038: by calling `obstack_chunk_free'.  You must define them and declare
039: them before using any obstack macros.
040: 
041: Each independent stack is represented by a `struct obstack'.
042: Each of the obstack macros expects a pointer to such a structure
043: as the first argument.
044: 
045: One motivation for this package is the problem of growing char strings
046: in symbol tables.  Unless you are "fascist pig with a read-only mind"
047: --Gosper's immortal quote from HAKMEM item 154, out of context--you
048: would not like to put any arbitrary upper limit on the length of your
049: symbols.
050: 
051: In practice this often means you will build many short symbols and a
052: few long symbols.  At the time you are reading a symbol you don't know
053: how long it is.  One traditional method is to read a symbol into a
054: buffer, realloc()ating the buffer every time you try to read a symbol
055: that is longer than the buffer.  This is beaut, but you still will
056: want to copy the symbol from the buffer to a more permanent
057: symbol-table entry say about half the time.
058: 
059: With obstacks, you can work differently.  Use one obstack for all symbol
060: names.  As you read a symbol, grow the name in the obstack gradually.
061: When the name is complete, finalize it.  Then, if the symbol exists already,
062: free the newly read name.
063: 
064: The way we do this is to take a large chunk, allocating memory from
065: low addresses.  When you want to build a symbol in the chunk you just
066: add chars above the current "high water mark" in the chunk.  When you
067: have finished adding chars, because you got to the end of the symbol,
068: you know how long the chars are, and you can create a new object.
069: Mostly the chars will not burst over the highest address of the chunk,
070: because you would typically expect a chunk to be (say) 100 times as
071: long as an average object.
072: 
073: In case that isn't clear, when we have enough chars to make up
074: the object, THEY ARE ALREADY CONTIGUOUS IN THE CHUNK (guaranteed)
075: so we just point to it where it lies.  No moving of chars is
076: needed and this is the second win: potentially long strings need
077: never be explicitly shuffled. Once an object is formed, it does not
078: change its address during its lifetime.
079: 
080: When the chars burst over a chunk boundary, we allocate a larger
081: chunk, and then copy the partly formed object from the end of the old
082: chunk to the beginning of the new larger chunk.  We then carry on
083: accreting characters to the end of the object as we normally would.
084: 
085: A special macro is provided to add a single char at a time to a
086: growing object.  This allows the use of register variables, which
087: break the ordinary 'growth' macro.
088: 
089: Summary:
090:         We allocate large chunks.
091:         We carve out one object at a time from the current chunk.
092:         Once carved, an object never moves.
093:         We are free to append data of any size to the currently
094:           growing object.
095:         Exactly one object is growing in an obstack at any one time.
096:         You can run one obstack per control block.
097:         You may have as many control blocks as you dare.
098:         Because of the way we do it, you can `unwind' an obstack
099:           back to a previous state. (You may remove objects much
100:           as you would with a stack.)
101: */
102: 
103: 
104: /* Don't do the contents of this file more than once.  */
105: 
106: #ifndef _OBSTACK_H
107: #define _OBSTACK_H 1
108: 
109: #ifdef __cplusplus
110: extern "C" {
111: #endif
112: 
113: /* We need the type of a pointer subtraction.  If __PTRDIFF_TYPE__ is
114:    defined, as with GNU C, use that; that way we don't pollute the
115:    namespace with <stddef.h>'s symbols.  Otherwise, include <stddef.h>
116:    and use ptrdiff_t.  */
117: 
118: #ifdef __PTRDIFF_TYPE__
119: # define PTR_INT_TYPE __PTRDIFF_TYPE__
120: #else
121: # include <stddef.h>
122: # define PTR_INT_TYPE ptrdiff_t
123: #endif
124: 
125: /* If B is the base of an object addressed by P, return the result of
126:    aligning P to the next multiple of A + 1.  B and P must be of type
127:    char *.  A + 1 must be a power of 2.  */
128: 
129: #define __BPTR_ALIGN(B, P, A) ((B) + (((P) - (B) + (A)) & ~(A)))
130: 
131: /* Similiar to _BPTR_ALIGN (B, P, A), except optimize the common case
132:    where pointers can be converted to integers, aligned as integers,
133:    and converted back again.  If PTR_INT_TYPE is narrower than a
134:    pointer (e.g., the AS/400), play it safe and compute the alignment
135:    relative to B.  Otherwise, use the faster strategy of computing the
136:    alignment relative to 0.  */
137: 
138: #define __PTR_ALIGN(B, P, A)                                                \
139:   __BPTR_ALIGN (sizeof (PTR_INT_TYPE) < sizeof (void *) ? (B) : (char *) 0, \
140:                 P, A)
141: 
142: #include <string.h>
143: 
144: struct _obstack_chunk           /* Lives at front of each chunk. */
145: {
146:   char  *limit;                 /* 1 past end of this chunk */
147:   struct _obstack_chunk *prev;  /* address of prior chunk or NULL */
148:   char  contents[4];            /* objects begin here */
149: };
150: 
151: struct obstack          /* control current object in current chunk */
152: {
153:   long  chunk_size;             /* preferred size to allocate chunks in */
154:   struct _obstack_chunk *chunk; /* address of current struct obstack_chunk */
155:   char  *object_base;           /* address of object we are building */
156:   char  *next_free;             /* where to add next char to current object */
157:   char  *chunk_limit;           /* address of char after current chunk */
158:   union
159:   {
160:     PTR_INT_TYPE tempint;
161:     void *tempptr;
162:   } temp;                       /* Temporary for some macros.  */
163:   int   alignment_mask;         /* Mask of alignment for each object. */
164:   /* These prototypes vary based on `use_extra_arg', and we use
165:      casts to the prototypeless function type in all assignments,
166:      but having prototypes here quiets -Wstrict-prototypes.  */
167:   struct _obstack_chunk *(*chunkfun) (void *, long);
168:   void (*freefun) (void *, struct _obstack_chunk *);
169:   void *extra_arg;              /* first arg for chunk alloc/dealloc funcs */
170:   unsigned use_extra_arg:1;     /* chunk alloc/dealloc funcs take extra arg */
171:   unsigned maybe_empty_object:1;/* There is a possibility that the current
172:                                    chunk contains a zero-length object.  This
173:                                    prevents freeing the chunk if we allocate
174:                                    a bigger chunk to replace it. */
175:   unsigned alloc_failed:1;      /* No longer used, as we now call the failed
176:                                    handler on error, but retained for binary
177:                                    compatibility.  */
178: };
179: 
180: /* Declare the external functions we use; they are in obstack.c.  */
181: 
182: extern void _obstack_newchunk (struct obstack *, int);
183: extern int _obstack_begin (struct obstack *, int, int,
184:                             void *(*) (long), void (*) (void *));
185: extern int _obstack_begin_1 (struct obstack *, int, int,
186:                              void *(*) (void *, long),
187:                              void (*) (void *, void *), void *);
188: extern int _obstack_memory_used (struct obstack *);
189: 
190: void obstack_free (struct obstack *__obstack, void *__block);
191: 
192: 
193: /* Error handler called when `obstack_chunk_alloc' failed to allocate
194:    more memory.  This can be set to a user defined function which
195:    should either abort gracefully or use longjump - but shouldn't
196:    return.  The default action is to print a message and abort.  */
197: extern void (*obstack_alloc_failed_handler) (void);
198: 
199: /* Exit value used when `print_and_abort' is used.  */
200: extern int obstack_exit_failure;
201: 
202: /* Pointer to beginning of object being allocated or to be allocated next.
203:    Note that this might not be the final address of the object
204:    because a new chunk might be needed to hold the final size.  */
205: 
206: #define obstack_base(h) ((void *) (h)->object_base)
207: 
208: /* Size for allocating ordinary chunks.  */
209: 
210: #define obstack_chunk_size(h) ((h)->chunk_size)
211: 
212: /* Pointer to next byte not yet allocated in current chunk.  */
213: 
214: #define obstack_next_free(h)    ((h)->next_free)
215: 
216: /* Mask specifying low bits that should be clear in address of an object.  */
217: 
218: #define obstack_alignment_mask(h) ((h)->alignment_mask)
219: 
220: /* To prevent prototype warnings provide complete argument list.  */
221: #define obstack_init(h)                                         \
222:   _obstack_begin ((h), 0, 0,                                    \
223:                   (void *(*) (long)) obstack_chunk_alloc,       \
224:                   (void (*) (void *)) obstack_chunk_free)
225: 
226: #define obstack_begin(h, size)                                  \
227:   _obstack_begin ((h), (size), 0,                               \
228:                   (void *(*) (long)) obstack_chunk_alloc,       \
229:                   (void (*) (void *)) obstack_chunk_free)
230: 
231: #define obstack_specify_allocation(h, size, alignment, chunkfun, freefun)  \
232:   _obstack_begin ((h), (size), (alignment),                                \
233:                   (void *(*) (long)) (chunkfun),                           \
234:                   (void (*) (void *)) (freefun))
235: 
236: #define obstack_specify_allocation_with_arg(h, size, alignment, chunkfun, freefun, arg) \
237:   _obstack_begin_1 ((h), (size), (alignment),                           \
238:                     (void *(*) (void *, long)) (chunkfun),              \
239:                     (void (*) (void *, void *)) (freefun), (arg))
240: 
241: #define obstack_chunkfun(h, newchunkfun) \
242:   ((h) -> chunkfun = (struct _obstack_chunk *(*)(void *, long)) (newchunkfun))
243: 
244: #define obstack_freefun(h, newfreefun) \
245:   ((h) -> freefun = (void (*)(void *, struct _obstack_chunk *)) (newfreefun))
246: 
247: #define obstack_1grow_fast(h,achar) (*((h)->next_free)++ = (achar))
248: 
249: #define obstack_blank_fast(h,n) ((h)->next_free += (n))
250: 
251: #define obstack_memory_used(h) _obstack_memory_used (h)
252: 
253: #if defined __GNUC__ && defined __STDC__ && __STDC__
254: /* NextStep 2.0 cc is really gcc 1.93 but it defines __GNUC__ = 2 and
255:    does not implement __extension__.  But that compiler doesn't define
256:    __GNUC_MINOR__.  */
257: # if __GNUC__ < 2 || (__NeXT__ && !__GNUC_MINOR__)
258: #  define __extension__
259: # endif
260: 
261: /* For GNU C, if not -traditional,
262:    we can define these macros to compute all args only once
263:    without using a global variable.
264:    Also, we can avoid using the `temp' slot, to make faster code.  */
265: 
266: # define obstack_object_size(OBSTACK)                                   \
267:   __extension__                                                         \
268:   ({ struct obstack const *__o = (OBSTACK);                             \
269:      (unsigned) (__o->next_free - __o->object_base); })
270: 
271: # define obstack_room(OBSTACK)                                          \
272:   __extension__                                                         \
273:   ({ struct obstack const *__o = (OBSTACK);                             \
274:      (unsigned) (__o->chunk_limit - __o->next_free); })
275: 
276: # define obstack_make_room(OBSTACK,length)                              \
277: __extension__                                                           \
278: ({ struct obstack *__o = (OBSTACK);                                     \
279:    int __len = (length);                                                \
280:    if (__o->chunk_limit - __o->next_free < __len)                       \
281:      _obstack_newchunk (__o, __len);                                    \
282:    (void) 0; })
283: 
284: # define obstack_empty_p(OBSTACK)                                       \
285:   __extension__                                                         \
286:   ({ struct obstack const *__o = (OBSTACK);                             \
287:      (__o->chunk->prev == 0                                             \
288:       && __o->next_free == __PTR_ALIGN ((char *) __o->chunk,            \
289:                                         __o->chunk->contents,           \
290:                                         __o->alignment_mask)); })
291: 
292: # define obstack_grow(OBSTACK,where,length)                             \
293: __extension__                                                           \
294: ({ struct obstack *__o = (OBSTACK);                                     \
295:    int __len = (length);                                                \
296:    if (__o->next_free + __len > __o->chunk_limit)                       \
297:      _obstack_newchunk (__o, __len);                                    \
298:    memcpy (__o->next_free, where, __len);                               \
299:    __o->next_free += __len;                                             \
300:    (void) 0; })
301: 
302: # define obstack_grow0(OBSTACK,where,length)                            \
303: __extension__                                                           \
304: ({ struct obstack *__o = (OBSTACK);                                     \
305:    int __len = (length);                                                \
306:    if (__o->next_free + __len + 1 > __o->chunk_limit)                   \
307:      _obstack_newchunk (__o, __len + 1);                                \
308:    memcpy (__o->next_free, where, __len);                               \
309:    __o->next_free += __len;                                             \
310:    *(__o->next_free)++ = 0;                                             \
311:    (void) 0; })
312: 
313: # define obstack_1grow(OBSTACK,datum)                                   \
314: __extension__                                                           \
315: ({ struct obstack *__o = (OBSTACK);                                     \
316:    if (__o->next_free + 1 > __o->chunk_limit)                           \
317:      _obstack_newchunk (__o, 1);                                        \
318:    obstack_1grow_fast (__o, datum);                                     \
319:    (void) 0; })
320: 
321: /* These assume that the obstack alignment is good enough for pointers
322:    or ints, and that the data added so far to the current object
323:    shares that much alignment.  */
324: 
325: # define obstack_ptr_grow(OBSTACK,datum)                                \
326: __extension__                                                           \
327: ({ struct obstack *__o = (OBSTACK);                                     \
328:    if (__o->next_free + sizeof (void *) > __o->chunk_limit)             \
329:      _obstack_newchunk (__o, sizeof (void *));                          \
330:    obstack_ptr_grow_fast (__o, datum); })                               \
331: 
332: # define obstack_int_grow(OBSTACK,datum)                                \
333: __extension__                                                           \
334: ({ struct obstack *__o = (OBSTACK);                                     \
335:    if (__o->next_free + sizeof (int) > __o->chunk_limit)                \
336:      _obstack_newchunk (__o, sizeof (int));                             \
337:    obstack_int_grow_fast (__o, datum); })
338: 
339: # define obstack_ptr_grow_fast(OBSTACK,aptr)                            \
340: __extension__                                                           \
341: ({ struct obstack *__o1 = (OBSTACK);                                    \
342:    *(const void **) __o1->next_free = (aptr);                           \
343:    __o1->next_free += sizeof (const void *);                            \
344:    (void) 0; })
345: 
346: # define obstack_int_grow_fast(OBSTACK,aint)                            \
347: __extension__                                                           \
348: ({ struct obstack *__o1 = (OBSTACK);                                    \
349:    *(int *) __o1->next_free = (aint);                                   \
350:    __o1->next_free += sizeof (int);                                     \
351:    (void) 0; })
352: 
353: # define obstack_blank(OBSTACK,length)                                  \
354: __extension__                                                           \
355: ({ struct obstack *__o = (OBSTACK);                                     \
356:    int __len = (length);                                                \
357:    if (__o->chunk_limit - __o->next_free < __len)                       \
358:      _obstack_newchunk (__o, __len);                                    \
359:    obstack_blank_fast (__o, __len);                                     \
360:    (void) 0; })
361: 
362: # define obstack_alloc(OBSTACK,length)                                  \
363: __extension__                                                           \
364: ({ struct obstack *__h = (OBSTACK);                                     \
365:    obstack_blank (__h, (length));                                       \
366:    obstack_finish (__h); })
367: 
368: # define obstack_copy(OBSTACK,where,length)                             \
369: __extension__                                                           \
370: ({ struct obstack *__h = (OBSTACK);                                     \
371:    obstack_grow (__h, (where), (length));                               \
372:    obstack_finish (__h); })
373: 
374: # define obstack_copy0(OBSTACK,where,length)                            \
375: __extension__                                                           \
376: ({ struct obstack *__h = (OBSTACK);                                     \
377:    obstack_grow0 (__h, (where), (length));                              \
378:    obstack_finish (__h); })
379: 
380: /* The local variable is named __o1 to avoid a name conflict
381:    when obstack_blank is called.  */
382: # define obstack_finish(OBSTACK)                                        \
383: __extension__                                                           \
384: ({ struct obstack *__o1 = (OBSTACK);                                    \
385:    void *__value = (void *) __o1->object_base;                          \
386:    if (__o1->next_free == __value)                                      \
387:      __o1->maybe_empty_object = 1;                                      \
388:    __o1->next_free                                                      \
389:      = __PTR_ALIGN (__o1->object_base, __o1->next_free,                 \
390:                     __o1->alignment_mask);                              \
391:    if (__o1->next_free - (char *)__o1->chunk                            \
392:        > __o1->chunk_limit - (char *)__o1->chunk)                       \
393:      __o1->next_free = __o1->chunk_limit;                               \
394:    __o1->object_base = __o1->next_free;                                 \
395:    __value; })
396: 
397: # define obstack_free(OBSTACK, OBJ)                                     \
398: __extension__                                                           \
399: ({ struct obstack *__o = (OBSTACK);                                     \
400:    void *__obj = (OBJ);                                                 \
401:    if (__obj > (void *)__o->chunk && __obj < (void *)__o->chunk_limit)  \
402:      __o->next_free = __o->object_base = (char *)__obj;                 \
403:    else (obstack_free) (__o, __obj); })
404: 
405: #else /* not __GNUC__ or not __STDC__ */
406: 
407: # define obstack_object_size(h) \
408:  (unsigned) ((h)->next_free - (h)->object_base)
409: 
410: # define obstack_room(h)                \
411:  (unsigned) ((h)->chunk_limit - (h)->next_free)
412: 
413: # define obstack_empty_p(h) \
414:  ((h)->chunk->prev == 0                                                 \
415:   && (h)->next_free == __PTR_ALIGN ((char *) (h)->chunk,                \
416:                                     (h)->chunk->contents,               \
417:                                     (h)->alignment_mask))
418: 
419: /* Note that the call to _obstack_newchunk is enclosed in (..., 0)
420:    so that we can avoid having void expressions
421:    in the arms of the conditional expression.
422:    Casting the third operand to void was tried before,
423:    but some compilers won't accept it.  */
424: 
425: # define obstack_make_room(h,length)                                    \
426: ( (h)->temp.tempint = (length),                                         \
427:   (((h)->next_free + (h)->temp.tempint > (h)->chunk_limit)              \
428:    ? (_obstack_newchunk ((h), (h)->temp.tempint), 0) : 0))
429: 
430: # define obstack_grow(h,where,length)                                   \
431: ( (h)->temp.tempint = (length),                                         \
432:   (((h)->next_free + (h)->temp.tempint > (h)->chunk_limit)              \
433:    ? (_obstack_newchunk ((h), (h)->temp.tempint), 0) : 0),              \
434:   memcpy ((h)->next_free, where, (h)->temp.tempint),                    \
435:   (h)->next_free += (h)->temp.tempint)
436: 
437: # define obstack_grow0(h,where,length)                                  \
438: ( (h)->temp.tempint = (length),                                         \
439:   (((h)->next_free + (h)->temp.tempint + 1 > (h)->chunk_limit)          \
440:    ? (_obstack_newchunk ((h), (h)->temp.tempint + 1), 0) : 0),          \
441:   memcpy ((h)->next_free, where, (h)->temp.tempint),                    \
442:   (h)->next_free += (h)->temp.tempint,                                  \
443:   *((h)->next_free)++ = 0)
444: 
445: # define obstack_1grow(h,datum)                                         \
446: ( (((h)->next_free + 1 > (h)->chunk_limit)                              \
447:    ? (_obstack_newchunk ((h), 1), 0) : 0),                              \
448:   obstack_1grow_fast (h, datum))
449: 
450: # define obstack_ptr_grow(h,datum)                                      \
451: ( (((h)->next_free + sizeof (char *) > (h)->chunk_limit)                \
452:    ? (_obstack_newchunk ((h), sizeof (char *)), 0) : 0),                \
453:   obstack_ptr_grow_fast (h, datum))
454: 
455: # define obstack_int_grow(h,datum)                                      \
456: ( (((h)->next_free + sizeof (int) > (h)->chunk_limit)                   \
457:    ? (_obstack_newchunk ((h), sizeof (int)), 0) : 0),                   \
458:   obstack_int_grow_fast (h, datum))
459: 
460: # define obstack_ptr_grow_fast(h,aptr)                                  \
461:   (((const void **) ((h)->next_free += sizeof (void *)))[-1] = (aptr))
462: 
463: # define obstack_int_grow_fast(h,aint)                                  \
464:   (((int *) ((h)->next_free += sizeof (int)))[-1] = (aint))
465: 
466: # define obstack_blank(h,length)                                        \
467: ( (h)->temp.tempint = (length),                                         \
468:   (((h)->chunk_limit - (h)->next_free < (h)->temp.tempint)              \
469:    ? (_obstack_newchunk ((h), (h)->temp.tempint), 0) : 0),              \
470:   obstack_blank_fast (h, (h)->temp.tempint))
471: 
472: # define obstack_alloc(h,length)                                        \
473:  (obstack_blank ((h), (length)), obstack_finish ((h)))
474: 
475: # define obstack_copy(h,where,length)                                   \
476:  (obstack_grow ((h), (where), (length)), obstack_finish ((h)))
477: 
478: # define obstack_copy0(h,where,length)                                  \
479:  (obstack_grow0 ((h), (where), (length)), obstack_finish ((h)))
480: 
481: # define obstack_finish(h)                                              \
482: ( ((h)->next_free == (h)->object_base                                   \
483:    ? (((h)->maybe_empty_object = 1), 0)                                 \
484:    : 0),                                                                \
485:   (h)->temp.tempptr = (h)->object_base,                                 \
486:   (h)->next_free                                                        \
487:     = __PTR_ALIGN ((h)->object_base, (h)->next_free,                    \
488:                    (h)->alignment_mask),                                \
489:   (((h)->next_free - (char *) (h)->chunk                                \
490:     > (h)->chunk_limit - (char *) (h)->chunk)                           \
491:    ? ((h)->next_free = (h)->chunk_limit) : 0),                          \
492:   (h)->object_base = (h)->next_free,                                    \
493:   (h)->temp.tempptr)
494: 
495: # define obstack_free(h,obj)                                            \
496: ( (h)->temp.tempint = (char *) (obj) - (char *) (h)->chunk,             \
497:   ((((h)->temp.tempint > 0                                              \
498:     && (h)->temp.tempint < (h)->chunk_limit - (char *) (h)->chunk))     \
499:    ? (((h)->next_free = (h)->object_base                                \
500:        = (h)->temp.tempint + (char *) (h)->chunk), 0)                   \
501:    : ((obstack_free) ((h), (h)->temp.tempint + (char *) (h)->chunk), 0)))
502: 
503: #endif /* not __GNUC__ or not __STDC__ */
504: 
505: #ifdef __cplusplus
506: }       /* C++ */
507: #endif
508: 
509: #endif /* obstack.h */
510: 


for client 18.217.142.249
© Andrew Scott 2006 - 2024,
All Rights Reserved
http://www.andrew-scott.uk/
Andrew Scott
http://www.andrew-scott.co.uk/