Merge Carl's preprocessor into the glcpp subdirectory.
authorKenneth Graunke <kenneth@whitecape.org>
Mon, 21 Jun 2010 18:22:11 +0000 (11:22 -0700)
committerKenneth Graunke <kenneth@whitecape.org>
Mon, 21 Jun 2010 18:22:11 +0000 (11:22 -0700)
147 files changed:
1  2 
glcpp/.gitignore
glcpp/Makefile
glcpp/README
glcpp/glcpp-lex.l
glcpp/glcpp-parse.y
glcpp/glcpp.c
glcpp/glcpp.h
glcpp/hash_table.c
glcpp/hash_table.h
glcpp/main/imports.h
glcpp/main/simple_list.h
glcpp/tests/000-content-with-spaces.c
glcpp/tests/000-content-with-spaces.c.expected
glcpp/tests/001-define.c
glcpp/tests/001-define.c.expected
glcpp/tests/002-define-chain.c
glcpp/tests/002-define-chain.c.expected
glcpp/tests/003-define-chain-reverse.c
glcpp/tests/003-define-chain-reverse.c.expected
glcpp/tests/004-define-recursive.c
glcpp/tests/004-define-recursive.c.expected
glcpp/tests/005-define-composite-chain.c
glcpp/tests/005-define-composite-chain.c.expected
glcpp/tests/006-define-composite-chain-reverse.c
glcpp/tests/006-define-composite-chain-reverse.c.expected
glcpp/tests/007-define-composite-recursive.c
glcpp/tests/007-define-composite-recursive.c.expected
glcpp/tests/008-define-empty.c
glcpp/tests/008-define-empty.c.expected
glcpp/tests/009-undef.c
glcpp/tests/009-undef.c.expected
glcpp/tests/010-undef-re-define.c
glcpp/tests/010-undef-re-define.c.expected
glcpp/tests/011-define-func-empty.c
glcpp/tests/011-define-func-empty.c.expected
glcpp/tests/012-define-func-no-args.c
glcpp/tests/012-define-func-no-args.c.expected
glcpp/tests/013-define-func-1-arg-unused.c
glcpp/tests/013-define-func-1-arg-unused.c.expected
glcpp/tests/014-define-func-2-arg-unused.c
glcpp/tests/014-define-func-2-arg-unused.c.expected
glcpp/tests/015-define-object-with-parens.c
glcpp/tests/015-define-object-with-parens.c.expected
glcpp/tests/016-define-func-1-arg.c
glcpp/tests/016-define-func-1-arg.c.expected
glcpp/tests/017-define-func-2-args.c
glcpp/tests/017-define-func-2-args.c.expected
glcpp/tests/018-define-func-macro-as-parameter.c
glcpp/tests/018-define-func-macro-as-parameter.c.expected
glcpp/tests/019-define-func-1-arg-multi.c
glcpp/tests/019-define-func-1-arg-multi.c.expected
glcpp/tests/020-define-func-2-arg-multi.c
glcpp/tests/020-define-func-2-arg-multi.c.expected
glcpp/tests/021-define-func-compose.c
glcpp/tests/021-define-func-compose.c.expected
glcpp/tests/022-define-func-arg-with-parens.c
glcpp/tests/022-define-func-arg-with-parens.c.expected
glcpp/tests/023-define-extra-whitespace.c
glcpp/tests/023-define-extra-whitespace.c.expected
glcpp/tests/024-define-chain-to-self-recursion.c
glcpp/tests/024-define-chain-to-self-recursion.c.expected
glcpp/tests/025-func-macro-as-non-macro.c
glcpp/tests/025-func-macro-as-non-macro.c.expected
glcpp/tests/026-define-func-extra-newlines.c
glcpp/tests/026-define-func-extra-newlines.c.expected
glcpp/tests/027-define-chain-obj-to-func.c
glcpp/tests/027-define-chain-obj-to-func.c.expected
glcpp/tests/028-define-chain-obj-to-non-func.c
glcpp/tests/028-define-chain-obj-to-non-func.c.expected
glcpp/tests/029-define-chain-obj-to-func-with-args.c
glcpp/tests/029-define-chain-obj-to-func-with-args.c.expected
glcpp/tests/030-define-chain-obj-to-func-compose.c
glcpp/tests/030-define-chain-obj-to-func-compose.c.expected
glcpp/tests/031-define-chain-func-to-func-compose.c
glcpp/tests/031-define-chain-func-to-func-compose.c.expected
glcpp/tests/032-define-func-self-recurse.c
glcpp/tests/032-define-func-self-recurse.c.expected
glcpp/tests/033-define-func-self-compose.c
glcpp/tests/033-define-func-self-compose.c.expected
glcpp/tests/034-define-func-self-compose-non-func.c
glcpp/tests/034-define-func-self-compose-non-func.c.expected
glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c
glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c.expected
glcpp/tests/036-define-func-non-macro-multi-token-argument.c
glcpp/tests/036-define-func-non-macro-multi-token-argument.c.expected
glcpp/tests/037-finalize-unexpanded-macro.c
glcpp/tests/037-finalize-unexpanded-macro.c.expected
glcpp/tests/038-func-arg-with-commas.c
glcpp/tests/038-func-arg-with-commas.c.expected
glcpp/tests/039-func-arg-obj-macro-with-comma.c
glcpp/tests/039-func-arg-obj-macro-with-comma.c.expected
glcpp/tests/040-token-pasting.c
glcpp/tests/040-token-pasting.c.expected
glcpp/tests/041-if-0.c
glcpp/tests/041-if-0.c.expected
glcpp/tests/042-if-1.c
glcpp/tests/042-if-1.c.expected
glcpp/tests/043-if-0-else.c
glcpp/tests/043-if-0-else.c.expected
glcpp/tests/044-if-1-else.c
glcpp/tests/044-if-1-else.c.expected
glcpp/tests/045-if-0-elif.c
glcpp/tests/045-if-0-elif.c.expected
glcpp/tests/046-if-1-elsif.c
glcpp/tests/046-if-1-elsif.c.expected
glcpp/tests/047-if-elif-else.c
glcpp/tests/047-if-elif-else.c.expected
glcpp/tests/048-if-nested.c
glcpp/tests/048-if-nested.c.expected
glcpp/tests/049-if-expression-precedence.c
glcpp/tests/049-if-expression-precedence.c.expected
glcpp/tests/050-if-defined.c
glcpp/tests/050-if-defined.c.expected
glcpp/tests/051-if-relational.c
glcpp/tests/051-if-relational.c.expected
glcpp/tests/052-if-bitwise.c
glcpp/tests/052-if-bitwise.c.expected
glcpp/tests/053-if-divide-and-shift.c
glcpp/tests/053-if-divide-and-shift.c.expected
glcpp/tests/054-if-with-macros.c
glcpp/tests/054-if-with-macros.c.expected
glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c
glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c.expected
glcpp/tests/056-macro-argument-with-comma.c
glcpp/tests/056-macro-argument-with-comma.c.expected
glcpp/tests/057-empty-arguments.c
glcpp/tests/057-empty-arguments.c.expected
glcpp/tests/058-token-pasting-empty-arguments.c
glcpp/tests/058-token-pasting-empty-arguments.c.expected
glcpp/tests/059-token-pasting-integer.c
glcpp/tests/059-token-pasting-integer.c.expected
glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c
glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c.expected
glcpp/tests/061-define-chain-obj-to-func-multi.c
glcpp/tests/061-define-chain-obj-to-func-multi.c.expected
glcpp/tests/062-if-0-skips-garbage.c
glcpp/tests/062-if-0-skips-garbage.c.expected
glcpp/tests/063-comments.c
glcpp/tests/063-comments.c.expected
glcpp/tests/071-punctuator.c
glcpp/tests/071-punctuator.c.expected
glcpp/tests/072-token-pasting-same-line.c
glcpp/tests/072-token-pasting-same-line.c.expected
glcpp/tests/099-c99-example.c
glcpp/tests/099-c99-example.c.expected
glcpp/tests/glcpp-test
glcpp/xtalloc.c

index 0000000,0000000..077db8d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,7 @@@
++glcpp
++glcpp-lex.c
++glcpp-parse.c
++glcpp-parse.h
++*.o
++*~
++tests/*.out
diff --cc glcpp/Makefile
index 0000000,3fb44ac..3fb44ac
mode 000000,100644..100644
--- /dev/null
diff --cc glcpp/README
index 0000000,ab42a3f..ab42a3f
mode 000000,100644..100644
--- /dev/null
--- 2/README
index 0000000,0d9a754..0d9a754
mode 000000,100644..100644
--- /dev/null
index 0000000,807cf59..807cf59
mode 000000,100644..100644
--- /dev/null
diff --cc glcpp/glcpp.c
index 0000000,fcdc4ed..fcdc4ed
mode 000000,100644..100644
--- /dev/null
diff --cc glcpp/glcpp.h
index 0000000,4459daa..4459daa
mode 000000,100644..100644
--- /dev/null
index 0000000,0000000..e89a256
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,159 @@@
++/*
++ * Copyright Â© 2008 Intel Corporation
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice (including the next
++ * paragraph) shall be included in all copies or substantial portions of the
++ * Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
++ * DEALINGS IN THE SOFTWARE.
++ */
++
++/**
++ * \file hash_table.c
++ * \brief Implementation of a generic, opaque hash table data type.
++ *
++ * \author Ian Romanick <ian.d.romanick@intel.com>
++ */
++
++#include "main/imports.h"
++#include "main/simple_list.h"
++#include "hash_table.h"
++
++struct node {
++   struct node *next;
++   struct node *prev;
++};
++
++struct hash_table {
++    hash_func_t    hash;
++    hash_compare_func_t  compare;
++
++    unsigned num_buckets;
++    struct node buckets[1];
++};
++
++
++struct hash_node {
++    struct node link;
++    const void *key;
++    void *data;
++};
++
++
++struct hash_table *
++hash_table_ctor(unsigned num_buckets, hash_func_t hash,
++                hash_compare_func_t compare)
++{
++    struct hash_table *ht;
++    unsigned i;
++
++
++    if (num_buckets < 16) {
++        num_buckets = 16;
++    }
++
++    ht = _mesa_malloc(sizeof(*ht) + ((num_buckets - 1) 
++                                   * sizeof(ht->buckets[0])));
++    if (ht != NULL) {
++        ht->hash = hash;
++        ht->compare = compare;
++        ht->num_buckets = num_buckets;
++
++        for (i = 0; i < num_buckets; i++) {
++            make_empty_list(& ht->buckets[i]);
++        }
++    }
++
++    return ht;
++}
++
++
++void
++hash_table_dtor(struct hash_table *ht)
++{
++   hash_table_clear(ht);
++   _mesa_free(ht);
++}
++
++
++void
++hash_table_clear(struct hash_table *ht)
++{
++   struct node *node;
++   struct node *temp;
++   unsigned i;
++
++
++   for (i = 0; i < ht->num_buckets; i++) {
++      foreach_s(node, temp, & ht->buckets[i]) {
++       remove_from_list(node);
++       _mesa_free(node);
++      }
++
++      assert(is_empty_list(& ht->buckets[i]));
++   }
++}
++
++
++void *
++hash_table_find(struct hash_table *ht, const void *key)
++{
++    const unsigned hash_value = (*ht->hash)(key);
++    const unsigned bucket = hash_value % ht->num_buckets;
++    struct node *node;
++
++    foreach(node, & ht->buckets[bucket]) {
++       struct hash_node *hn = (struct hash_node *) node;
++
++       if ((*ht->compare)(hn->key, key) == 0) {
++        return hn->data;
++       }
++    }
++
++    return NULL;
++}
++
++
++void
++hash_table_insert(struct hash_table *ht, void *data, const void *key)
++{
++    const unsigned hash_value = (*ht->hash)(key);
++    const unsigned bucket = hash_value % ht->num_buckets;
++    struct hash_node *node;
++
++    node = _mesa_calloc(sizeof(*node));
++
++    node->data = data;
++    node->key = key;
++
++    insert_at_head(& ht->buckets[bucket], & node->link);
++}
++
++
++unsigned
++hash_table_string_hash(const void *key)
++{
++    const char *str = (const char *) key;
++    unsigned hash = 5381;
++
++
++    while (*str != '\0') {
++        hash = (hash * 33) + *str;
++        str++;
++    }
++
++    return hash;
++}
index 0000000,0000000..b9dd343
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,125 @@@
++/*
++ * Copyright Â© 2008 Intel Corporation
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice (including the next
++ * paragraph) shall be included in all copies or substantial portions of the
++ * Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
++ * DEALINGS IN THE SOFTWARE.
++ */
++
++/**
++ * \file hash_table.h
++ * \brief Implementation of a generic, opaque hash table data type.
++ *
++ * \author Ian Romanick <ian.d.romanick@intel.com>
++ */
++
++#ifndef HASH_TABLE_H
++#define HASH_TABLE_H
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#include <string.h>
++
++struct hash_table;
++
++typedef unsigned (*hash_func_t)(const void *key);
++typedef int (*hash_compare_func_t)(const void *key1, const void *key2);
++
++/**
++ * Hash table constructor
++ *
++ * Creates a hash table with the specified number of buckets.  The supplied
++ * \c hash and \c compare routines are used when adding elements to the table
++ * and when searching for elements in the table.
++ *
++ * \param num_buckets  Number of buckets (bins) in the hash table.
++ * \param hash         Function used to compute hash value of input keys.
++ * \param compare      Function used to compare keys.
++ */
++extern struct hash_table *hash_table_ctor(unsigned num_buckets,
++    hash_func_t hash, hash_compare_func_t compare);
++
++
++/**
++ * Release all memory associated with a hash table
++ *
++ * \warning
++ * This function cannot release memory occupied either by keys or data.
++ */
++extern void hash_table_dtor(struct hash_table *ht);
++
++
++/**
++ * Flush all entries from a hash table
++ *
++ * \param ht  Table to be cleared of its entries.
++ */
++extern void hash_table_clear(struct hash_table *ht);
++
++
++/**
++ * Search a hash table for a specific element
++ *
++ * \param ht   Table to be searched
++ * \param key  Key of the desired element
++ *
++ * \return
++ * The \c data value supplied to \c hash_table_insert when the element with
++ * the matching key was added.  If no matching key exists in the table,
++ * \c NULL is returned.
++ */
++extern void *hash_table_find(struct hash_table *ht, const void *key);
++
++
++/**
++ * Add an element to a hash table
++ */
++extern void hash_table_insert(struct hash_table *ht, void *data,
++    const void *key);
++
++
++/**
++ * Compute hash value of a string
++ *
++ * Computes the hash value of a string using the DJB2 algorithm developed by
++ * Professor Daniel J. Bernstein.  It was published on comp.lang.c once upon
++ * a time.  I was unable to find the original posting in the archives.
++ *
++ * \param key  Pointer to a NUL terminated string to be hashed.
++ *
++ * \sa hash_table_string_compare
++ */
++extern unsigned hash_table_string_hash(const void *key);
++
++
++/**
++ * Compare two strings used as keys
++ *
++ * This is just a macro wrapper around \c strcmp.
++ *
++ * \sa hash_table_string_hash
++ */
++#define hash_table_string_compare ((hash_compare_func_t) strcmp)
++
++#ifdef __cplusplus
++};
++#endif
++
++#endif /* HASH_TABLE_H */
index 0000000,0000000..d219734
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++#include <assert.h>
++#include <stdlib.h>
++
++#define _mesa_malloc(x)   malloc(x)
++#define _mesa_free(x)     free(x)
++#define _mesa_calloc(x)   calloc(1,x)
index 0000000,0000000..5ef39e1
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,235 @@@
++/**
++ * \file simple_list.h
++ * Simple macros for type-safe, intrusive lists.
++ *
++ *  Intended to work with a list sentinal which is created as an empty
++ *  list.  Insert & delete are O(1).
++ *  
++ * \author
++ *  (C) 1997, Keith Whitwell
++ */
++
++/*
++ * Mesa 3-D graphics library
++ * Version:  3.5
++ *
++ * Copyright (C) 1999-2001  Brian Paul   All Rights Reserved.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included
++ * in all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
++ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
++ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
++ */
++
++
++#ifndef _SIMPLE_LIST_H
++#define _SIMPLE_LIST_H
++
++struct simple_node {
++   struct simple_node *next;
++   struct simple_node *prev;
++};
++
++/**
++ * Remove an element from list.
++ *
++ * \param elem element to remove.
++ */
++#define remove_from_list(elem)                        \
++do {                                          \
++   (elem)->next->prev = (elem)->prev;         \
++   (elem)->prev->next = (elem)->next;         \
++} while (0)
++
++/**
++ * Insert an element to the list head.
++ *
++ * \param list list.
++ * \param elem element to insert.
++ */
++#define insert_at_head(list, elem)            \
++do {                                          \
++   (elem)->prev = list;                               \
++   (elem)->next = (list)->next;                       \
++   (list)->next->prev = elem;                 \
++   (list)->next = elem;                               \
++} while(0)
++
++/**
++ * Insert an element to the list tail.
++ *
++ * \param list list.
++ * \param elem element to insert.
++ */
++#define insert_at_tail(list, elem)            \
++do {                                          \
++   (elem)->next = list;                               \
++   (elem)->prev = (list)->prev;                       \
++   (list)->prev->next = elem;                 \
++   (list)->prev = elem;                               \
++} while(0)
++
++/**
++ * Move an element to the list head.
++ *
++ * \param list list.
++ * \param elem element to move.
++ */
++#define move_to_head(list, elem)              \
++do {                                          \
++   remove_from_list(elem);                    \
++   insert_at_head(list, elem);                        \
++} while (0)
++
++/**
++ * Move an element to the list tail.
++ *
++ * \param list list.
++ * \param elem element to move.
++ */
++#define move_to_tail(list, elem)              \
++do {                                          \
++   remove_from_list(elem);                    \
++   insert_at_tail(list, elem);                        \
++} while (0)
++
++/**
++ * Consatinate a cyclic list to a list
++ *
++ * Appends the sequence of nodes starting with \c tail to the list \c head.
++ * A "cyclic list" is a list that does not have a sentinal node.  This means
++ * that the data pointed to by \c tail is an actual node, not a dataless
++ * sentinal.  Note that if \c tail constist of a single node, this macro
++ * behaves identically to \c insert_at_tail
++ *
++ * \param head Head of the list to be appended to.  This may or may not
++ *             be a cyclic list.
++ * \param tail Head of the cyclic list to be appended to \c head.
++ * \param temp Temporary \c simple_list used by the macro
++ *
++ * \sa insert_at_tail
++ */
++#define concat_list_and_cycle(head, tail, temp)       \
++do {                                          \
++   (head)->prev->next = (tail);                       \
++   (tail)->prev->next = (head);                       \
++   (temp) = (head)->prev;                     \
++   (head)->prev = (tail)->prev;                       \
++   (tail)->prev = (temp);                     \
++} while (0)
++
++#define concat_list(head, next_list)          \
++do {                                          \
++   (next_list)->next->prev = (head)->prev;    \
++   (next_list)->prev->next = (head);          \
++   (head)->prev->next = (next_list)->next;    \
++   (head)->prev = (next_list)->prev;          \
++} while (0)
++
++/**
++ * Make a empty list empty.
++ *
++ * \param sentinal list (sentinal element).
++ */
++#define make_empty_list(sentinal)             \
++do {                                          \
++   (sentinal)->next = sentinal;                       \
++   (sentinal)->prev = sentinal;                       \
++} while (0)
++
++/**
++ * Get list first element.
++ *
++ * \param list list.
++ *
++ * \return pointer to first element.
++ */
++#define first_elem(list)       ((list)->next)
++
++/**
++ * Get list last element.
++ *
++ * \param list list.
++ *
++ * \return pointer to last element.
++ */
++#define last_elem(list)        ((list)->prev)
++
++/**
++ * Get next element.
++ *
++ * \param elem element.
++ *
++ * \return pointer to next element.
++ */
++#define next_elem(elem)        ((elem)->next)
++
++/**
++ * Get previous element.
++ *
++ * \param elem element.
++ *
++ * \return pointer to previous element.
++ */
++#define prev_elem(elem)        ((elem)->prev)
++
++/**
++ * Test whether element is at end of the list.
++ * 
++ * \param list list.
++ * \param elem element.
++ * 
++ * \return non-zero if element is at end of list, or zero otherwise.
++ */
++#define at_end(list, elem)     ((elem) == (list))
++
++/**
++ * Test if a list is empty.
++ * 
++ * \param list list.
++ * 
++ * \return non-zero if list empty, or zero otherwise.
++ */
++#define is_empty_list(list)    ((list)->next == (list))
++
++/**
++ * Walk through the elements of a list.
++ *
++ * \param ptr pointer to the current element.
++ * \param list list.
++ *
++ * \note It should be followed by a { } block or a single statement, as in a \c
++ * for loop.
++ */
++#define foreach(ptr, list)     \
++        for( ptr=(list)->next ;  ptr!=list ;  ptr=(ptr)->next )
++
++/**
++ * Walk through the elements of a list.
++ *
++ * Same as #foreach but lets you unlink the current value during a list
++ * traversal.  Useful for freeing a list, element by element.
++ * 
++ * \param ptr pointer to the current element.
++ * \param t temporary pointer.
++ * \param list list.
++ *
++ * \note It should be followed by a { } block or a single statement, as in a \c
++ * for loop.
++ */
++#define foreach_s(ptr, t, list)   \
++        for(ptr=(list)->next,t=(ptr)->next; list != ptr; ptr=t, t=(t)->next)
++
++#endif
index 0000000,696cb3a..696cb3a
mode 000000,100644..100644
--- /dev/null
index 0000000,cbf2fee..cbf2fee
mode 000000,100644..100644
--- /dev/null
index 0000000,a464d9d..a464d9d
mode 000000,100644..100644
--- /dev/null
index 0000000,87d75c6..87d75c6
mode 000000,100644..100644
--- /dev/null
index 0000000,a18b724..a18b724
mode 000000,100644..100644
--- /dev/null
index 0000000,2ac56ea..2ac56ea
mode 000000,100644..100644
--- /dev/null
index 0000000,b1bd17e..b1bd17e
mode 000000,100644..100644
--- /dev/null
index 0000000,3fc1fb4..3fc1fb4
mode 000000,100644..100644
--- /dev/null
index 0000000,9c0b35a..9c0b35a
mode 000000,100644..100644
--- /dev/null
index 0000000,32ff737..32ff737
mode 000000,100644..100644
--- /dev/null
index 0000000,d9ce13c..d9ce13c
mode 000000,100644..100644
--- /dev/null
index 0000000,c2bb730..c2bb730
mode 000000,100644..100644
--- /dev/null
index 0000000,a2e2404..a2e2404
mode 000000,100644..100644
--- /dev/null
index 0000000,c725383..c725383
mode 000000,100644..100644
--- /dev/null
index 0000000,21ddd0e..21ddd0e
mode 000000,100644..100644
--- /dev/null
index 0000000,1407c7d..1407c7d
mode 000000,100644..100644
--- /dev/null
index 0000000,caab3ba..caab3ba
mode 000000,100644..100644
--- /dev/null
index 0000000,2cab677..2cab677
mode 000000,100644..100644
--- /dev/null
index 0000000,8b506b3..8b506b3
mode 000000,100644..100644
--- /dev/null
index 0000000,874a25c..874a25c
mode 000000,100644..100644
--- /dev/null
index 0000000,a6ae946..a6ae946
mode 000000,100644..100644
--- /dev/null
index 0000000,323351f..323351f
mode 000000,100644..100644
--- /dev/null
index 0000000,3d7e6be..3d7e6be
mode 000000,100644..100644
--- /dev/null
index 0000000,28dfc25..28dfc25
mode 000000,100644..100644
--- /dev/null
index 0000000,4a31e1c..4a31e1c
mode 000000,100644..100644
--- /dev/null
index 0000000,e50f686..e50f686
mode 000000,100644..100644
--- /dev/null
index 0000000,a9bb158..a9bb158
mode 000000,100644..100644
--- /dev/null
index 0000000,130515a..130515a
mode 000000,100644..100644
--- /dev/null
index 0000000,a499571..a499571
mode 000000,100644..100644
--- /dev/null
index 0000000,e8f0838..e8f0838
mode 000000,100644..100644
--- /dev/null
index 0000000,fc4679c..fc4679c
mode 000000,100644..100644
--- /dev/null
index 0000000,8beb9c3..8beb9c3
mode 000000,100644..100644
--- /dev/null
index 0000000,34f0f95..34f0f95
mode 000000,100644..100644
--- /dev/null
index 0000000,737eb8d..737eb8d
mode 000000,100644..100644
--- /dev/null
index 0000000,c3db488..c3db488
mode 000000,100644..100644
--- /dev/null
index 0000000,2d8e45e..2d8e45e
mode 000000,100644..100644
--- /dev/null
index 0000000,44e52b2..44e52b2
mode 000000,100644..100644
--- /dev/null
index 0000000,d24c54a..d24c54a
mode 000000,100644..100644
--- /dev/null
index 0000000,3da79a0..3da79a0
mode 000000,100644..100644
--- /dev/null
index 0000000,6140232..6140232
mode 000000,100644..100644
--- /dev/null
index 0000000,d9e439b..d9e439b
mode 000000,100644..100644
--- /dev/null
index 0000000,e641d2f..e641d2f
mode 000000,100644..100644
--- /dev/null
index 0000000,4998d76..4998d76
mode 000000,100644..100644
--- /dev/null
index 0000000,959d682..959d682
mode 000000,100644..100644
--- /dev/null
index 0000000,959d682..959d682
mode 000000,100644..100644
--- /dev/null
index 0000000,d1976b1..d1976b1
mode 000000,100644..100644
--- /dev/null
index 0000000,352bbff..352bbff
mode 000000,100644..100644
--- /dev/null
index 0000000,396f6e1..396f6e1
mode 000000,100755..100755
--- /dev/null
diff --cc glcpp/xtalloc.c
index 0000000,656ac2d..656ac2d
mode 000000,100644..100644
--- /dev/null