ia64/xen-unstable

changeset 1597:7fc121a3c8a0

bitkeeper revision 1.1010.1.11 (40e03333GhMB8qgYk92TiquiQmUajA)

Change domain save/restore deal with the config string.
author mjw@wray-m-3.hpl.hp.com
date Mon Jun 28 15:03:15 2004 +0000 (2004-06-28)
parents c8e677f40f9d
children 5427e66e7ea4
files .rootkeys BitKeeper/etc/ignore tools/lib/allocate.c tools/lib/allocate.h tools/lib/debug.h tools/lib/enum.c tools/lib/enum.h tools/lib/file_stream.c tools/lib/file_stream.h tools/lib/gzip_stream.c tools/lib/gzip_stream.h tools/lib/hash_table.c tools/lib/hash_table.h tools/lib/iostream.c tools/lib/iostream.h tools/lib/kernel_stream.c tools/lib/kernel_stream.h tools/lib/lexis.c tools/lib/lexis.h tools/lib/lzi_stream.c tools/lib/lzi_stream.h tools/lib/lzo_stream.c tools/lib/lzo_stream.h tools/lib/marshal.c tools/lib/marshal.h tools/lib/socket_stream.c tools/lib/socket_stream.h tools/lib/string_stream.c tools/lib/string_stream.h tools/lib/sxpr.c tools/lib/sxpr.h tools/lib/sxpr_parser.c tools/lib/sxpr_parser.h tools/lib/sys_ctype.h tools/lib/sys_net.c tools/lib/sys_net.h tools/lib/sys_string.c tools/lib/sys_string.h tools/lib/xdr.c tools/lib/xdr.h tools/xc/lib/Makefile tools/xc/lib/xc.h tools/xc/lib/xc_io.c tools/xc/lib/xc_io.h tools/xc/lib/xc_linux_restore.c tools/xc/lib/xc_linux_save.c tools/xc/lib/xc_private.h tools/xc/py/Xc.c tools/xc/py/setup.py tools/xen/lib/xend/XendDomain.py tools/xen/lib/xend/XendDomainInfo.py tools/xen/lib/xend/server/SrvDomain.py tools/xen/lib/xend/server/SrvDomainDir.py tools/xen/lib/xend/sxp.py tools/xen/xend
line diff
     1.1 --- a/.rootkeys	Mon Jun 28 08:17:15 2004 +0000
     1.2 +++ b/.rootkeys	Mon Jun 28 15:03:15 2004 +0000
     1.3 @@ -165,6 +165,44 @@ 401d7e16RJj-lbtsVEjua6HYAIiKiA tools/exa
     1.4  40c9c468pXANclL7slGaoD0kSrIwoQ tools/examples/xm_dom_create.py
     1.5  40cf2937oKlROYOJTN8GWwWM5AmjBg tools/examples/xmdefaults
     1.6  40dfd40auJwNnb8NoiSnRkvZaaXkUg tools/examples/xmnetbsd
     1.7 +40e033325Sjqs-_4TuzeUEprP_gYFg tools/lib/allocate.c
     1.8 +40e03332KYz7o1bn2MG_KPbBlyoIMA tools/lib/allocate.h
     1.9 +40e03332IyRttYoXKoJla5qCC514SQ tools/lib/debug.h
    1.10 +40e03332qV5tJ-GJZjo-LBCeGuEjJA tools/lib/enum.c
    1.11 +40e03332wwMVxfobgA1PSMTSAGLiCw tools/lib/enum.h
    1.12 +40e03332p5Dc_owJQRuN72ymJZddFQ tools/lib/file_stream.c
    1.13 +40e03332jWfB2viAhLSkq1WK0r_iDQ tools/lib/file_stream.h
    1.14 +40e03332rUjNMGg11n2rN6V4DCrvOg tools/lib/gzip_stream.c
    1.15 +40e033321O5Qg22haLoq5lpmk4tooQ tools/lib/gzip_stream.h
    1.16 +40e03332QrTR96tc6yS2rMBpd2mq1A tools/lib/hash_table.c
    1.17 +40e033325KoIb0d_uy8s7b5DUR9fPQ tools/lib/hash_table.h
    1.18 +40e03332ihnBGzHykVwZnFmkAppb4g tools/lib/iostream.c
    1.19 +40e03332UGwbLR4wsw4ft14p0Yw5pg tools/lib/iostream.h
    1.20 +40e0333245DLDzJemeSVBLuutHtzEQ tools/lib/kernel_stream.c
    1.21 +40e03332aK0GkgpDdc-PVTkWKTeOBg tools/lib/kernel_stream.h
    1.22 +40e03332HJ0cDcZDKDUUT-tEiBWOZw tools/lib/lexis.c
    1.23 +40e03332tnH9Ggzxbfi3xY9Vh2hUlg tools/lib/lexis.h
    1.24 +40e03332aYIW0BNBh6wXuKKn_P7Yyg tools/lib/lzi_stream.c
    1.25 +40e0333233voTffE4cJSMGJARfiSSQ tools/lib/lzi_stream.h
    1.26 +40e03332FXuMoUnfsAKSgV8X4rFbYQ tools/lib/lzo_stream.c
    1.27 +40e03332InJaiLfpDcIXBy2fI0RFGQ tools/lib/lzo_stream.h
    1.28 +40e03332a5SCuRsejHStTuWzMQNv8Q tools/lib/marshal.c
    1.29 +40e03332TwKyJrZQiiQfNq4vc2hpgw tools/lib/marshal.h
    1.30 +40e033328ccHlJuTR1FswYL_EC6LFA tools/lib/socket_stream.c
    1.31 +40e03332P0KVQGkmahj47aafo1X0nA tools/lib/socket_stream.h
    1.32 +40e03332KT_tnnoAMbPVAZBB7kSOAQ tools/lib/string_stream.c
    1.33 +40e03332-VtK6_OZa1vMHXFil8uq6w tools/lib/string_stream.h
    1.34 +40e03332dDtczi6YX7_mMxhYjJeAdQ tools/lib/sxpr.c
    1.35 +40e03332QPuyNKDOTIYVvkwK5qO-vg tools/lib/sxpr.h
    1.36 +40e03332Pi0_osJ3XPBi38ADPqdl4A tools/lib/sxpr_parser.c
    1.37 +40e033324v5QFMvWEXXzv38uUT9kHg tools/lib/sxpr_parser.h
    1.38 +40e03332gKUInsqtxQOV4mPiMqf_dg tools/lib/sys_ctype.h
    1.39 +40e03332Rkvq6nn_UNjzAAK_Tk9v1g tools/lib/sys_net.c
    1.40 +40e03332lQHvQHw4Rh7VsT1_sui29A tools/lib/sys_net.h
    1.41 +40e033321smklZd7bDSdWvQCeIshtg tools/lib/sys_string.c
    1.42 +40e03332h5V611rRWURRLqb1Ekatxg tools/lib/sys_string.h
    1.43 +40e03332u4q5kgF0N7RfqB4s0pZVew tools/lib/xdr.c
    1.44 +40e03332hY16nfRXF4gGd5S1aUJUBw tools/lib/xdr.h
    1.45  3f776bd2Xd-dUcPKlPN2vG89VGtfvQ tools/misc/Makefile
    1.46  40ab2cfawIw8tsYo0dQKtp83h4qfTQ tools/misc/fakei386xen
    1.47  3f6dc136ZKOjd8PIqLbFBl_v-rnkGg tools/misc/miniterm/Makefile
    1.48 @@ -185,6 +223,8 @@ 3fbba6dbEVkVMX0JuDFzap9jeaucGA tools/xc/
    1.49  3fbba6dbasJQV-MVElDC0DGSHMiL5w tools/xc/lib/xc_domain.c
    1.50  40278d99BLsfUv3qxv0I8C1sClZ0ow tools/xc/lib/xc_elf.h
    1.51  403e0977Bjsm_e82pwvl9VvaJxh8Gg tools/xc/lib/xc_evtchn.c
    1.52 +40e03333Eegw8czSWvHsbKxrRZJjRA tools/xc/lib/xc_io.c
    1.53 +40e03333vrWGbLAhyJjXlqCHaJt7eA tools/xc/lib/xc_io.h
    1.54  3fbba6dbNCU7U6nsMYiXzKkp3ztaJg tools/xc/lib/xc_linux_build.c
    1.55  3fbba6dbl267zZOAVHYLOdLCdhcZMw tools/xc/lib/xc_linux_restore.c
    1.56  3fbba6db7li3FJiABYtCmuGxOJxEGw tools/xc/lib/xc_linux_save.c
     2.1 --- a/BitKeeper/etc/ignore	Mon Jun 28 08:17:15 2004 +0000
     2.2 +++ b/BitKeeper/etc/ignore	Mon Jun 28 15:03:15 2004 +0000
     2.3 @@ -31,3 +31,21 @@ xen/tools/figlet/figlet
     2.4  xen/xen
     2.5  xen/xen-syms
     2.6  xen/xen.*
     2.7 +tools/xc/lib/.allocate.o.d
     2.8 +tools/xc/lib/.file_stream.o.d
     2.9 +tools/xc/lib/.gzip_stream.o.d
    2.10 +tools/xc/lib/.iostream.o.d
    2.11 +tools/xc/lib/.sys_net.o.d
    2.12 +tools/xc/lib/.sys_string.o.d
    2.13 +tools/xc/lib/.xc_atropos.o.d
    2.14 +tools/xc/lib/.xc_bvtsched.o.d
    2.15 +tools/xc/lib/.xc_domain.o.d
    2.16 +tools/xc/lib/.xc_evtchn.o.d
    2.17 +tools/xc/lib/.xc_io.o.d
    2.18 +tools/xc/lib/.xc_linux_build.o.d
    2.19 +tools/xc/lib/.xc_linux_restore.o.d
    2.20 +tools/xc/lib/.xc_linux_save.o.d
    2.21 +tools/xc/lib/.xc_misc.o.d
    2.22 +tools/xc/lib/.xc_netbsd_build.o.d
    2.23 +tools/xc/lib/.xc_physdev.o.d
    2.24 +tools/xc/lib/.xc_private.o.d
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/tools/lib/allocate.c	Mon Jun 28 15:03:15 2004 +0000
     3.3 @@ -0,0 +1,116 @@
     3.4 +/*
     3.5 + * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
     3.6 + *
     3.7 + * This library is free software; you can redistribute it and/or modify
     3.8 + * it under the terms of the GNU Lesser General Public License as published by
     3.9 + * the Free Software Foundation; either version 2.1 of the License, or
    3.10 + * (at your option) any later version.
    3.11 + *
    3.12 + * This library is distributed in the hope that it will be useful,
    3.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    3.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    3.15 + * GNU Lesser General Public License for more details.
    3.16 + *
    3.17 + * You should have received a copy of the GNU Lesser General Public License
    3.18 + * along with this library; if not, write to the Free Software
    3.19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    3.20 + */
    3.21 +
    3.22 +#include "allocate.h"
    3.23 +
    3.24 +/** @file
    3.25 + * Support for allocating memory.
    3.26 + * Usable from user code or kernel code (with __KERNEL__ defined).
    3.27 + * In user code will use GC if USE_GC is defined.
    3.28 + */
    3.29 +
    3.30 +#ifdef __KERNEL__
    3.31 +/*----------------------------------------------------------------------------*/
    3.32 +#  include <linux/config.h>
    3.33 +#  include <linux/slab.h>
    3.34 +#  include <linux/string.h>
    3.35 +#  include <linux/types.h>
    3.36 +
    3.37 +#  define DEFAULT_TYPE    0
    3.38 +#  define MALLOC(n, type) kmalloc(n, type)
    3.39 +#  define FREE(ptr)       kfree(ptr)
    3.40 +
    3.41 +/*----------------------------------------------------------------------------*/
    3.42 +#else /* ! __KERNEL__ */
    3.43 +
    3.44 +#  include <stdlib.h>
    3.45 +#  include <string.h>
    3.46 +
    3.47 +#  define DEFAULT_TYPE    0
    3.48 +
    3.49 +#ifdef USE_GC
    3.50 +#  include "gc.h"
    3.51 +#  define MALLOC(n, typ)  GC_malloc(n)
    3.52 +#  define FREE(ptr)       (ptr=NULL)
    3.53 +//typedef void *GC_PTR;
    3.54 +//GC_PTR (*GC_oom_fn)(size_t n);
    3.55 +#else
    3.56 +#  define MALLOC(n, type) malloc(n)
    3.57 +#  define FREE(ptr)       free(ptr)
    3.58 +#endif
    3.59 +
    3.60 +/*----------------------------------------------------------------------------*/
    3.61 +#endif
    3.62 +
    3.63 +/** Function to call when memory cannot be allocated. */
    3.64 +AllocateFailedFn *allocate_failed_fn = NULL;
    3.65 +
    3.66 +/** Allocate memory and zero it.
    3.67 + * The type is only relevant when calling from kernel code,
    3.68 + * from user code it is ignored.
    3.69 + * In kernel code the values accepted by kmalloc can be used:
    3.70 + * GFP_USER, GFP_ATOMIC, GFP_KERNEL.
    3.71 + *
    3.72 + * @param size number of bytes to allocate
    3.73 + * @param type memory type to allocate (kernel only)
    3.74 + * @return pointer to the allocated memory or zero
    3.75 + * if malloc failed
    3.76 + */
    3.77 +void *allocate_type(int size, int type){
    3.78 +    void *p = MALLOC(size, type);
    3.79 +    if(p){
    3.80 +        memzero(p, size);
    3.81 +    } else if(allocate_failed_fn){
    3.82 +        allocate_failed_fn(size, type);
    3.83 +    }
    3.84 +    return p;
    3.85 +}
    3.86 +
    3.87 +/** Allocate memory and zero it.
    3.88 + *
    3.89 + * @param size number of bytes to allocate
    3.90 + * @return pointer to the allocated memory or zero
    3.91 + * if malloc failed
    3.92 + */
    3.93 +void *allocate(int size){
    3.94 +    return allocate_type(size, DEFAULT_TYPE);
    3.95 +}
    3.96 +
    3.97 +/** Free memory allocated by allocate().
    3.98 + * No-op if 'p' is null.
    3.99 + *
   3.100 + * @param p memory to free
   3.101 + */
   3.102 +void deallocate(void *p){
   3.103 +    if(p){
   3.104 +        FREE(p);
   3.105 +    }
   3.106 +}
   3.107 +
   3.108 +/** Set bytes to zero.
   3.109 + * No-op if 'p' is null.
   3.110 + *
   3.111 + * @param p memory to zero
   3.112 + * @param size number of bytes to zero
   3.113 + */
   3.114 +void memzero(void *p, int size){
   3.115 +    if(p){
   3.116 +        memset(p, 0, (size_t)size);
   3.117 +    }
   3.118 +}
   3.119 +
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/tools/lib/allocate.h	Mon Jun 28 15:03:15 2004 +0000
     4.3 @@ -0,0 +1,45 @@
     4.4 +/*
     4.5 + * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
     4.6 + *
     4.7 + * This library is free software; you can redistribute it and/or modify
     4.8 + * it under the terms of the GNU Lesser General Public License as published by
     4.9 + * the Free Software Foundation; either version 2.1 of the License, or
    4.10 + * (at your option) any later version.
    4.11 + *
    4.12 + * This library is distributed in the hope that it will be useful,
    4.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    4.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    4.15 + * GNU Lesser General Public License for more details.
    4.16 + *
    4.17 + * You should have received a copy of the GNU Lesser General Public License
    4.18 + * along with this library; if not, write to the Free Software
    4.19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    4.20 + */
    4.21 +
    4.22 +#ifndef _XEN_LIB_ALLOCATE_H_
    4.23 +#define _XEN_LIB_ALLOCATE_H_
    4.24 +
    4.25 +/** Allocate memory for a given type, and cast. */
    4.26 +#define ALLOCATE(ctype) (ctype *)allocate(sizeof(ctype))
    4.27 +
    4.28 +/** Allocate memory for a given type, and cast. */
    4.29 +#define ALLOCATE_TYPE(ctype, type) (ctype *)allocate(sizeof(ctype))
    4.30 +
    4.31 +extern void *allocate_type(int size, int type);
    4.32 +extern void *allocate(int size);
    4.33 +extern void deallocate(void *);
    4.34 +extern void memzero(void *p, int size);
    4.35 +
    4.36 +typedef void AllocateFailedFn(int size, int type);
    4.37 +extern AllocateFailedFn *allocate_failed_fn;
    4.38 +
    4.39 +#endif /* _XEN_LIB_ALLOCATE_H_ */
    4.40 +
    4.41 +
    4.42 +
    4.43 +
    4.44 +
    4.45 +
    4.46 +
    4.47 +
    4.48 +
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/tools/lib/debug.h	Mon Jun 28 15:03:15 2004 +0000
     5.3 @@ -0,0 +1,72 @@
     5.4 +/*
     5.5 + * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
     5.6 + *
     5.7 + * This library is free software; you can redistribute it and/or modify
     5.8 + * it under the terms of the GNU Lesser General Public License as published by
     5.9 + * the Free Software Foundation; either version 2.1 of the License, or
    5.10 + * (at your option) any later version.
    5.11 + *
    5.12 + * This library is distributed in the hope that it will be useful,
    5.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    5.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    5.15 + * GNU Lesser General Public License for more details.
    5.16 + *
    5.17 + * You should have received a copy of the GNU Lesser General Public License
    5.18 + * along with this library; if not, write to the Free Software
    5.19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    5.20 + */
    5.21 +#ifndef _XEN_LIB_DEBUG_H_
    5.22 +#define _XEN_LIB_DEBUG_H_
    5.23 +
    5.24 +#ifndef MODULE_NAME
    5.25 +#define MODULE_NAME ""
    5.26 +#endif
    5.27 +
    5.28 +#ifdef __KERNEL__
    5.29 +#include <linux/config.h>
    5.30 +#include <linux/kernel.h>
    5.31 +
    5.32 +#ifdef DEBUG
    5.33 +
    5.34 +#define dprintf(fmt, args...) printk(KERN_DEBUG   "[DBG] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
    5.35 +#define wprintf(fmt, args...) printk(KERN_WARNING "[WRN] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
    5.36 +#define iprintf(fmt, args...) printk(KERN_INFO    "[INF] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
    5.37 +#define eprintf(fmt, args...) printk(KERN_ERR     "[ERR] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
    5.38 +
    5.39 +#else
    5.40 +
    5.41 +#define dprintf(fmt, args...) do {} while(0)
    5.42 +#define wprintf(fmt, args...) printk(KERN_WARNING "[WRN] " MODULE_NAME fmt, ##args)
    5.43 +#define iprintf(fmt, args...) printk(KERN_INFO    "[INF] " MODULE_NAME fmt, ##args)
    5.44 +#define eprintf(fmt, args...) printk(KERN_ERR     "[ERR] " MODULE_NAME fmt, ##args)
    5.45 +
    5.46 +#endif
    5.47 +
    5.48 +#else
    5.49 +
    5.50 +#include <stdio.h>
    5.51 +
    5.52 +#ifdef DEBUG
    5.53 +
    5.54 +#define dprintf(fmt, args...) fprintf(stdout, "[DBG] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
    5.55 +#define wprintf(fmt, args...) fprintf(stderr, "[WRN] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
    5.56 +#define iprintf(fmt, args...) fprintf(stderr, "[INF] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
    5.57 +#define eprintf(fmt, args...) fprintf(stderr, "[ERR] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
    5.58 +
    5.59 +#else
    5.60 +
    5.61 +#define dprintf(fmt, args...) do {} while(0)
    5.62 +#define wprintf(fmt, args...) fprintf(stderr, "[WRN] " MODULE_NAME fmt, ##args)
    5.63 +#define iprintf(fmt, args...) fprintf(stderr, "[INF] " MODULE_NAME fmt, ##args)
    5.64 +#define eprintf(fmt, args...) fprintf(stderr, "[ERR] " MODULE_NAME fmt, ##args)
    5.65 +
    5.66 +#endif
    5.67 +
    5.68 +#endif
    5.69 +
    5.70 +/** Print format for an IP address.
    5.71 + * See NIPQUAD(), HIPQUAD()
    5.72 + */
    5.73 +#define IPFMT "%u.%u.%u.%u"
    5.74 +
    5.75 +#endif /* ! _XEN_LIB_DEBUG_H_ */
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/tools/lib/enum.c	Mon Jun 28 15:03:15 2004 +0000
     6.3 @@ -0,0 +1,61 @@
     6.4 +/*
     6.5 + * Copyright (C) 2002, 2004 Mike Wray <mike.wray@hp.com>
     6.6 + *
     6.7 + * This library is free software; you can redistribute it and/or modify
     6.8 + * it under the terms of the GNU Lesser General Public License as
     6.9 + * published by the Free Software Foundation; either version 2.1 of the
    6.10 + * License, or  (at your option) any later version. This library is 
    6.11 + * distributed in the  hope that it will be useful, but WITHOUT ANY
    6.12 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or
    6.13 + * FITNESS FOR A PARTICULAR PURPOSE.
    6.14 + * See the GNU Lesser General Public License for more details.
    6.15 + *
    6.16 + * You should have received a copy of the GNU Lesser General Public License
    6.17 + * along with this library; if not, write to the Free Software Foundation,
    6.18 + * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
    6.19 + */
    6.20 +
    6.21 +#ifdef __KERNEL__
    6.22 +#include <linux/errno.h>
    6.23 +#else
    6.24 +#include <errno.h>
    6.25 +#endif
    6.26 +
    6.27 +#include "sys_string.h"
    6.28 +#include "enum.h"
    6.29 +
    6.30 +/** Map an enum name to its value using a table.
    6.31 + *
    6.32 + * @param name enum name
    6.33 + * @param defs enum definitions
    6.34 + * @return enum value or -1 if not known
    6.35 + */
    6.36 +int enum_name_to_val(char *name, EnumDef *defs){
    6.37 +    int val = -1;
    6.38 +    for(; defs->name; defs++){
    6.39 +	if(!strcmp(defs->name, name)){
    6.40 +	    val = defs->val;
    6.41 +	    break;
    6.42 +	}
    6.43 +    }
    6.44 +    return val;
    6.45 +}
    6.46 +
    6.47 +/** Map an enum value to its name using a table.
    6.48 + *
    6.49 + * @param val enum value
    6.50 + * @param defs enum definitions
    6.51 + * @param defs_n number of definitions
    6.52 + * @return enum name or NULL if not known
    6.53 + */
    6.54 +char *enum_val_to_name(int val, EnumDef *defs){
    6.55 +    char *name = NULL;
    6.56 +    for(; defs->name; defs++){
    6.57 +	if(val == defs->val){
    6.58 +	    name = defs->name;
    6.59 +	    break;
    6.60 +	}
    6.61 +    }
    6.62 +    return name;
    6.63 +}
    6.64 +
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/tools/lib/enum.h	Mon Jun 28 15:03:15 2004 +0000
     7.3 @@ -0,0 +1,30 @@
     7.4 +/*
     7.5 + * Copyright (C) 2002, 2004 Mike Wray <mike.wray@hp.com>
     7.6 + *
     7.7 + * This library is free software; you can redistribute it and/or modify
     7.8 + * it under the terms of the GNU Lesser General Public License as
     7.9 + * published by the Free Software Foundation; either version 2.1 of the
    7.10 + * License, or  (at your option) any later version. This library is 
    7.11 + * distributed in the  hope that it will be useful, but WITHOUT ANY
    7.12 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or
    7.13 + * FITNESS FOR A PARTICULAR PURPOSE.
    7.14 + * See the GNU Lesser General Public License for more details.
    7.15 + *
    7.16 + * You should have received a copy of the GNU Lesser General Public License
    7.17 + * along with this library; if not, write to the Free Software Foundation,
    7.18 + * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
    7.19 + */
    7.20 +
    7.21 +#ifndef _XEN_LIB_ENUM_H_
    7.22 +#define _XEN_LIB_ENUM_H_
    7.23 +
    7.24 +/** Mapping of an enum value to a name. */
    7.25 +typedef struct EnumDef {
    7.26 +    int val;
    7.27 +    char *name;
    7.28 +} EnumDef;
    7.29 +
    7.30 +extern int enum_name_to_val(char *name, EnumDef *defs);
    7.31 +extern char *enum_val_to_name(int val, EnumDef *defs);
    7.32 +
    7.33 +#endif /* _XEN_LIB_ENUM_H_ */
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/tools/lib/file_stream.c	Mon Jun 28 15:03:15 2004 +0000
     8.3 @@ -0,0 +1,202 @@
     8.4 +/*
     8.5 + * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
     8.6 + *
     8.7 + * This library is free software; you can redistribute it and/or modify
     8.8 + * it under the terms of the GNU Lesser General Public License as published by
     8.9 + * the Free Software Foundation; either version 2.1 of the License, or
    8.10 + * (at your option) any later version.
    8.11 + *
    8.12 + * This library is distributed in the hope that it will be useful,
    8.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    8.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    8.15 + * GNU Lesser General Public License for more details.
    8.16 + *
    8.17 + * You should have received a copy of the GNU Lesser General Public License
    8.18 + * along with this library; if not, write to the Free Software
    8.19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    8.20 + */
    8.21 +
    8.22 +/** @file
    8.23 + * An IOStream implementation using FILE*.
    8.24 + */
    8.25 +#ifndef __KERNEL__
    8.26 +#include <stdio.h>
    8.27 +#include <stdlib.h>
    8.28 +#include "allocate.h"
    8.29 +#include "file_stream.h"
    8.30 +
    8.31 +static int file_read(IOStream *s, void *buf, size_t n);
    8.32 +static int file_write(IOStream *s, const void *buf, size_t n);
    8.33 +static int file_error(IOStream *s);
    8.34 +static int file_close(IOStream *s);
    8.35 +static void file_free(IOStream *s);
    8.36 +static int file_flush(IOStream *s);
    8.37 +
    8.38 +/** Methods used by a FILE* IOStream. */
    8.39 +static const IOMethods file_methods = {
    8.40 +    read:  file_read,
    8.41 +    write: file_write,
    8.42 +    error: file_error,
    8.43 +    close: file_close,
    8.44 +    free:  file_free,
    8.45 +    flush: file_flush,
    8.46 +};
    8.47 +
    8.48 +/** IOStream for stdin. */
    8.49 +static IOStream _iostdin = {
    8.50 +    methods: &file_methods,
    8.51 +    data: (void*)1,
    8.52 +};
    8.53 +
    8.54 +/** IOStream for stdout. */
    8.55 +static IOStream _iostdout = {
    8.56 +    methods: &file_methods,
    8.57 +    data: (void*)2,
    8.58 +};
    8.59 +
    8.60 +/** IOStream for stderr. */
    8.61 +static IOStream _iostderr = {
    8.62 +    methods: &file_methods,
    8.63 +    data: (void*)3,
    8.64 +};
    8.65 +
    8.66 +/** IOStream for stdin. */
    8.67 +IOStream *iostdin = &_iostdin;
    8.68 +
    8.69 +/** IOStream for stdout. */
    8.70 +IOStream *iostdout = &_iostdout;
    8.71 +
    8.72 +/** IOStream for stderr. */
    8.73 +IOStream *iostderr = &_iostderr;
    8.74 +
    8.75 +/** Get the underlying FILE*.
    8.76 + * 
    8.77 + * @param s file stream
    8.78 + * @return the stream s wraps
    8.79 + */
    8.80 +static inline FILE *get_file(IOStream *s){
    8.81 +    switch((long)s->data){
    8.82 +    case 1: s->data = stdin; break;
    8.83 +    case 2: s->data = stdout; break;
    8.84 +    case 3: s->data = stderr; break;
    8.85 +    }
    8.86 +    return (FILE*)s->data;
    8.87 +}
    8.88 +
    8.89 +/** Control buffering on the underlying stream, like setvbuf().
    8.90 + *
    8.91 + * @param io file stream
    8.92 + * @param buf buffer
    8.93 + * @param mode buffering mode (see man setvbuf())
    8.94 + * @param size buffer size
    8.95 + * @return 0 on success, non-zero otherwise
    8.96 + */
    8.97 +int file_stream_setvbuf(IOStream *io, char *buf, int mode, size_t size){
    8.98 +    return setvbuf(get_file(io), buf, mode, size);
    8.99 +}
   8.100 +
   8.101 +/** Write to the underlying stream using fwrite();
   8.102 + *
   8.103 + * @param stream input
   8.104 + * @param buf where to put input
   8.105 + * @param n number of bytes to write
   8.106 + * @return number of bytes written
   8.107 + */
   8.108 +static int file_write(IOStream *s, const void *buf, size_t n){
   8.109 +    return fwrite(buf, 1, n, get_file(s));
   8.110 +}
   8.111 +
   8.112 +/** Read from the underlying stream using fread();
   8.113 + *
   8.114 + * @param stream input
   8.115 + * @param buf where to put input
   8.116 + * @param n number of bytes to read
   8.117 + * @return number of bytes read
   8.118 + */
   8.119 +static int file_read(IOStream *s, void *buf, size_t n){
   8.120 +    return fread(buf, 1, n, get_file(s));
   8.121 +}
   8.122 +
   8.123 +/** Fush the underlying stream using fflush().
   8.124 + *
   8.125 + * @param s file stream
   8.126 + * @return 0 on success, error code otherwise
   8.127 + */
   8.128 +static int file_flush(IOStream *s){
   8.129 +    return fflush(get_file(s));
   8.130 +}
   8.131 +
   8.132 +/** Check if a stream has an error.
   8.133 + *
   8.134 + * @param s file stream
   8.135 + * @return 1 if has an error, 0 otherwise
   8.136 + */
   8.137 +static int file_error(IOStream *s){
   8.138 +    return ferror(get_file(s));
   8.139 +}
   8.140 +
   8.141 +/** Close a file stream.
   8.142 + *
   8.143 + * @param s file stream to close
   8.144 + * @return result of the close
   8.145 + */
   8.146 +static int file_close(IOStream *s){
   8.147 +    return fclose(get_file(s));
   8.148 +}
   8.149 +
   8.150 +/** Free a file stream.
   8.151 + *
   8.152 + * @param s file stream
   8.153 + */
   8.154 +static void file_free(IOStream *s){
   8.155 +    // Do nothing - fclose does it all?
   8.156 +}
   8.157 +
   8.158 +/** Create an IOStream for a stream.
   8.159 + *
   8.160 + * @param f stream to wrap
   8.161 + * @return new IOStream using f for i/o
   8.162 + */
   8.163 +IOStream *file_stream_new(FILE *f){
   8.164 +    IOStream *io = ALLOCATE(IOStream);
   8.165 +    if(io){
   8.166 +	io->methods = &file_methods;
   8.167 +	io->data = (void*)f;
   8.168 +    }
   8.169 +    return io;
   8.170 +}
   8.171 +
   8.172 +/** IOStream version of fopen().
   8.173 + *
   8.174 + * @param file name of the file to open
   8.175 + * @param flags giving the mode to open in (as for fopen())
   8.176 + * @return new stream for the open file, or 0 if failed
   8.177 + */
   8.178 +IOStream *file_stream_fopen(const char *file, const char *flags){
   8.179 +    IOStream *io = 0;
   8.180 +    FILE *fin = fopen(file, flags);
   8.181 +    if(fin){
   8.182 +	io = file_stream_new(fin);
   8.183 +	if(!io){
   8.184 +	    fclose(fin);
   8.185 +	    //free(fin); // fclose frees ?
   8.186 +	}
   8.187 +    }
   8.188 +    return io;
   8.189 +}
   8.190 +
   8.191 +/** IOStream version of fdopen().
   8.192 + *
   8.193 + * @param fd file descriptor
   8.194 + * @param flags giving the mode to open in (as for fdopen())
   8.195 + * @return new stream for the open file, or 0 if failed
   8.196 + */
   8.197 +IOStream *file_stream_fdopen(int fd, const char *flags){
   8.198 +    IOStream *io = 0;
   8.199 +    FILE *fin = fdopen(fd, flags);
   8.200 +    if(fin){
   8.201 +	io = file_stream_new(fin);
   8.202 +    }
   8.203 +    return io;
   8.204 +}
   8.205 +#endif
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/tools/lib/file_stream.h	Mon Jun 28 15:03:15 2004 +0000
     9.3 @@ -0,0 +1,35 @@
     9.4 +/*
     9.5 + * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
     9.6 + *
     9.7 + * This library is free software; you can redistribute it and/or modify
     9.8 + * it under the terms of the GNU Lesser General Public License as published by
     9.9 + * the Free Software Foundation; either version 2.1 of the License, or
    9.10 + * (at your option) any later version.
    9.11 + *
    9.12 + * This library is distributed in the hope that it will be useful,
    9.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    9.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    9.15 + * GNU Lesser General Public License for more details.
    9.16 + *
    9.17 + * You should have received a copy of the GNU Lesser General Public License
    9.18 + * along with this library; if not, write to the Free Software
    9.19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    9.20 + */
    9.21 +
    9.22 +#ifndef _XEN_LIB_FILE_STREAM_H_
    9.23 +#define _XEN_LIB_FILE_STREAM_H_
    9.24 +
    9.25 +#ifndef __KERNEL__
    9.26 +#include "iostream.h"
    9.27 +#include <stdio.h>
    9.28 +
    9.29 +extern IOStream *file_stream_new(FILE *f);
    9.30 +extern IOStream *file_stream_fopen(const char *file, const char *flags);
    9.31 +extern IOStream *file_stream_fdopen(int fd, const char *flags);
    9.32 +extern IOStream get_stream_stdout(void);
    9.33 +extern IOStream get_stream_stderr(void);
    9.34 +extern IOStream get_stream_stdin(void);
    9.35 +
    9.36 +extern int file_stream_setvbuf(IOStream *io, char *buf, int mode, size_t size);
    9.37 +#endif
    9.38 +#endif /* !_XEN_LIB_FILE_STREAM_H_ */
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/tools/lib/gzip_stream.c	Mon Jun 28 15:03:15 2004 +0000
    10.3 @@ -0,0 +1,185 @@
    10.4 +/* $Id: gzip_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $ */
    10.5 +/*
    10.6 + * Copyright (C) 2003 Hewlett-Packard Company.
    10.7 + *
    10.8 + * This library is free software; you can redistribute it and/or modify
    10.9 + * it under the terms of the GNU Lesser General Public License as published by
   10.10 + * the Free Software Foundation; either version 2.1 of the License, or
   10.11 + * (at your option) any later version.
   10.12 + *
   10.13 + * This library is distributed in the hope that it will be useful,
   10.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   10.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   10.16 + * GNU Lesser General Public License for more details.
   10.17 + *
   10.18 + * You should have received a copy of the GNU Lesser General Public License
   10.19 + * along with this library; if not, write to the Free Software
   10.20 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   10.21 + */
   10.22 +
   10.23 +/** @file
   10.24 + * An IOStream implementation using zlib gzFile to provide
   10.25 + * compression and decompression.
   10.26 + */
   10.27 +#ifndef __KERNEL__
   10.28 +
   10.29 +#include <stdio.h>
   10.30 +#include <stdlib.h>
   10.31 +
   10.32 +#include "zlib.h"
   10.33 +
   10.34 +extern FILE* gzfile(gzFile file);
   10.35 +
   10.36 +#include "allocate.h"
   10.37 +#include "gzip_stream.h"
   10.38 +
   10.39 +static int gzip_read(IOStream *s, void *buf, size_t n);
   10.40 +static int gzip_write(IOStream *s, const void *buf, size_t n);
   10.41 +static int gzip_error(IOStream *s);
   10.42 +static int gzip_close(IOStream *s);
   10.43 +static void gzip_free(IOStream *s);
   10.44 +static int gzip_flush(IOStream *s);
   10.45 +
   10.46 +/** Methods used by a gzFile* IOStream. */
   10.47 +static const IOMethods gzip_methods = {
   10.48 +    read: gzip_read,
   10.49 +    write: gzip_write,
   10.50 +    error: gzip_error,
   10.51 +    close: gzip_close,
   10.52 +    free:  gzip_free,
   10.53 +    flush: gzip_flush,
   10.54 +};
   10.55 +
   10.56 +/** Get the underlying gzFile*.
   10.57 + * 
   10.58 + * @param s gzip stream
   10.59 + * @return the stream s wraps
   10.60 + */
   10.61 +static inline gzFile get_gzfile(IOStream *s){
   10.62 +    return (gzFile)s->data;
   10.63 +}
   10.64 +
   10.65 +/** Control buffering on the underlying stream, like setvbuf().
   10.66 + *
   10.67 + * @param io gzip stream
   10.68 + * @param buf buffer
   10.69 + * @param mode buffering mode (see man setvbuf())
   10.70 + * @param size buffer size
   10.71 + * @return 0 on success, non-zero otherwise
   10.72 + */
   10.73 +int gzip_stream_setvbuf(IOStream *io, char *buf, int mode, size_t size){
   10.74 +    return setvbuf(gzfile(get_gzfile(io)), buf, mode, size);
   10.75 +}
   10.76 +
   10.77 +/** Write to the underlying stream.
   10.78 + *
   10.79 + * @param stream destination
   10.80 + * @param buf data
   10.81 + * @param n number of bytes to write
   10.82 + * @return number of bytes written
   10.83 + */
   10.84 +static int gzip_write(IOStream *s, const void *buf, size_t n){
   10.85 +    return gzwrite(get_gzfile(s), (void*)buf, n);
   10.86 +}
   10.87 +
   10.88 +/** Read from the underlying stream.
   10.89 + *
   10.90 + * @param stream input
   10.91 + * @param buf where to put input
   10.92 + * @param n number of bytes to read
   10.93 + * @return number of bytes read
   10.94 + */
   10.95 +static int gzip_read(IOStream *s, void *buf, size_t n){
   10.96 +    return gzread(get_gzfile(s), buf, n);
   10.97 +}
   10.98 +
   10.99 +/** Flush the underlying stream.
  10.100 + *
  10.101 + * @param s gzip stream
  10.102 + * @return 0 on success, error code otherwise
  10.103 + */
  10.104 +static int gzip_flush(IOStream *s){
  10.105 +    //return gzflush(get_gzfile(s), Z_NO_FLUSH);
  10.106 +    return gzflush(get_gzfile(s), Z_SYNC_FLUSH);
  10.107 +    //return gzflush(get_gzfile(s), Z_FULL_FLUSH);
  10.108 +}
  10.109 +
  10.110 +/** Check if a stream has an error.
  10.111 + *
  10.112 + * @param s gzip stream
  10.113 + * @return 1 if has an error, 0 otherwise
  10.114 + */
  10.115 +static int gzip_error(IOStream *s){
  10.116 +    int err;
  10.117 +    gzFile *gz = get_gzfile(s);
  10.118 +    gzerror(gz, &err);
  10.119 +    return (err == Z_ERRNO ? ferror(gzfile(gz)) : err);
  10.120 +}
  10.121 +
  10.122 +/** Close a gzip stream.
  10.123 + *
  10.124 + * @param s gzip stream to close
  10.125 + * @return result of the close
  10.126 + */
  10.127 +static int gzip_close(IOStream *s){
  10.128 +    return gzclose(get_gzfile(s));
  10.129 +}
  10.130 +
  10.131 +/** Free a gzip stream.
  10.132 + *
  10.133 + * @param s gzip stream
  10.134 + */
  10.135 +static void gzip_free(IOStream *s){
  10.136 +    // Do nothing - fclose does it all?
  10.137 +}
  10.138 +
  10.139 +/** Create an IOStream for a gzip stream.
  10.140 + *
  10.141 + * @param f stream to wrap
  10.142 + * @return new IOStream using f for i/o
  10.143 + */
  10.144 +IOStream *gzip_stream_new(gzFile *f){
  10.145 +    IOStream *io = ALLOCATE(IOStream);
  10.146 +    if(io){
  10.147 +	io->methods = &gzip_methods;
  10.148 +	io->data = (void*)f;
  10.149 +    }
  10.150 +    return io;
  10.151 +}
  10.152 +
  10.153 +/** IOStream version of fopen().
  10.154 + *
  10.155 + * @param file name of the file to open
  10.156 + * @param flags giving the mode to open in (as for fopen())
  10.157 + * @return new stream for the open file, or NULL if failed
  10.158 + */
  10.159 +IOStream *gzip_stream_fopen(const char *file, const char *flags){
  10.160 +    IOStream *io = NULL;
  10.161 +    gzFile *fgz;
  10.162 +    fgz = gzopen(file, flags);
  10.163 +    if(fgz){
  10.164 +	io = gzip_stream_new(fgz);
  10.165 +	if(!io){
  10.166 +	    gzclose(fgz);
  10.167 +	    //free(fgz); // gzclose frees ?
  10.168 +	}
  10.169 +    }
  10.170 +    return io;
  10.171 +}
  10.172 +
  10.173 +/** IOStream version of fdopen().
  10.174 + *
  10.175 + * @param fd file descriptor
  10.176 + * @param flags giving the mode to open in (as for fdopen())
  10.177 + * @return new stream for the open file, or NULL if failed
  10.178 + */
  10.179 +IOStream *gzip_stream_fdopen(int fd, const char *flags){
  10.180 +    IOStream *io = NULL;
  10.181 +    gzFile *fgz;
  10.182 +    fgz = gzdopen(fd, flags);
  10.183 +    if(fgz){
  10.184 +	io = gzip_stream_new(fgz);
  10.185 +    }
  10.186 +    return io;
  10.187 +}
  10.188 +#endif
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/tools/lib/gzip_stream.h	Mon Jun 28 15:03:15 2004 +0000
    11.3 @@ -0,0 +1,33 @@
    11.4 +#/* $Id: gzip_stream.h,v 1.3 2003/09/30 15:22:53 mjw Exp $ */
    11.5 +/*
    11.6 + * Copyright (C) 2003 Hewlett-Packard Company.
    11.7 + *
    11.8 + * This library is free software; you can redistribute it and/or modify
    11.9 + * it under the terms of the GNU Lesser General Public License as published by
   11.10 + * the Free Software Foundation; either version 2.1 of the License, or
   11.11 + * (at your option) any later version.
   11.12 + *
   11.13 + * This library is distributed in the hope that it will be useful,
   11.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   11.16 + * GNU Lesser General Public License for more details.
   11.17 + *
   11.18 + * You should have received a copy of the GNU Lesser General Public License
   11.19 + * along with this library; if not, write to the Free Software
   11.20 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   11.21 + */
   11.22 +
   11.23 +#ifndef _SP_GZIP_STREAM_H_
   11.24 +#define _SP_GZIP_STREAM_H_
   11.25 +
   11.26 +#ifndef __KERNEL__
   11.27 +#include "iostream.h"
   11.28 +#include "zlib.h"
   11.29 +
   11.30 +extern IOStream *gzip_stream_new(gzFile *f);
   11.31 +extern IOStream *gzip_stream_fopen(const char *file, const char *flags);
   11.32 +extern IOStream *gzip_stream_fdopen(int fd, const char *flags);
   11.33 +
   11.34 +extern int gzip_stream_setvbuf(IOStream *io, char *buf, int mode, size_t size);
   11.35 +#endif
   11.36 +#endif /* !_SP_FILE_STREAM_H_ */
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/tools/lib/hash_table.c	Mon Jun 28 15:03:15 2004 +0000
    12.3 @@ -0,0 +1,640 @@
    12.4 +/*
    12.5 + * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
    12.6 + *
    12.7 + * This library is free software; you can redistribute it and/or modify
    12.8 + * it under the terms of the GNU Lesser General Public License as published by
    12.9 + * the Free Software Foundation; either version 2.1 of the License, or
   12.10 + * (at your option) any later version.
   12.11 + *
   12.12 + * This library is distributed in the hope that it will be useful,
   12.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   12.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12.15 + * GNU Lesser General Public License for more details.
   12.16 + *
   12.17 + * You should have received a copy of the GNU Lesser General Public License
   12.18 + * along with this library; if not, write to the Free Software
   12.19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   12.20 + */
   12.21 +
   12.22 +#ifdef __KERNEL__
   12.23 +#  include <linux/config.h>
   12.24 +#  include <linux/module.h>
   12.25 +#  include <linux/kernel.h>
   12.26 +#  include <linux/errno.h>
   12.27 +#else
   12.28 +#  include <errno.h>
   12.29 +#  include <stddef.h>
   12.30 +#endif
   12.31 +
   12.32 +//#include <limits.h>
   12.33 +
   12.34 +#include "allocate.h"
   12.35 +#include "hash_table.h"
   12.36 +
   12.37 +/** @file
   12.38 + * Base support for hashtables.
   12.39 + *
   12.40 + * Hash codes are reduced modulo the number of buckets to index tables,
   12.41 + * so there is no need for hash functions to limit the range of hashcodes.
   12.42 + * In fact it is assumed that hashcodes do not change when the number of
   12.43 + * buckets in the table changes.
   12.44 + */
   12.45 +
   12.46 +/*==========================================================================*/
   12.47 +/** Number of bits in half a word. */
   12.48 +//#if __WORDSIZE == 64
   12.49 +//#define HALF_WORD_BITS 32
   12.50 +//#else
   12.51 +#define HALF_WORD_BITS 16
   12.52 +//#endif
   12.53 +
   12.54 +/** Mask for lo half of a word. On 32-bit this is 
   12.55 + * (1<<16) - 1 = 65535 = 0xffff
   12.56 + * It's 4294967295 = 0xffffffff on 64-bit.
   12.57 + */
   12.58 +#define LO_HALF_MASK ((1 << HALF_WORD_BITS) - 1)
   12.59 +
   12.60 +/** Get the lo half of a word. */
   12.61 +#define LO_HALF(x) ((x) & LO_HALF_MASK)
   12.62 +
   12.63 +/** Get the hi half of a word. */
   12.64 +#define HI_HALF(x) ((x) >> HALF_WORD_BITS)
   12.65 +
   12.66 +/** Do a full hash on both inputs, using DES-style non-linear scrambling.
   12.67 + * Both inputs are replaced with the results of the hash.
   12.68 + *
   12.69 + * @param pleft input/output word
   12.70 + * @param pright input/output word
   12.71 + */
   12.72 +void pseudo_des(unsigned long *pleft, unsigned long *pright){
   12.73 +    // Bit-rich mixing constant.
   12.74 +    static const unsigned long a_mixer[] = {
   12.75 +        0xbaa96887L, 0x1e17d32cL, 0x03bcdc3cL, 0x0f33d1b2L, };
   12.76 +
   12.77 +    // Bit-rich mixing constant.
   12.78 +    static const unsigned long b_mixer[] = {
   12.79 +        0x4b0f3b58L, 0xe874f0c3L, 0x6955c5a6L, 0x55a7ca46L, };
   12.80 +
   12.81 +    // Number of iterations - must be 2 or 4.
   12.82 +    static const int ncycle = 4;
   12.83 +    //static const int ncycle = 2;
   12.84 +
   12.85 +    unsigned long left = *pleft, right = *pright;
   12.86 +    unsigned long v, v_hi, v_lo;
   12.87 +    int i;
   12.88 +
   12.89 +    for(i=0; i<ncycle; i++){
   12.90 +        // Flip some bits in right to get v.
   12.91 +        v = right;
   12.92 +        v ^= a_mixer[i];
   12.93 +        // Get lo and hi halves of v.
   12.94 +        v_lo = LO_HALF(v);
   12.95 +        v_hi = HI_HALF(v);
   12.96 +        // Non-linear mix of the halves of v.
   12.97 +        v = ((v_lo * v_lo) + ~(v_hi * v_hi));
   12.98 +        // Swap the halves of v.
   12.99 +        v = (HI_HALF(v) | (LO_HALF(v) << HALF_WORD_BITS));
  12.100 +        // Flip some bits.
  12.101 +        v ^= b_mixer[i];
  12.102 +        // More non-linear mixing.
  12.103 +        v += (v_lo * v_hi);
  12.104 +        v ^= left;
  12.105 +        left = right;
  12.106 +        right = v;
  12.107 +    }
  12.108 +    *pleft = left;
  12.109 +    *pright = right;
  12.110 +}
  12.111 +
  12.112 +/** Hash a string.
  12.113 + *
  12.114 + * @param s input to hash
  12.115 + * @return hashcode
  12.116 + */
  12.117 +Hashcode hash_string(char *s){
  12.118 +    Hashcode h = 0;
  12.119 +    if(s){
  12.120 +        for( ; *s; s++){
  12.121 +            h = hash_2ul(h, *s);
  12.122 +        }
  12.123 +    }
  12.124 +    return h;
  12.125 +}
  12.126 +
  12.127 +/** Get the bucket for a hashcode in a hash table.
  12.128 + *
  12.129 + * @param table to get bucket from
  12.130 + * @param hashcode to get bucket for
  12.131 + * @return bucket
  12.132 + */
  12.133 +inline HTBucket * get_bucket(HashTable *table, Hashcode hashcode){
  12.134 +    return table->buckets + (hashcode % table->buckets_n);
  12.135 +}
  12.136 +
  12.137 +/** Initialize a hash table.
  12.138 + * Can be safely called more than once.
  12.139 + *
  12.140 + * @param table to initialize
  12.141 + */
  12.142 +void HashTable_init(HashTable *table){
  12.143 +    int i;
  12.144 +
  12.145 +    if(!table->init_done){
  12.146 +        table->init_done = 1;
  12.147 +        table->next_id = 0;
  12.148 +        for(i=0; i<table->buckets_n; i++){
  12.149 +            HTBucket *bucket = get_bucket(table, i);
  12.150 +            bucket->head = 0;
  12.151 +            bucket->count = 0;
  12.152 +        }
  12.153 +        table->entry_count = 0;
  12.154 +    }
  12.155 +}
  12.156 +
  12.157 +/** Allocate a new hashtable.
  12.158 + * If the number of buckets is not positive the default is used.
  12.159 + * The number of buckets should usually be prime.
  12.160 + *
  12.161 + * @param buckets_n number of buckets
  12.162 + * @return new hashtable or null
  12.163 + */
  12.164 +HashTable *HashTable_new(int buckets_n){
  12.165 +    HashTable *z = ALLOCATE(HashTable);
  12.166 +    if(!z) goto exit;
  12.167 +    if(buckets_n <= 0){
  12.168 +        buckets_n = HT_BUCKETS_N;
  12.169 +    }
  12.170 +    z->buckets = (HTBucket*)allocate(buckets_n * sizeof(HTBucket));
  12.171 +    if(!z->buckets){
  12.172 +        deallocate(z);
  12.173 +        z = 0;
  12.174 +        goto exit;
  12.175 +    }
  12.176 +    z->buckets_n = buckets_n;
  12.177 +    HashTable_init(z);
  12.178 +  exit:
  12.179 +    return z;
  12.180 +}
  12.181 +
  12.182 +/** Free a hashtable.
  12.183 + * Any entries are removed and freed.
  12.184 + *
  12.185 + * @param h hashtable (ignored if null)
  12.186 + */
  12.187 +void HashTable_free(HashTable *h){
  12.188 +    if(h){
  12.189 +        HashTable_clear(h);
  12.190 +        deallocate(h->buckets);
  12.191 +        deallocate(h);
  12.192 +    }
  12.193 +}
  12.194 +
  12.195 +/** Push an entry on the list in the bucket for a given hashcode.
  12.196 + *
  12.197 + * @param table to add entry to
  12.198 + * @param hashcode for the entry
  12.199 + * @param entry to add
  12.200 + */
  12.201 +static inline void push_on_bucket(HashTable *table, Hashcode hashcode,
  12.202 +				  HTEntry *entry){
  12.203 +    HTBucket *bucket;
  12.204 +    HTEntry *old_head;
  12.205 +
  12.206 +    bucket = get_bucket(table, hashcode);
  12.207 +    old_head = bucket->head;
  12.208 +    bucket->count++;
  12.209 +    bucket->head = entry;
  12.210 +    entry->next = old_head;
  12.211 +}
  12.212 +
  12.213 +/** Change the number of buckets in a hashtable.
  12.214 + * No-op if the number of buckets is not positive.
  12.215 + * Existing entries are reallocated to buckets based on their hashcodes.
  12.216 + * The table is unmodified if the number of buckets cannot be changed.
  12.217 + *
  12.218 + * @param table hashtable
  12.219 + * @param buckets_n new number of buckets
  12.220 + * @return 0 on success, error code otherwise
  12.221 + */
  12.222 +int HashTable_set_buckets_n(HashTable *table, int buckets_n){
  12.223 +    int err = 0;
  12.224 +    HTBucket *old_buckets = table->buckets;
  12.225 +    int old_buckets_n = table->buckets_n;
  12.226 +    int i;
  12.227 +
  12.228 +    if(buckets_n <= 0){
  12.229 +        err = -EINVAL;
  12.230 +        goto exit;
  12.231 +    }
  12.232 +    table->buckets = (HTBucket*)allocate(buckets_n * sizeof(HTBucket));
  12.233 +    if(!table->buckets){
  12.234 +        err = -ENOMEM;
  12.235 +        table->buckets = old_buckets;
  12.236 +        goto exit;
  12.237 +    }
  12.238 +    table->buckets_n = buckets_n;
  12.239 +    for(i=0; i<old_buckets_n; i++){
  12.240 +        HTBucket *bucket = old_buckets + i;
  12.241 +        HTEntry *entry, *next;
  12.242 +        for(entry = bucket->head; entry; entry = next){
  12.243 +            next = entry->next;
  12.244 +            push_on_bucket(table, entry->hashcode, entry);
  12.245 +        }
  12.246 +    }
  12.247 +    deallocate(old_buckets);
  12.248 +  exit:
  12.249 +    return err;
  12.250 +}
  12.251 +
  12.252 +/** Adjust the number of buckets so the table is neither too full nor too empty.
  12.253 + * The table is unmodified if adjusting fails.
  12.254 + *
  12.255 + * @param table hash table
  12.256 + * @param buckets_min minimum number of buckets (use default if 0 or negative)
  12.257 + * @return 0 on success, error code otherwise
  12.258 + */
  12.259 +int HashTable_adjust(HashTable *table, int buckets_min){
  12.260 +    int buckets_n = 0;
  12.261 +    int err = 0;
  12.262 +    if(buckets_min <= 0) buckets_min = HT_BUCKETS_N;
  12.263 +    if(table->entry_count >= table->buckets_n){
  12.264 +        // The table is dense - expand it.
  12.265 +        buckets_n = 2 * table->buckets_n;
  12.266 +    } else if((table->buckets_n > buckets_min) &&
  12.267 +              (4 * table->entry_count < table->buckets_n)){
  12.268 +        // The table is more than minimum size and sparse - shrink it.
  12.269 +        buckets_n = 2 * table->entry_count;
  12.270 +        if(buckets_n < buckets_min) buckets_n = buckets_min;
  12.271 +    }
  12.272 +    if(buckets_n){
  12.273 +        err = HashTable_set_buckets_n(table, buckets_n);
  12.274 +    }
  12.275 +    return err;
  12.276 +}
  12.277 +
  12.278 +/** Allocate a new entry for a given value.
  12.279 + *
  12.280 + * @param value to put in the entry
  12.281 + * @return entry, or 0 on failure
  12.282 + */
  12.283 +HTEntry * HTEntry_new(Hashcode hashcode, void *key, void *value){
  12.284 +    HTEntry *z = ALLOCATE(HTEntry);
  12.285 +    if(z){
  12.286 +        z->hashcode = hashcode;
  12.287 +        z->key = key;
  12.288 +        z->value = value;
  12.289 +    }
  12.290 +    return z;
  12.291 +}
  12.292 +
  12.293 +/** Free an entry.
  12.294 + *
  12.295 + * @param z entry to free
  12.296 + */
  12.297 +inline void HTEntry_free(HTEntry *z){
  12.298 +    if(z){
  12.299 +        deallocate(z);
  12.300 +    }
  12.301 +}
  12.302 +
  12.303 +/** Free an entry in a hashtable.
  12.304 + * The table's entry_free_fn is used is defined, otherwise 
  12.305 + * the HTEntry itself is freed.
  12.306 + *
  12.307 + * @param table hashtable
  12.308 + * @param entry to free
  12.309 + */
  12.310 +inline void HashTable_free_entry(HashTable *table, HTEntry *entry){
  12.311 +    if(!entry)return;
  12.312 +    if(table && table->entry_free_fn){
  12.313 +        table->entry_free_fn(table, entry);
  12.314 +    } else {
  12.315 +        HTEntry_free(entry);
  12.316 +    }
  12.317 +}
  12.318 +
  12.319 +/** Get the first entry satisfying a test from the bucket for the
  12.320 + * given hashcode.
  12.321 + *
  12.322 + * @param table to look in
  12.323 + * @param hashcode indicates the bucket
  12.324 + * @param test_fn test to apply to elements
  12.325 + * @param arg first argument to calls to test_fn
  12.326 + * @return entry found, or 0
  12.327 + */
  12.328 +inline HTEntry * HashTable_find_entry(HashTable *table, Hashcode hashcode,
  12.329 +				      TableTestFn *test_fn, TableArg arg){
  12.330 +    HTBucket *bucket;
  12.331 +    HTEntry *entry = 0;
  12.332 +    HTEntry *next;
  12.333 +
  12.334 +    bucket = get_bucket(table, hashcode);
  12.335 +    for(entry = bucket->head; entry; entry = next){
  12.336 +        next = entry->next;
  12.337 +        if(test_fn(arg, table, entry)){
  12.338 +            break;
  12.339 +        }
  12.340 +    }
  12.341 +    return entry;
  12.342 +}
  12.343 +
  12.344 +/** Test hashtable keys for equality.
  12.345 + * Uses the table's key_equal_fn if defined, otherwise pointer equality.
  12.346 + *
  12.347 + * @param key1 key to compare
  12.348 + * @param key2 key to compare
  12.349 + * @return 1 if equal, 0 otherwise
  12.350 + */
  12.351 +inline int HashTable_key_equal(HashTable *table, void *key1, void *key2){
  12.352 +    return (table->key_equal_fn ? table->key_equal_fn(key1, key2) : key1==key2);
  12.353 +}
  12.354 +
  12.355 +/** Compute the hashcode of a hashtable key.
  12.356 + * The table's key_hash_fn is used if defined, otherwise the address of
  12.357 + * the key is hashed.
  12.358 + *
  12.359 + * @param table hashtable
  12.360 + * @param key to hash
  12.361 + * @return hashcode
  12.362 + */
  12.363 +inline Hashcode HashTable_key_hash(HashTable *table, void *key){
  12.364 +    return (table->key_hash_fn ? table->key_hash_fn(key) : hash_ul((unsigned long)key));
  12.365 +}
  12.366 +
  12.367 +/** Test if an entry has a given key.
  12.368 + *
  12.369 + * @param arg containing key to test for
  12.370 + * @param table the entry is in
  12.371 + * @param entry to test
  12.372 + * @return 1 if the entry has the key, 0 otherwise
  12.373 + */
  12.374 +static inline int has_key(TableArg arg, HashTable *table, HTEntry *entry){
  12.375 +    return HashTable_key_equal(table, arg.ptr, entry->key);
  12.376 +}
  12.377 +
  12.378 +/** Get an entry with a given key.
  12.379 + *
  12.380 + * @param table to search
  12.381 + * @param key to look for
  12.382 + * @return entry if found, null otherwise
  12.383 + */
  12.384 +#if 0
  12.385 +inline HTEntry * HashTable_get_entry(HashTable *table, void *key){
  12.386 +    TableArg arg = { ptr: key };
  12.387 +    return HashTable_find_entry(table, HashTable_key_hash(table, key), has_key, arg);
  12.388 +}
  12.389 +#else
  12.390 +inline HTEntry * HashTable_get_entry(HashTable *table, void *key){
  12.391 +    Hashcode hashcode;
  12.392 +    HTBucket *bucket;
  12.393 +    HTEntry *entry = 0;
  12.394 +    HTEntry *next;
  12.395 +
  12.396 +    hashcode = HashTable_key_hash(table, key);
  12.397 +    bucket = get_bucket(table, hashcode);
  12.398 +    for(entry = bucket->head; entry; entry = next){
  12.399 +        next = entry->next;
  12.400 +        if(HashTable_key_equal(table, key, entry->key)){
  12.401 +            break;
  12.402 +        }
  12.403 +    }
  12.404 +    return entry;
  12.405 +}
  12.406 +#endif
  12.407 +
  12.408 +/** Get the value of an entry with a given key.
  12.409 + *
  12.410 + * @param table to search
  12.411 + * @param key to look for
  12.412 + * @return value if an entry was found, null otherwise
  12.413 + */
  12.414 +inline void * HashTable_get(HashTable *table, void *key){
  12.415 +    HTEntry *entry = HashTable_get_entry(table, key);
  12.416 +    return (entry ? entry->value : 0);
  12.417 +}
  12.418 +
  12.419 +/** Print the buckets in a table.
  12.420 + *
  12.421 + * @param table to print
  12.422 + */
  12.423 +void show_buckets(HashTable *table, IOStream *io){
  12.424 +    int i,j ;
  12.425 +    IOStream_print(io, "entry_count=%d buckets_n=%d\n", table->entry_count, table->buckets_n);
  12.426 +    for(i=0; i<table->buckets_n; i++){
  12.427 +        if(0 || table->buckets[i].count>0){
  12.428 +            IOStream_print(io, "bucket %3d %3d %10p ", i,
  12.429 +                        table->buckets[i].count,
  12.430 +                        table->buckets[i].head);
  12.431 +            for(j = table->buckets[i].count; j>0; j--){
  12.432 +                IOStream_print(io, "+");
  12.433 +            }
  12.434 +            IOStream_print(io, "\n");
  12.435 +        }
  12.436 +    }
  12.437 +    HashTable_print(table, io); 
  12.438 +}
  12.439 +    
  12.440 +/** Print an entry in a table.
  12.441 + *
  12.442 + * @param entry to print
  12.443 + * @param arg a pointer to an IOStream to print to
  12.444 + * @return 0
  12.445 + */
  12.446 +static int print_entry(TableArg arg, HashTable *table, HTEntry *entry){
  12.447 +    IOStream *io = (IOStream*)arg.ptr;
  12.448 +    IOStream_print(io, " b=%4lx h=%08lx i=%08lx |-> e=%8p k=%8p v=%8p\n",
  12.449 +                entry->hashcode % table->buckets_n,
  12.450 +                entry->hashcode,
  12.451 +                entry->index,
  12.452 +                entry, entry->key, entry->value);
  12.453 +    return 0;
  12.454 +}
  12.455 +
  12.456 +/** Print a hash table.
  12.457 + *
  12.458 + * @param table to print
  12.459 + */
  12.460 +void HashTable_print(HashTable *table, IOStream *io){
  12.461 +    IOStream_print(io, "{\n");
  12.462 +    HashTable_map(table, print_entry, (TableArg){ ptr: io });
  12.463 +    IOStream_print(io, "}\n");
  12.464 +}
  12.465 +/*==========================================================================*/
  12.466 +
  12.467 +/** Get the next entry id to use for a table.
  12.468 + *
  12.469 + * @param table hash table
  12.470 + * @return non-zero entry id
  12.471 + */
  12.472 +static inline unsigned long get_next_id(HashTable *table){
  12.473 +    unsigned long id;
  12.474 +
  12.475 +    if(table->next_id == 0){
  12.476 +        table->next_id = 1;
  12.477 +    }
  12.478 +    id = table->next_id++;
  12.479 +    return id;
  12.480 +}
  12.481 +
  12.482 +/** Add an entry to the bucket for the
  12.483 + * given hashcode.
  12.484 + *
  12.485 + * @param table to insert in
  12.486 + * @param hashcode indicates the bucket
  12.487 + * @param key to add an entry for
  12.488 + * @param value to add an entry for
  12.489 + * @return entry on success, 0 on failure
  12.490 + */
  12.491 +inline HTEntry * HashTable_add_entry(HashTable *table, Hashcode hashcode, void *key, void *value){
  12.492 +    HTEntry *entry = HTEntry_new(hashcode, key, value);
  12.493 +    if(entry){
  12.494 +        entry->index = get_next_id(table);
  12.495 +        push_on_bucket(table, hashcode, entry);
  12.496 +        table->entry_count++;
  12.497 +    }
  12.498 +    return entry;
  12.499 +}
  12.500 +
  12.501 +/** Move the front entry for a bucket to the correct point in the bucket order as
  12.502 + * defined by the order function. If this is called every time a new entry is added
  12.503 + * the bucket will be maintained in sorted order.
  12.504 + *
  12.505 + * @param table to modify
  12.506 + * @param hashcode indicates the bucket
  12.507 + * @param order entry comparison function
  12.508 + * @return 0 if an entry was moved, 1 if not
  12.509 + */
  12.510 +int HashTable_order_bucket(HashTable *table, Hashcode hashcode, TableOrderFn *order){
  12.511 +    HTEntry *new_entry = NULL, *prev = NULL, *entry = NULL;
  12.512 +    HTBucket *bucket;
  12.513 +    int err = 1;
  12.514 +
  12.515 +    bucket = get_bucket(table, hashcode);
  12.516 +    new_entry = bucket->head;
  12.517 +    if(!new_entry || !new_entry->next) goto exit;
  12.518 +    for(entry = new_entry->next; entry; prev = entry, entry = entry->next){
  12.519 +        if(order(new_entry, entry) <= 0) break;
  12.520 +    }
  12.521 +    if(prev){
  12.522 +        err = 0;
  12.523 +        bucket->head = new_entry->next; 
  12.524 +        new_entry->next = entry;
  12.525 +        prev->next = new_entry;
  12.526 +    }
  12.527 +  exit:
  12.528 +    return err;
  12.529 +}
  12.530 +
  12.531 +/** Add an entry to a hashtable.
  12.532 + * The entry is added to the bucket for its key's hashcode.
  12.533 + *
  12.534 + * @param table to insert in
  12.535 + * @param key to add an entry for
  12.536 + * @param value to add an entry for
  12.537 + * @return entry on success, 0 on failure
  12.538 + */
  12.539 +inline HTEntry * HashTable_add(HashTable *table, void *key, void *value){
  12.540 +    return HashTable_add_entry(table, HashTable_key_hash(table, key), key, value);
  12.541 +}
  12.542 +
  12.543 +
  12.544 +/** Remove entries satisfying a test from the bucket for the
  12.545 + * given hashcode. 
  12.546 + *
  12.547 + * @param table to remove from
  12.548 + * @param hashcode indicates the bucket
  12.549 + * @param test_fn test to apply to elements
  12.550 + * @param arg first argument to calls to test_fn
  12.551 + * @return number of entries removed
  12.552 + */
  12.553 +inline int HashTable_remove_entry(HashTable *table, Hashcode hashcode,
  12.554 +				  TableTestFn *test_fn, TableArg arg){
  12.555 +    HTBucket *bucket;
  12.556 +    HTEntry *entry, *prev = 0, *next;
  12.557 +    int removed_count = 0;
  12.558 +
  12.559 +    bucket = get_bucket(table, hashcode);
  12.560 +    for(entry = bucket->head; entry; entry = next){
  12.561 +        next = entry->next;
  12.562 +        if(test_fn(arg, table, entry)){
  12.563 +            if(prev){
  12.564 +                prev->next = next;
  12.565 +            } else {
  12.566 +                bucket->head = next;
  12.567 +            }
  12.568 +            bucket->count--;
  12.569 +            table->entry_count--;
  12.570 +            removed_count++;
  12.571 +            HashTable_free_entry(table, entry);
  12.572 +            entry = 0;
  12.573 +        }
  12.574 +        prev = entry;
  12.575 +    }
  12.576 +    return removed_count;
  12.577 +}
  12.578 +
  12.579 +/** Remove entries with a given key. 
  12.580 + *
  12.581 + * @param table to remove from
  12.582 + * @param key of entries to remove
  12.583 + * @return number of entries removed
  12.584 + */
  12.585 +inline int HashTable_remove(HashTable *table, void *key){
  12.586 +#if 1
  12.587 +    Hashcode hashcode;
  12.588 +    HTBucket *bucket;
  12.589 +    HTEntry *entry, *prev = 0, *next;
  12.590 +    int removed_count = 0;
  12.591 +
  12.592 +    hashcode = HashTable_key_hash(table, key);
  12.593 +    bucket = get_bucket(table, hashcode);
  12.594 +    for(entry = bucket->head; entry; entry = next){
  12.595 +        next = entry->next;
  12.596 +        if(HashTable_key_equal(table, key, entry->key)){
  12.597 +            if(prev){
  12.598 +                prev->next = next;
  12.599 +            } else {
  12.600 +                bucket->head = next;
  12.601 +            }
  12.602 +            bucket->count--;
  12.603 +            table->entry_count--;
  12.604 +            removed_count++;
  12.605 +            HashTable_free_entry(table, entry);
  12.606 +            entry = 0;
  12.607 +        }
  12.608 +        prev = entry;
  12.609 +    }
  12.610 +    return removed_count;
  12.611 +#else
  12.612 +    return HashTable_remove_entry(table, HashTable_key_hash(table, key),
  12.613 +				  has_key, (TableArg){ ptr: key});
  12.614 +#endif
  12.615 +}
  12.616 +
  12.617 +/** Remove (and free) all the entries in a bucket.
  12.618 + *
  12.619 + * @param bucket to clear
  12.620 + */
  12.621 +static inline void bucket_clear(HashTable *table, HTBucket *bucket){
  12.622 +    HTEntry *entry, *next;
  12.623 +
  12.624 +    for(entry = bucket->head; entry; entry = next){
  12.625 +        next = entry->next;
  12.626 +        HashTable_free_entry(table, entry);
  12.627 +    }
  12.628 +    bucket->head = 0;
  12.629 +    table->entry_count -= bucket->count;
  12.630 +    bucket->count = 0;
  12.631 +}
  12.632 +
  12.633 +/** Remove (and free) all the entries in a table.
  12.634 + *
  12.635 + * @param table to clear
  12.636 + */
  12.637 +void HashTable_clear(HashTable *table){
  12.638 +    int i, n = table->buckets_n;
  12.639 +
  12.640 +    for(i=0; i<n; i++){
  12.641 +        bucket_clear(table, table->buckets + i);
  12.642 +    }
  12.643 +}
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/tools/lib/hash_table.h	Mon Jun 28 15:03:15 2004 +0000
    13.3 @@ -0,0 +1,295 @@
    13.4 +/* $Id: hash_table.h,v 1.1 2004/03/30 16:21:26 mjw Exp $ */
    13.5 +/*
    13.6 + * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
    13.7 + *
    13.8 + * This library is free software; you can redistribute it and/or modify
    13.9 + * it under the terms of the GNU Lesser General Public License as published by
   13.10 + * the Free Software Foundation; either version 2.1 of the License, or
   13.11 + * (at your option) any later version.
   13.12 + *
   13.13 + * This library is distributed in the hope that it will be useful,
   13.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   13.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13.16 + * GNU Lesser General Public License for more details.
   13.17 + *
   13.18 + * You should have received a copy of the GNU Lesser General Public License
   13.19 + * along with this library; if not, write to the Free Software
   13.20 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   13.21 + */
   13.22 +
   13.23 +#ifndef _XEN_LIB_HASH_TABLE_H_
   13.24 +#define _XEN_LIB_HASH_TABLE_H_
   13.25 +
   13.26 +#include "iostream.h"
   13.27 +
   13.28 +typedef unsigned long Hashcode;
   13.29 +
   13.30 +/** Type used to pass parameters to table functions. */
   13.31 +typedef union TableArg {
   13.32 +    unsigned long ul;
   13.33 +    void *ptr;
   13.34 +} TableArg;
   13.35 +
   13.36 +/** An entry in a bucket list. */
   13.37 +typedef struct HTEntry {
   13.38 +    /** Hashcode of the entry's key. */
   13.39 +    Hashcode hashcode;
   13.40 +    /** Identifier for this entry in the table. */
   13.41 +    int index;
   13.42 +    /** The key for this entry. */
   13.43 +    void *key;
   13.44 +    /** The value in this entry. */
   13.45 +    void *value;
   13.46 +    /** The next entry in the list. */
   13.47 +    struct HTEntry *next;
   13.48 +} HTEntry;
   13.49 +
   13.50 +/** A bucket in a rule table. */
   13.51 +typedef struct HTBucket {
   13.52 +    /** Number of entries in the bucket. */
   13.53 +    int count;
   13.54 +    /** First entry in the bucket (may be null). */
   13.55 +    HTEntry *head;
   13.56 +} HTBucket;
   13.57 +
   13.58 +/** Default number of buckets in a hash table.
   13.59 + * You want enough buckets so the lists in the buckets will typically be short.
   13.60 + * It's a good idea if this is prime, since that will help to spread hashcodes
   13.61 + * around the table.
   13.62 + */
   13.63 +//#define HT_BUCKETS_N 1
   13.64 +//#define HT_BUCKETS_N 3
   13.65 +//#define HT_BUCKETS_N 7
   13.66 +//#define HT_BUCKETS_N 17
   13.67 +//#define HT_BUCKETS_N 97
   13.68 +//#define HT_BUCKETS_N 211
   13.69 +//#define HT_BUCKETS_N 401
   13.70 +#define HT_BUCKETS_N 1021
   13.71 +
   13.72 +typedef struct HashTable HashTable;
   13.73 +
   13.74 +/** Type for a function used to select table entries. */
   13.75 +typedef int TableTestFn(TableArg arg, HashTable *table, HTEntry *entry);
   13.76 +
   13.77 +/** Type for a function to map over table entries. */
   13.78 +typedef int TableMapFn(TableArg arg, HashTable *table, HTEntry *entry);
   13.79 +
   13.80 +/** Type for a function to free table entries. */
   13.81 +typedef void TableFreeFn(HashTable *table, HTEntry *entry);
   13.82 +
   13.83 +/** Type for a function to hash table keys. */
   13.84 +typedef Hashcode TableHashFn(void *key);
   13.85 +
   13.86 +/** Type for a function to test table keys for equality. */
   13.87 +typedef int TableEqualFn(void *key1, void *key2);
   13.88 +
   13.89 +/** Type for a function to order table entries. */
   13.90 +typedef int TableOrderFn(HTEntry *e1, HTEntry *e2);
   13.91 +
   13.92 +/** General hash table.
   13.93 + * A hash table with a list in each bucket.
   13.94 + * Functions can be supplied for freeing entries, hashing keys, and comparing keys.
   13.95 + * These all default to 0, when default behaviour treating keys as integers is used.
   13.96 + */
   13.97 +struct HashTable {
   13.98 +    /** Flag indicating whether the table has been initialised. */
   13.99 +    int init_done;
  13.100 +    /** Next value for the id field in inserted rules. */
  13.101 +    unsigned long next_id;
  13.102 +    /** Number of buckets in the bucket array. */
  13.103 +    int buckets_n;
  13.104 +    /** Array of buckets, each with its own list. */
  13.105 +    HTBucket *buckets;
  13.106 +    /** Number of entries in the table. */
  13.107 +    int entry_count;
  13.108 +    /** Function to free keys and values in entries. */
  13.109 +    TableFreeFn *entry_free_fn;
  13.110 +    /** Function to hash keys. */
  13.111 +    TableHashFn *key_hash_fn;
  13.112 +    /** Function to compare keys for equality. */
  13.113 +    TableEqualFn *key_equal_fn;
  13.114 +    /** Place for the user of the table to hang extra data. */
  13.115 +    void *user_data;
  13.116 +};
  13.117 +
  13.118 +extern HashTable *HashTable_new(int bucket_n);
  13.119 +extern void HashTable_free(HashTable *table);
  13.120 +extern HTEntry * HTEntry_new(Hashcode hashcode, void *key, void *value);
  13.121 +extern void HTEntry_free(HTEntry *entry);
  13.122 +extern int HashTable_set_bucket_n(HashTable *table, int bucket_n);
  13.123 +extern void HashTable_clear(HashTable *table);
  13.124 +extern HTEntry * HashTable_add_entry(HashTable *table, Hashcode hashcode, void *key, void *value);
  13.125 +extern HTEntry * HashTable_get_entry(HashTable *table, void *key);
  13.126 +extern HTEntry * HashTable_add(HashTable *table, void *key, void *value);
  13.127 +extern void * HashTable_get(HashTable *table, void *key);
  13.128 +extern int HashTable_remove(HashTable *table, void *key);
  13.129 +extern HTEntry * HashTable_find_entry(HashTable *table, Hashcode hashcode,
  13.130 +                                      TableTestFn *test_fn, TableArg arg);
  13.131 +extern int HashTable_remove_entry(HashTable *table, Hashcode hashcode,
  13.132 +                                   TableTestFn *test_fn, TableArg arg);
  13.133 +//extern int HashTable_map(HashTable *table, TableMapFn *map_fn, TableArg arg);
  13.134 +extern void HashTable_print(HashTable *table, IOStream *out);
  13.135 +extern int HashTable_set_buckets_n(HashTable *table, int buckets_n);
  13.136 +extern int HashTable_adjust(HashTable *table, int buckets_min);
  13.137 +extern void pseudo_des(unsigned long *pleft, unsigned long *pright);
  13.138 +extern Hashcode hash_string(char *s);
  13.139 +
  13.140 +extern int HashTable_order_bucket(HashTable *table, Hashcode hashcode, TableOrderFn *order);
  13.141 +
  13.142 +/** Control whether to use hashing based on DES or simple
  13.143 + * hashing. DES hashing is `more random' but much more expensive.
  13.144 + */
  13.145 +#define HASH_PSEUDO_DES 0
  13.146 +
  13.147 +/** Hash a long using a quick and dirty linear congruential random number generator.
  13.148 + *  See `Numerical Recipes in C', Chapter 7, "An Even Quicker Generator".
  13.149 + *
  13.150 + * @param a value to hash
  13.151 + * @return hashed input
  13.152 + */
  13.153 +static inline unsigned long lcrng_hash(unsigned long a){
  13.154 +    return (1664525L * a + 1013904223L);
  13.155 +}
  13.156 +
  13.157 +/** Hash an unsigned long.
  13.158 + *
  13.159 + * @param a input to hash
  13.160 + * @return hashcode
  13.161 + */
  13.162 +static inline Hashcode hash_ul(unsigned long a){
  13.163 +#if HASH_PSEUDO_DES
  13.164 +    unsigned long left = a;
  13.165 +    unsigned long right = 0L;
  13.166 +    pseudo_des(&left, &right);
  13.167 +    return right;
  13.168 +#else
  13.169 +    a = lcrng_hash(a);
  13.170 +    a = lcrng_hash(a);
  13.171 +    return a;
  13.172 +#endif
  13.173 +}
  13.174 +
  13.175 +/** Hash two unsigned longs together.
  13.176 + *
  13.177 + * @param a input to hash
  13.178 + * @param b input to hash
  13.179 + * @return hashcode
  13.180 + */
  13.181 +static inline Hashcode hash_2ul(unsigned long a, unsigned long b){
  13.182 +#if HASH_PSEUDO_DES
  13.183 +    unsigned long left = a;
  13.184 +    unsigned long right = b;
  13.185 +    pseudo_des(&left, &right);
  13.186 +    return right;
  13.187 +#else
  13.188 +    a = lcrng_hash(a);
  13.189 +    a ^= b;
  13.190 +    a = lcrng_hash(a);
  13.191 +    return a;
  13.192 +#endif
  13.193 +}
  13.194 +
  13.195 +/** Hash a hashcode and an unsigned long together.
  13.196 + *
  13.197 + * @param a input hashcode
  13.198 + * @param b input to hash
  13.199 + * @return hashcode
  13.200 + */
  13.201 +static inline Hashcode hash_hul(Hashcode a, unsigned long b){
  13.202 +#if HASH_PSEUDO_DES
  13.203 +    unsigned long left = a;
  13.204 +    unsigned long right = b;
  13.205 +    pseudo_des(&left, &right);
  13.206 +    return right;
  13.207 +#else
  13.208 +    a ^= b;
  13.209 +    a = lcrng_hash(a);
  13.210 +    return a;
  13.211 +#endif
  13.212 +}
  13.213 +
  13.214 +/** Macro to declare variables for HashTable_for_each() to use.
  13.215 + *
  13.216 + * @param entry variable that is set to entries in the table
  13.217 + */
  13.218 +#define HashTable_for_decl(entry) \
  13.219 +  HashTable *_var_table; \
  13.220 +  HTBucket *_var_bucket; \
  13.221 +  HTBucket *_var_end; \
  13.222 +  HTEntry *_var_next; \
  13.223 +  HTEntry *entry
  13.224 +
  13.225 +/** Macro to iterate over the entries in a hashtable.
  13.226 + * Must be in a scope where HashTable_for_decl() has been used to declare
  13.227 + * variables for it to use.
  13.228 + * The variable 'entry' is iterated over entries in the table.
  13.229 + * The code produced is syntactically a loop, so it must be followed by
  13.230 + * a loop body, typically some statements in braces:
  13.231 + * HashTable_for_each(entry, table){ ...loop body... }
  13.232 + *
  13.233 + * HashTable_for_each() and HashTable_for_decl() cannot be used for nested
  13.234 + * loops as variables will clash.
  13.235 + *
  13.236 + * @note The simplest way to code a direct loop over the entries in a hashtable
  13.237 + * is to use a loop over the buckets, with a nested loop over the entries
  13.238 + * in a bucket. Using this approach in a macro means the macro contains
  13.239 + * an opening brace, and calls to it must be followed by 2 braces!
  13.240 + * To avoid this the code has been restructured so that it is a for loop.
  13.241 + * So that statements could be used in the test expression of the for loop,
  13.242 + * we have used the gcc statement expression extension ({ ... }).
  13.243 + *
  13.244 + * @param entry variable to iterate over the entries
  13.245 + * @param table to iterate over (non-null)
  13.246 + */
  13.247 +#define HashTable_for_each(entry, table) \
  13.248 +  _var_table = table; \
  13.249 +  _var_bucket = _var_table->buckets; \
  13.250 +  _var_end = _var_bucket + _var_table->buckets_n; \
  13.251 +  for(entry=0, _var_next=0; \
  13.252 +      ({ if(_var_next){ \
  13.253 +             entry = _var_next; \
  13.254 +             _var_next = entry->next; \
  13.255 +          } else { \
  13.256 +             while(_var_bucket < _var_end){ \
  13.257 +                 entry = _var_bucket->head; \
  13.258 +                 _var_bucket++; \
  13.259 +                 if(entry){ \
  13.260 +                      _var_next = entry->next; \
  13.261 +                      break; \
  13.262 +                 } \
  13.263 +             } \
  13.264 +          }; \
  13.265 +         entry; }); \
  13.266 +      entry = _var_next )
  13.267 +
  13.268 +/** Map a function over the entries in a table.
  13.269 + * Mapping stops when the function returns a non-zero value.
  13.270 + * Uses the gcc statement expression extension ({ ... }).
  13.271 + *
  13.272 + * @param table to map over
  13.273 + * @param fn function to apply to entries
  13.274 + * @param arg first argument to call the function with
  13.275 + * @return 0 if fn always returned 0, first non-zero value otherwise
  13.276 + */
  13.277 +#define HashTable_map(table, fn, arg) \
  13.278 +  ({ HashTable_for_decl(_var_entry); \
  13.279 +    TableArg _var_arg = arg; \
  13.280 +    int _var_value = 0; \
  13.281 +    HashTable_for_each(_var_entry, table){ \
  13.282 +        if((_var_value = fn(_var_arg, _var_table, _var_entry))) break; \
  13.283 +    } \
  13.284 +    _var_value; })
  13.285 +
  13.286 +/** Cast x to the type for a key or value in a hash table.
  13.287 + * This avoids compiler warnings when using short integers
  13.288 + * as keys or values (especially on 64-bit platforms).
  13.289 + */
  13.290 +#define HKEY(x) ((void*)(unsigned long)(x))
  13.291 +
  13.292 +/** Cast x from the type for a key or value in a hash table.
  13.293 + * to an unsigned long. This avoids compiler warnings when using
  13.294 + * short integers as keys or values (especially on 64-bit platforms).
  13.295 + */
  13.296 +#define HVAL(x) ((unsigned long)(x))
  13.297 +
  13.298 +#endif /* !_XEN_LIB_HASH_TABLE_H_ */
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/tools/lib/iostream.c	Mon Jun 28 15:03:15 2004 +0000
    14.3 @@ -0,0 +1,37 @@
    14.4 +#include "iostream.h"
    14.5 +#include "sys_string.h"
    14.6 +
    14.7 +/** Print on a stream, like vfprintf().
    14.8 + *
    14.9 + * @param stream to print to
   14.10 + * @param format for the print (as fprintf())
   14.11 + * @param args arguments to print
   14.12 + * @return result code from the print
   14.13 + */
   14.14 +int IOStream_vprint(IOStream *stream, const char *format, va_list args){
   14.15 +  char buffer[1024];
   14.16 +  int k = sizeof(buffer), n;
   14.17 +
   14.18 +  n = vsnprintf(buffer, k, (char*)format, args);
   14.19 +  if(n < 0 || n > k ){
   14.20 +      n = k;
   14.21 +  }
   14.22 +  n = IOStream_write(stream, buffer, n);
   14.23 +  return n;
   14.24 +}
   14.25 +
   14.26 +/** Print on a stream, like fprintf().
   14.27 + *
   14.28 + * @param stream to print to
   14.29 + * @param format for the print (as fprintf())
   14.30 + * @return result code from the print
   14.31 + */
   14.32 +int IOStream_print(IOStream *stream, const char *format, ...){
   14.33 +  va_list args;
   14.34 +  int result = -1;
   14.35 +
   14.36 +  va_start(args, format);
   14.37 +  result = IOStream_vprint(stream, format, args);
   14.38 +  va_end(args);
   14.39 +  return result;
   14.40 +}
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/tools/lib/iostream.h	Mon Jun 28 15:03:15 2004 +0000
    15.3 @@ -0,0 +1,243 @@
    15.4 +#ifndef _XC_LINUX_SAVE_H_
    15.5 +#define _XC_LINUX_SAVE_H_
    15.6 +
    15.7 +#include <stdarg.h>
    15.8 +#include <stdint.h>
    15.9 +#include <stddef.h>
   15.10 +
   15.11 +#ifdef __KERNEL__
   15.12 +#include <linux/errno.h>
   15.13 +#else
   15.14 +#include <errno.h>
   15.15 +#endif
   15.16 +
   15.17 +#include "allocate.h"
   15.18 +
   15.19 +/** End of input return value. */
   15.20 +#define IOSTREAM_EOF -1
   15.21 +
   15.22 +/** An input/output abstraction.
   15.23 + */
   15.24 +typedef struct IOStream IOStream;
   15.25 +
   15.26 +/** Record of the functions to use for operations on an
   15.27 + * IOStream implementation.
   15.28 + */
   15.29 +typedef struct IOMethods {
   15.30 +    /** Read function.  Called with the user data, buffer to read into
   15.31 +     * and number of bytes to read.  Must return number of bytes read
   15.32 +     * on success, less than zero on error.
   15.33 +     */
   15.34 +    int (*read)(IOStream *stream, void *buf, size_t n);
   15.35 +
   15.36 +    /** Write function. Called with user data, buffer to write and
   15.37 +     * number of bytes to write. Must return number of bytes written on
   15.38 +     * success, less than zero otherwise.
   15.39 +     */
   15.40 +    int (*write)(IOStream *stream, const void *buf, size_t n);
   15.41 +
   15.42 +    int (*flush)(IOStream *s);
   15.43 +
   15.44 +    int (*error)(IOStream *s);
   15.45 +
   15.46 +    int (*close)(IOStream *s);
   15.47 +
   15.48 +    void (*free)(IOStream *s);
   15.49 +
   15.50 +    void (*lock)(IOStream *s);
   15.51 +    void (*unlock)(IOStream *s);
   15.52 +
   15.53 +} IOMethods;
   15.54 +
   15.55 +/** Abstract i/o object.
   15.56 + */
   15.57 +struct IOStream {
   15.58 +    /** Methods to use to implement operations. */
   15.59 +    const IOMethods *methods;
   15.60 +    /** Private state for the implementation. */
   15.61 +    const void *data;
   15.62 +    /** Flag indicating whether the stream is closed. */
   15.63 +    int closed;
   15.64 +    /** Number of bytes written. */
   15.65 +    int written;
   15.66 +    /** Number of bytes read. */
   15.67 +    int read;
   15.68 +};
   15.69 +
   15.70 +
   15.71 +/** IOStream version of stdin. */
   15.72 +extern IOStream *iostdin;
   15.73 +
   15.74 +/** IOStream version of stdout, */
   15.75 +extern IOStream *iostdout;
   15.76 +
   15.77 +/** IOStream version of stderr. */
   15.78 +extern IOStream *iostderr;
   15.79 +
   15.80 +extern int IOStream_print(IOStream *io, const char *format, ...);
   15.81 +extern int IOStream_vprint(IOStream *io, const char *format, va_list args);
   15.82 +
   15.83 +/** Read from a stream.
   15.84 + *
   15.85 + * @param stream input
   15.86 + * @param buf where to put input
   15.87 + * @param n number of bytes to read
   15.88 + * @return if ok, number of bytes read, otherwise negative error code
   15.89 + */
   15.90 +static inline int IOStream_read(IOStream *stream, void *buf, size_t n){
   15.91 +    int result = 0;
   15.92 +    if(stream->closed) goto exit;
   15.93 +    if(!stream->methods || !stream->methods->read){
   15.94 +        result = -EINVAL;
   15.95 +        goto exit;
   15.96 +    }
   15.97 +    result = stream->methods->read(stream, buf, n);
   15.98 +    if(result > 0){
   15.99 +        stream->read += result;
  15.100 +    }
  15.101 +  exit:
  15.102 +    return result;
  15.103 +}
  15.104 +
  15.105 +/** Write to a stream.
  15.106 + *
  15.107 + * @param stream input
  15.108 + * @param buf where to put input
  15.109 + * @param n number of bytes to write
  15.110 + * @return if ok, number of bytes read, otherwise negative error code
  15.111 + */
  15.112 +static inline int IOStream_write(IOStream *stream, const void *buf, size_t n){
  15.113 +    int result = 0;
  15.114 +    if(stream->closed) goto exit;
  15.115 +    if(!stream->methods || !stream->methods->write){
  15.116 +        result = -EINVAL;
  15.117 +        goto exit;
  15.118 +    }
  15.119 +    result = stream->methods->write(stream, buf, n);
  15.120 +    if(result > 0){
  15.121 +        stream->written += result;
  15.122 +    }
  15.123 +  exit:
  15.124 +    return result;
  15.125 +}
  15.126 +
  15.127 +/** Flush the stream.
  15.128 + *
  15.129 + * @param stream stream
  15.130 + * @return 0 on success, IOSTREAM_EOF otherwise
  15.131 + */
  15.132 +static inline int IOStream_flush(IOStream *stream){
  15.133 +    int result = 0;
  15.134 +    if(stream->closed){
  15.135 +        result = IOSTREAM_EOF;
  15.136 +    } else if(stream->methods->flush){
  15.137 +        result = stream->methods->flush(stream);
  15.138 +        if(result < 0) result = IOSTREAM_EOF;
  15.139 +    }
  15.140 +    return result;
  15.141 +}
  15.142 +
  15.143 +/** Check whether the stream has an error.
  15.144 + *
  15.145 + * @param stream to check
  15.146 + * @return 1 for error, 0 otherwise
  15.147 + */
  15.148 +static inline int IOStream_error(IOStream *stream){
  15.149 +    int err = 0;
  15.150 +    if(stream->methods && stream->methods->error){
  15.151 +       err = stream->methods->error(stream);
  15.152 +    }
  15.153 +    return err;
  15.154 +}
  15.155 +
  15.156 +/** Close the stream.
  15.157 + *
  15.158 + * @param stream to close
  15.159 + * @return 1 for error, 0 otherwise
  15.160 + */
  15.161 +static inline int IOStream_close(IOStream *stream){
  15.162 +    int err = 1;
  15.163 +    if(stream->methods && stream->methods->close){
  15.164 +        err = stream->methods->close(stream);
  15.165 +    }
  15.166 +    return err;
  15.167 +}
  15.168 +
  15.169 +/** Test if the stream has been closed.
  15.170 + *
  15.171 + * @param stream to check
  15.172 + * @return 1 if closed, 0 otherwise
  15.173 + */
  15.174 +static inline int IOStream_is_closed(IOStream *stream){
  15.175 +  return stream->closed;
  15.176 +}
  15.177 +
  15.178 +/** Free the memory used by the stream.
  15.179 + *
  15.180 + * @param stream to free
  15.181 + */
  15.182 +static inline void IOStream_free(IOStream *stream){
  15.183 +  if(stream->methods && stream->methods->free){
  15.184 +    stream->methods->free(stream);
  15.185 +  }
  15.186 +  *stream = (IOStream){};
  15.187 +  deallocate(stream);
  15.188 +}
  15.189 +
  15.190 +
  15.191 +/** Print a character to a stream, like fputc().
  15.192 + *
  15.193 + * @param stream to print to
  15.194 + * @param c character to print
  15.195 + * @return result code from the print
  15.196 + */
  15.197 +static inline int IOStream_putc(IOStream *stream, int c){
  15.198 +    int err;
  15.199 +    unsigned char b = (unsigned char)c;
  15.200 +    err = IOStream_write(stream, &b, 1);
  15.201 +    if(err < 1){
  15.202 +        err = IOSTREAM_EOF;
  15.203 +    } else {
  15.204 +        err = b;
  15.205 +    }
  15.206 +    return err;
  15.207 +}
  15.208 +
  15.209 +/** Read from a stream, like fgetc().
  15.210 + *
  15.211 + * @param stream to read from
  15.212 + * @return IOSTREAM_EOF on error, character read otherwise
  15.213 + */
  15.214 +static inline int IOStream_getc(IOStream *stream){
  15.215 +    int err, rc;
  15.216 +    unsigned char b;
  15.217 +
  15.218 +    err = IOStream_read(stream, &b, 1);
  15.219 +    if(err < 1){
  15.220 +        rc = IOSTREAM_EOF;
  15.221 +    } else {
  15.222 +        rc = b;
  15.223 +    }
  15.224 +    return rc;
  15.225 +}
  15.226 +
  15.227 +/** Get number of bytes read.
  15.228 + *
  15.229 + * @param stream to get from
  15.230 + * @return number of bytes read
  15.231 + */
  15.232 +static inline int IOStream_get_read(IOStream *stream){
  15.233 +    return stream->read;
  15.234 +}
  15.235 +
  15.236 +/** Get number of bytes written.
  15.237 + *
  15.238 + * @param stream to get from
  15.239 + * @return number of bytes written
  15.240 + */
  15.241 +static inline int IOStream_get_written(IOStream *stream){
  15.242 +    return stream->written;
  15.243 +}
  15.244 +
  15.245 +
  15.246 +#endif /* ! _XC_LINUX_SAVE_H_ */
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/tools/lib/kernel_stream.c	Mon Jun 28 15:03:15 2004 +0000
    16.3 @@ -0,0 +1,177 @@
    16.4 +/*
    16.5 + * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
    16.6 + *
    16.7 + * This library is free software; you can redistribute it and/or modify
    16.8 + * it under the terms of the GNU Lesser General Public License as published by
    16.9 + * the Free Software Foundation; either version 2.1 of the License, or
   16.10 + * (at your option) any later version.
   16.11 + *
   16.12 + * This library is distributed in the hope that it will be useful,
   16.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   16.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16.15 + * GNU Lesser General Public License for more details.
   16.16 + *
   16.17 + * You should have received a copy of the GNU Lesser General Public License
   16.18 + * along with this library; if not, write to the Free Software
   16.19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   16.20 + */
   16.21 +
   16.22 +/** @file
   16.23 + * An IOStream implementation using printk() for output.
   16.24 + * Input is not implemented.
   16.25 + */
   16.26 +#ifdef __KERNEL__
   16.27 +
   16.28 +#include <linux/config.h>
   16.29 +#include <linux/module.h>
   16.30 +#include <linux/kernel.h>
   16.31 +#include <linux/types.h>
   16.32 +#include <linux/errno.h>
   16.33 +#include <linux/slab.h>
   16.34 +#include <linux/spinlock.h>
   16.35 +
   16.36 +#include "kernel_stream.h"
   16.37 +#include "allocate.h"
   16.38 +
   16.39 +/** Number of characters in the output buffer.
   16.40 + * The kernel uses 1024 for printk, so that should suffice.
   16.41 + */
   16.42 +#define BUF_N 1024
   16.43 +
   16.44 +/** State for a kernel stream. */
   16.45 +typedef struct KernelData {
   16.46 +    /** Stream lock. We need a lock to serialize access to the stream. */
   16.47 +    spinlock_t lock;
   16.48 +    /** Saved flags for locking. */
   16.49 +    unsigned long flags;
   16.50 +    /** Size of the output buffer. */
   16.51 +    int buf_n;
   16.52 +    /** Output buffer. */
   16.53 +    char buf[BUF_N];
   16.54 +} KernelData;
   16.55 +
   16.56 +static int kernel_write(IOStream *s, const char *msg, int n);
   16.57 +static void kernel_free(IOStream *s);
   16.58 +static void kernel_stream_lock(IOStream *s);
   16.59 +static void kernel_stream_unlock(IOStream *s);
   16.60 +
   16.61 +/** Methods for a kernel stream. Output only. */
   16.62 +static const IOMethods kernel_methods = {
   16.63 +  write:  kernel_write,
   16.64 +  free:   kernel_free,
   16.65 +  lock:   kernel_stream_lock,
   16.66 +  unlock: kernel_stream_unlock,
   16.67 +};
   16.68 +
   16.69 +/** Shared state for kernel streams.
   16.70 + * All implementations write using printk, so we can use
   16.71 + * shared state and avoid allocating it.
   16.72 + */
   16.73 +static const KernelData kernel_data = {
   16.74 +  lock: SPIN_LOCK_UNLOCKED,
   16.75 +  flags: 0,
   16.76 +  buf_n: BUF_N,
   16.77 +};
   16.78 +
   16.79 +/** Stream for kernel printk. */
   16.80 +static IOStream iokernel = {
   16.81 +    methods: &kernel_methods,
   16.82 +    data:    &kernel_data,
   16.83 +};
   16.84 +
   16.85 +/** Stream for kernel printk. */
   16.86 +IOStream *iostdout = &iokernel;
   16.87 +
   16.88 +/** Stream for kernel printk. */
   16.89 +IOStream *iostdin = &iokernel;
   16.90 +
   16.91 +/** Stream for kernel printk. */
   16.92 +IOStream *iostderr = &iokernel;
   16.93 +
   16.94 +/** Get an output-only stream implementation using
   16.95 + * printk(). The stream uses static storage, and must not be freed.
   16.96 + *
   16.97 + * @return kernel stream
   16.98 + */
   16.99 +IOStream get_stream_kernel(void){
  16.100 +  return iokernel;
  16.101 +}
  16.102 +
  16.103 +/** Obtain the lock on the stream state.
  16.104 + *
  16.105 + * @param kdata stream state
  16.106 + */
  16.107 +static inline void KernelData_lock(KernelData *kdata){
  16.108 +  spin_lock_irqsave(&kdata->lock, kdata->flags);
  16.109 +}
  16.110 +
  16.111 +/** Release the lock on the stream state.
  16.112 + *
  16.113 + * @param kdata stream state
  16.114 + */
  16.115 +static inline void KernelData_unlock(KernelData *kdata){
  16.116 +  spin_unlock_irqrestore(&kdata->lock, kdata->flags);
  16.117 +}
  16.118 +
  16.119 +/** Get the stream state.
  16.120 + *
  16.121 + * @param s kernel stream
  16.122 + * @return stream state
  16.123 + */
  16.124 +static inline KernelData *get_kernel_data(IOStream *s){
  16.125 +  return (KernelData*)s->data;
  16.126 +}
  16.127 +
  16.128 +/** Obtain the lock on the stream state.
  16.129 + *
  16.130 + * @param s stream
  16.131 + */
  16.132 +void kernel_stream_lock(IOStream *s){
  16.133 +    KernelData_lock(get_kernel_data(s));
  16.134 +}
  16.135 +
  16.136 +/** Release the lock on the stream state.
  16.137 + *
  16.138 + * @param s stream
  16.139 + */
  16.140 +void kernel_stream_unlock(IOStream *s){
  16.141 +    KernelData_unlock(get_kernel_data(s));
  16.142 +}
  16.143 +
  16.144 +/** Write to a kernel stream.
  16.145 + *
  16.146 + * @param stream kernel stream
  16.147 + * @param format print format
  16.148 + * @param args print arguments
  16.149 + * @return result of the print
  16.150 + */
  16.151 +static int kernel_write(IOStream *stream, const char *buf, int n){
  16.152 +  KernelData *kdata = get_kernel_data(stream);
  16.153 +  int k;
  16.154 +  k = kdata->buf_n - 1;
  16.155 +  if(n < k) k = n;
  16.156 +  memcpy(kdata->buf, buf, k);
  16.157 +  kdata->buf[k] = '\0'
  16.158 +  printk(kdata->buf);
  16.159 +  return k;
  16.160 +}
  16.161 +
  16.162 +/** Free a kernel stream.
  16.163 + * Frees the internal state of the stream.
  16.164 + * Do not call this unless the stream was dynamically allocated.
  16.165 + * Do not call this on a stream returned from get_stream_kernel().
  16.166 + *
  16.167 + * @param io stream to free
  16.168 + */
  16.169 +static void kernel_free(IOStream *io){
  16.170 +  KernelData *kdata;
  16.171 +  if(io == &iokernel) return;
  16.172 +  kdata = get_kernel_data(io);
  16.173 +  zero(kdata, sizeof(*kdata));
  16.174 +  deallocate(kdata);
  16.175 +}
  16.176 +#endif /* __KERNEL__ */
  16.177 +
  16.178 +
  16.179 +
  16.180 +
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/tools/lib/kernel_stream.h	Mon Jun 28 15:03:15 2004 +0000
    17.3 @@ -0,0 +1,29 @@
    17.4 +/*
    17.5 + * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
    17.6 + *
    17.7 + * This library is free software; you can redistribute it and/or modify
    17.8 + * it under the terms of the GNU Lesser General Public License as published by
    17.9 + * the Free Software Foundation; either version 2.1 of the License, or
   17.10 + * (at your option) any later version.
   17.11 + *
   17.12 + * This library is distributed in the hope that it will be useful,
   17.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   17.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17.15 + * GNU Lesser General Public License for more details.
   17.16 + *
   17.17 + * You should have received a copy of the GNU Lesser General Public License
   17.18 + * along with this library; if not, write to the Free Software
   17.19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   17.20 + */
   17.21 +
   17.22 +#ifndef _XEN_LIB_KERNEL_STREAM_H_
   17.23 +#define _XEN_LIB_KERNEL_STREAM_H_
   17.24 +
   17.25 +#ifdef __KERNEL__
   17.26 +#include "iostream.h"
   17.27 +
   17.28 +extern IOStream get_stream_kernel(void);
   17.29 +#define get_stream_stdout get_stream_kernel
   17.30 +
   17.31 +#endif /* __KERNEL__ */
   17.32 +#endif /* !_XEN_LIB_KERNEL_STREAM_H_ */
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/tools/lib/lexis.c	Mon Jun 28 15:03:15 2004 +0000
    18.3 @@ -0,0 +1,93 @@
    18.4 +/*
    18.5 + *
    18.6 + * This library is free software; you can redistribute it and/or modify
    18.7 + * it under the terms of the GNU Lesser General Public License as
    18.8 + * published by the Free Software Foundation; either version 2.1 of the
    18.9 + * License, or  (at your option) any later version. This library is 
   18.10 + * distributed in the  hope that it will be useful, but WITHOUT ANY
   18.11 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or
   18.12 + * FITNESS FOR A PARTICULAR PURPOSE.
   18.13 + * See the GNU Lesser General Public License for more details.
   18.14 + *
   18.15 + * You should have received a copy of the GNU Lesser General Public License
   18.16 + * along with this library; if not, write to the Free Software Foundation,
   18.17 + * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   18.18 + */
   18.19 +
   18.20 +/** @file
   18.21 + * Lexical analysis.
   18.22 + */
   18.23 +
   18.24 +#include "sys_string.h"
   18.25 +#include "lexis.h"
   18.26 +#include <errno.h>
   18.27 +
   18.28 +/** Check if a value lies in a (closed) range.
   18.29 + *
   18.30 + * @param x value to test
   18.31 + * @param lo low end of the range
   18.32 + * @param hi high end of the range
   18.33 + * @return 1 if x is in the interval [lo, hi], 0 otherwise
   18.34 + */
   18.35 +inline static int in_range(int x, int lo, int hi){
   18.36 +    return (lo <= x) && (x <= hi);
   18.37 +}
   18.38 +
   18.39 +/** Determine if a string is an (unsigned) decimal number.
   18.40 + * 
   18.41 + * @param s pointer to characters to test
   18.42 + * @param n length of string
   18.43 + * @return 1 if s is a decimal number, 0 otherwise.
   18.44 + */
   18.45 +int is_decimal_number(const char *s, int n){
   18.46 +    int i;
   18.47 +    if(n <= 0)return 0;
   18.48 +    for(i = 0; i < n; i++){
   18.49 +        if(!in_decimal_digit_class(s[i])) return 0;
   18.50 +    }
   18.51 +    return 1;
   18.52 +}
   18.53 +
   18.54 +/** Determine if a string is a hex number.
   18.55 + * Hex numbers are 0, or start with 0x or 0X followed
   18.56 + * by a non-zero number of hex digits (0-9,a-f,A-F).
   18.57 + * 
   18.58 + * @param s pointer to characters to test
   18.59 + * @param n length of string
   18.60 + * @return 1 if s is a hex number, 0 otherwise.
   18.61 + */
   18.62 +int is_hex_number(const char *s, int n){
   18.63 +    int i;
   18.64 +    if(n <= 0) return 0;
   18.65 +    if(n == 1){
   18.66 +        return s[0]=='0';
   18.67 +    }
   18.68 +    if(n <= 3) return 0;
   18.69 +    if(s[0] != '0' || (s[1] != 'x' && s[1] != 'X')) return 0;
   18.70 +    for(i = 2; i < n; i++){
   18.71 +        if(!in_hex_digit_class(s[i])) return 0;
   18.72 +    }
   18.73 +    return 1;
   18.74 +}
   18.75 +
   18.76 +/** Test if a string matches a keyword.
   18.77 + * The comparison is case-insensitive.
   18.78 + * The comparison fails if either argument is null.
   18.79 + *
   18.80 + * @param s string
   18.81 + * @param k keyword
   18.82 + * @return 1 if they match, 0 otherwise
   18.83 + */
   18.84 +int is_keyword(const char *s, const char *k){
   18.85 +  return s && k && !strcasecmp(s, k);
   18.86 +}
   18.87 +
   18.88 +/** Test if a string matches a character.
   18.89 + *
   18.90 + * @param s string
   18.91 + * @param c character (non-null)
   18.92 + * @return 1 if s contains exactly c, 0 otherwise
   18.93 + */
   18.94 +int is_keychar(const char *s, char c){
   18.95 +  return c && (s[0] == c) && !s[1];
   18.96 +}
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/tools/lib/lexis.h	Mon Jun 28 15:03:15 2004 +0000
    19.3 @@ -0,0 +1,122 @@
    19.4 +/*
    19.5 + *
    19.6 + * This library is free software; you can redistribute it and/or modify
    19.7 + * it under the terms of the GNU Lesser General Public License as
    19.8 + * published by the Free Software Foundation; either version 2.1 of the
    19.9 + * License, or  (at your option) any later version. This library is 
   19.10 + * distributed in the  hope that it will be useful, but WITHOUT ANY
   19.11 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or
   19.12 + * FITNESS FOR A PARTICULAR PURPOSE.
   19.13 + * See the GNU Lesser General Public License for more details.
   19.14 + *
   19.15 + * You should have received a copy of the GNU Lesser General Public License
   19.16 + * along with this library; if not, write to the Free Software Foundation,
   19.17 + * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   19.18 + */
   19.19 +
   19.20 +#ifndef _SP_LEXIS_H_
   19.21 +#define _SP_LEXIS_H_
   19.22 +
   19.23 +#include "sys_string.h"
   19.24 +#include "sys_ctype.h"
   19.25 +
   19.26 +/** @file
   19.27 + * Lexical analysis.
   19.28 + */
   19.29 +
   19.30 +/** Class of characters treated as space. */
   19.31 +#define space_class ((char []){ '\n', '\r', '\t', ' ', '\f' , 0 })
   19.32 +
   19.33 +/** Class of separator characters. */
   19.34 +#define sep_class "{}()<>[]@!;"
   19.35 +
   19.36 +#define comment_class "#"
   19.37 +
   19.38 +/** Determine if a character is in a given class.
   19.39 + * 
   19.40 + * @param c character to test
   19.41 + * @param s null-terminated string of characters in the class
   19.42 + * @return 1 if c is in the class, 0 otherwise.
   19.43 + */
   19.44 +static inline int in_class(int c, const char *s){
   19.45 +  return s && (strchr(s, c) != 0);
   19.46 +}
   19.47 +
   19.48 +/** Determine if a character is in the space class.
   19.49 + * 
   19.50 + * @param c character to test
   19.51 + * @return 1 if c is in the class, 0 otherwise.
   19.52 + */
   19.53 +static inline int in_space_class(int c){
   19.54 +    return in_class(c, space_class);
   19.55 +}
   19.56 +
   19.57 +static inline int in_comment_class(int c){
   19.58 +    return in_class(c, comment_class);
   19.59 +}
   19.60 +
   19.61 +/** Determine if a character is in the separator class.
   19.62 + * Separator characters terminate tokens, and do not need space
   19.63 + * to separate them.
   19.64 + * 
   19.65 + * @param c character to test
   19.66 + * @return 1 if c is in the class, 0 otherwise.
   19.67 + */
   19.68 +static inline int in_sep_class(int c){
   19.69 +    return in_class(c, sep_class);
   19.70 +}
   19.71 +
   19.72 +/** Determine if a character is in the alpha class.
   19.73 + * 
   19.74 + * @param c character to test
   19.75 + * @return 1 if c is in the class, 0 otherwise.
   19.76 + */
   19.77 +static inline int in_alpha_class(int c){
   19.78 +    return isalpha(c);
   19.79 +}
   19.80 +
   19.81 +/** Determine if a character is in the octal digit class.
   19.82 + * 
   19.83 + * @param c character to test
   19.84 + * @return 1 if c is in the class, 0 otherwise.
   19.85 + */
   19.86 +static inline int in_octal_digit_class(int c){
   19.87 +    return '0' <= c && c <= '7';
   19.88 +}
   19.89 +
   19.90 +/** Determine if a character is in the decimal digit class.
   19.91 + * 
   19.92 + * @param c character to test
   19.93 + * @return 1 if c is in the class, 0 otherwise.
   19.94 + */
   19.95 +static inline int in_decimal_digit_class(int c){
   19.96 +    return isdigit(c);
   19.97 +}
   19.98 +
   19.99 +/** Determine if a character is in the hex digit class.
  19.100 + * 
  19.101 + * @param c character to test
  19.102 + * @return 1 if c is in the class, 0 otherwise.
  19.103 + */
  19.104 +static inline int in_hex_digit_class(int c){
  19.105 +    return isdigit(c) || in_class(c, "abcdefABCDEF");
  19.106 +}
  19.107 +
  19.108 +
  19.109 +static inline int in_string_quote_class(int c){
  19.110 +    return in_class(c, "'\"");
  19.111 +}
  19.112 +
  19.113 +static inline int in_printable_class(int c){
  19.114 +    return ('A' <= c && c <= 'Z')
  19.115 +        || ('a' <= c && c <= 'z')
  19.116 +        || ('0' <= c && c <= '9')
  19.117 +        || in_class(c, "!$%&*+,-./:;<=>?@^_`{|}~");
  19.118 +}
  19.119 +
  19.120 +extern int is_decimal_number(const char *s, int n);
  19.121 +extern int is_hex_number(const char *s, int n);
  19.122 +extern int is_keyword(const char *s, const char *k);
  19.123 +extern int is_keychar(const char *s, char c);
  19.124 +
  19.125 +#endif /* !_SP_LEXIS_H_ */
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/tools/lib/lzi_stream.c	Mon Jun 28 15:03:15 2004 +0000
    20.3 @@ -0,0 +1,590 @@
    20.4 +/* $Id: lzi_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $ */
    20.5 +#define __FILE_ID_INFO "$Id: lzi_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $"
    20.6 +#include <what.h>
    20.7 +static char __rcsid[] __attribute__((unused)) = WHAT_ID __FILE_ID_INFO;
    20.8 +/*
    20.9 + * Copyright (C) 2003 Hewlett-Packard Company.
   20.10 + *
   20.11 + * This library is free software; you can redistribute it and/or modify
   20.12 + * it under the terms of the GNU Lesser General Public License as published by
   20.13 + * the Free Software Foundation; either version 2.1 of the License, or
   20.14 + * (at your option) any later version.
   20.15 + *
   20.16 + * This library is distributed in the hope that it will be useful,
   20.17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   20.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   20.19 + * GNU Lesser General Public License for more details.
   20.20 + *
   20.21 + * You should have received a copy of the GNU Lesser General Public License
   20.22 + * along with this library; if not, write to the Free Software
   20.23 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   20.24 + */
   20.25 +
   20.26 +/** @file
   20.27 + * An IOStream implementation using LZI to provide compression and decompression.
   20.28 + * This is designed to provide compression without output latency.
   20.29 + * Flushing an LZI stream flushes all pending data to the underlying stream.
   20.30 + * This is essential for stream-based (e.g. networked) applications.
   20.31 + *
   20.32 + * A compressed data stream is a sequence of blocks.
   20.33 + * Each block is the block size followed by the compressed data.
   20.34 + * The last block has size zero.
   20.35 + * Sizes are 4-byte unsigned in network order.
   20.36 + *
   20.37 + * This format allows compressed data to be read from a stream without reading
   20.38 + * past the logical end of compressed data.
   20.39 + *
   20.40 + * @author Mike Wray <mike.wray@hpl.hp.com>
   20.41 + */
   20.42 +#ifndef __KERNEL__
   20.43 +
   20.44 +#include <stdio.h>
   20.45 +#include <stdlib.h>
   20.46 +#include <errno.h>
   20.47 +#include <string.h>
   20.48 +
   20.49 +#include "zlib.h"
   20.50 +
   20.51 +#include "allocate.h"
   20.52 +#include "lzi_stream.h"
   20.53 +#include "file_stream.h"
   20.54 +#include "marshal.h"
   20.55 +
   20.56 +#define dprintf(fmt, args...) fprintf(stdout, "[DEBUG] LZI>%s" fmt, __FUNCTION__, ##args)
   20.57 +#define wprintf(fmt, args...) fprintf(stderr, "[WARN]  LZI>%s" fmt, __FUNCTION__, ##args)
   20.58 +#define iprintf(fmt, args...) fprintf(stdout, "[INFO]  LZI>%s" fmt, __FUNCTION__, ##args)
   20.59 +#define eprintf(fmt, args...) fprintf(stderr, "[ERROR] LZI>%s" fmt, __FUNCTION__, ##args)
   20.60 +
   20.61 +static int lzi_read(IOStream *s, void *buf, size_t size, size_t count);
   20.62 +static int lzi_write(IOStream *s, const void *buf, size_t size, size_t count);
   20.63 +static int lzi_print(IOStream *s, const char *msg, va_list args);
   20.64 +static int lzi_getc(IOStream *s);
   20.65 +static int lzi_error(IOStream *s);
   20.66 +static int lzi_close(IOStream *s);
   20.67 +static void lzi_free(IOStream *s);
   20.68 +static int lzi_flush(IOStream *s);
   20.69 +
   20.70 +enum {
   20.71 +    LZI_WRITE = 1,
   20.72 +    LZI_READ = 2,
   20.73 +};
   20.74 +
   20.75 +/** Methods used by a gzFile* IOStream. */
   20.76 +static const IOMethods lzi_methods = {
   20.77 +    read: lzi_read,
   20.78 +    write: lzi_write,
   20.79 +    print: lzi_print,
   20.80 +    getc:  lzi_getc,
   20.81 +    error: lzi_error,
   20.82 +    close: lzi_close,
   20.83 +    free:  lzi_free,
   20.84 +    flush: lzi_flush,
   20.85 +};
   20.86 +
   20.87 +#define BUFFER_SIZE (512 * 1024)
   20.88 +
   20.89 +typedef struct LZIState {
   20.90 +    z_stream zstream;
   20.91 +    void *inbuf;
   20.92 +    uint32_t inbuf_size;
   20.93 +    void *outbuf;
   20.94 +    uint32_t outbuf_size;
   20.95 +    /** Underlying stream for I/O. */
   20.96 +    IOStream *io;
   20.97 +    /** Flags. */
   20.98 +    int flags;
   20.99 +    /** Error indicator. */
  20.100 +    int error;
  20.101 +    int eof;
  20.102 +    int plain_bytes;
  20.103 +    int comp_bytes;
  20.104 +    int zstream_initialized;
  20.105 +    int flushed;
  20.106 +} LZIState;
  20.107 +
  20.108 +static inline int LZIState_writeable(LZIState *s){
  20.109 +    return (s->flags & LZI_WRITE) != 0;
  20.110 +}
  20.111 +
  20.112 +static inline int LZIState_readable(LZIState *s){
  20.113 +    return (s->flags & LZI_READ) != 0;
  20.114 +}
  20.115 +
  20.116 +void LZIState_free(LZIState *z){
  20.117 +    if(!z) return;
  20.118 +    if(z->zstream_initialized){
  20.119 +        if(LZIState_writeable(z)){
  20.120 +            deflateEnd(&z->zstream);
  20.121 +        } else if(LZIState_readable(z)){
  20.122 +            inflateEnd(&z->zstream);
  20.123 +        }
  20.124 +    }
  20.125 +    deallocate(z->inbuf);
  20.126 +    deallocate(z->outbuf);
  20.127 +    deallocate(z);
  20.128 +}
  20.129 +
  20.130 +static int mode_flags(const char *mode, int *flags){
  20.131 +    int err = 0;
  20.132 +    int r=0, w=0;
  20.133 +    if(!mode){
  20.134 +        err = -EINVAL;
  20.135 +        goto exit;
  20.136 +    }
  20.137 +    for(; *mode; mode++){
  20.138 +        if(*mode == 'w') w = 1;
  20.139 +        if(*mode == 'r') r = 1;
  20.140 +    }
  20.141 +    if(r + w != 1){
  20.142 +        err = -EINVAL;
  20.143 +        goto exit;
  20.144 +    }
  20.145 +    if(r) *flags |= LZI_READ;
  20.146 +    if(w) *flags |= LZI_WRITE;
  20.147 +  exit:
  20.148 +    return err;
  20.149 +}
  20.150 +
  20.151 +/** Get the stream state.
  20.152 + * 
  20.153 + * @param s lzi stream
  20.154 + * @return stream state.
  20.155 + */
  20.156 +static inline LZIState * lzi_state(IOStream *io){
  20.157 +    return io->data;
  20.158 +}
  20.159 +
  20.160 +IOStream *lzi_stream_io(IOStream *io){
  20.161 +    LZIState *s = lzi_state(io);
  20.162 +    return s->io;
  20.163 +}
  20.164 +
  20.165 +static inline void set_error(LZIState *s, int err){
  20.166 +    if(err < 0 && !s->error){
  20.167 +        s->error = err;
  20.168 +    }
  20.169 +}
  20.170 +
  20.171 +static int zerror(LZIState *s, int err){
  20.172 +    if(err){
  20.173 +        //dprintf("> err=%d\n", err);
  20.174 +        if(err < 0) set_error(s, -EIO);
  20.175 +    }
  20.176 +    return s->error;
  20.177 +}
  20.178 +
  20.179 +int lzi_stream_plain_bytes(IOStream *io){
  20.180 +    LZIState *s = lzi_state(io);
  20.181 +    return s->plain_bytes;
  20.182 +}
  20.183 +
  20.184 +int lzi_stream_comp_bytes(IOStream *io){
  20.185 +    LZIState *s = lzi_state(io);
  20.186 +    return s->comp_bytes;
  20.187 +}
  20.188 +
  20.189 +float lzi_stream_ratio(IOStream *io){
  20.190 +    LZIState *s = lzi_state(io);
  20.191 +    float ratio = 0.0;
  20.192 +    if(s->comp_bytes){
  20.193 +        ratio = ((float) s->comp_bytes)/((float) s->plain_bytes);
  20.194 +    }
  20.195 +    return ratio;
  20.196 +}
  20.197 +
  20.198 +static int alloc(void **p, int n){
  20.199 +    *p = allocate(n);
  20.200 +    return (p ? 0 : -ENOMEM);
  20.201 +}
  20.202 +
  20.203 +LZIState * LZIState_new(IOStream *io, int flags){
  20.204 +    int err = -ENOMEM;
  20.205 +    int zlevel = Z_BEST_SPEED; // Level 1 compression - fastest.
  20.206 +    int zstrategy = Z_DEFAULT_STRATEGY;
  20.207 +    int zwindow = MAX_WBITS;
  20.208 +    int zmemory = 8;
  20.209 +    LZIState *z = ALLOCATE(LZIState);
  20.210 +
  20.211 +    //dprintf(">\n");
  20.212 +    if(!z) goto exit;
  20.213 +    z->io = io;
  20.214 +    z->flags = flags;
  20.215 +
  20.216 +    if(LZIState_writeable(z)){
  20.217 +        z->outbuf_size = BUFFER_SIZE;
  20.218 +        /* windowBits is passed < 0 to suppress zlib header */
  20.219 +        err = deflateInit2(&z->zstream, zlevel, Z_DEFLATED, -zwindow, zmemory, zstrategy);
  20.220 +        if (err != Z_OK) goto exit;
  20.221 +        z->zstream_initialized = 1;
  20.222 +        err = alloc(&z->outbuf, z->outbuf_size);
  20.223 +        if(err) goto exit;
  20.224 +        z->zstream.next_out = z->outbuf;
  20.225 +        z->zstream.avail_out = z->outbuf_size;
  20.226 +    } else {
  20.227 +        z->inbuf_size = BUFFER_SIZE;
  20.228 +        err = alloc(&z->inbuf, z->inbuf_size);
  20.229 +        if(err) goto exit;
  20.230 +        ///z->zstream.next_in  = z->inbuf;
  20.231 +
  20.232 +        /* windowBits is passed < 0 to tell that there is no zlib header.
  20.233 +         * Note that in this case inflate *requires* an extra "dummy" byte
  20.234 +         * after the compressed stream in order to complete decompression and
  20.235 +         * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
  20.236 +         * present after the compressed stream.
  20.237 +         */
  20.238 +        err = inflateInit2(&z->zstream, -zwindow);
  20.239 +        if(err != Z_OK) goto exit;
  20.240 +        z->zstream_initialized = 1;
  20.241 +    }
  20.242 +        
  20.243 +  exit:
  20.244 +    if(err){
  20.245 +        LZIState_free(z);
  20.246 +        z = NULL;
  20.247 +    }
  20.248 +    //dprintf("< z=%p\n", z);
  20.249 +    return z;
  20.250 +}
  20.251 +
  20.252 +int read_block(LZIState *s){
  20.253 +    int err = 0, k = 0;
  20.254 +    //dprintf(">\n");
  20.255 +    if(s->eof) goto exit;
  20.256 +    err = unmarshal_uint32(s->io, &k);
  20.257 +    if(err) goto exit;
  20.258 +    if(k > s->inbuf_size){
  20.259 +        err = -EINVAL;
  20.260 +        goto exit;
  20.261 +    }
  20.262 +    if(k){
  20.263 +        err = unmarshal_bytes(s->io, s->inbuf, k);
  20.264 +        if(err) goto exit;
  20.265 +    } else {
  20.266 +        s->eof = 1;
  20.267 +    }        
  20.268 +    s->zstream.avail_in = k;
  20.269 +    s->zstream.next_in = s->inbuf;
  20.270 +    s->comp_bytes += 4;
  20.271 +    s->comp_bytes += k;
  20.272 +  exit:
  20.273 +    //dprintf("< err=%d\n", err);
  20.274 +    return err;
  20.275 +}
  20.276 +
  20.277 +int write_block(LZIState *s){
  20.278 +    int err = 0;
  20.279 +    int k = ((char*)s->zstream.next_out) - ((char*)s->outbuf);
  20.280 +    int k2 = s->outbuf_size - s->zstream.avail_out;
  20.281 +    //dprintf("> k=%d k2=%d\n", k, k2);
  20.282 +    if(!k) goto exit;
  20.283 +    err = marshal_uint32(s->io, k);
  20.284 +    if(err) goto exit;
  20.285 +    err = marshal_bytes(s->io, s->outbuf, k);
  20.286 +    if(err) goto exit;
  20.287 +    s->zstream.next_out = s->outbuf;
  20.288 +    s->zstream.avail_out = s->outbuf_size;
  20.289 +    s->comp_bytes += 4;
  20.290 +    s->comp_bytes += k;
  20.291 +  exit:
  20.292 +    //dprintf("< err=%d\n", err);
  20.293 +    return err;
  20.294 +}
  20.295 +
  20.296 +int write_terminator(LZIState *s){
  20.297 +    int err = 0;
  20.298 +    char c = 0;
  20.299 +    err = marshal_uint32(s->io, 1);
  20.300 +    if(err) goto exit;
  20.301 +    err = marshal_bytes(s->io, &c, 1);
  20.302 +    if(err) goto exit;
  20.303 +    err = marshal_uint32(s->io, 0);
  20.304 +    if(err) goto exit;
  20.305 +    s->comp_bytes += 9;
  20.306 +  exit:
  20.307 +    return err;
  20.308 +}
  20.309 +
  20.310 +/** Write to the underlying stream using fwrite();
  20.311 + *
  20.312 + * @param io destination
  20.313 + * @param buf data
  20.314 + * @param size size of data elements
  20.315 + * @param count number of data elements to write
  20.316 + * @return number of data elements written
  20.317 + */
  20.318 +static int lzi_write(IOStream *io, const void *buf, size_t size, size_t count){
  20.319 +    int err = 0;
  20.320 +    int n = size * count;
  20.321 +    LZIState *s = lzi_state(io);
  20.322 +
  20.323 +    //dprintf("> buf=%p size=%d count=%d n=%d\n", buf, size, count, n);
  20.324 +    if(!LZIState_writeable(s)){
  20.325 +        err = -EINVAL;
  20.326 +        goto exit;
  20.327 +    }
  20.328 +    s->flushed = 0;
  20.329 +    s->zstream.next_in = (void*)buf;
  20.330 +    s->zstream.avail_in = n;
  20.331 +    while(s->zstream.avail_in){
  20.332 +        if(s->zstream.avail_out == 0){
  20.333 +            err = write_block(s);
  20.334 +            if(err) goto exit;
  20.335 +        }
  20.336 +        //dprintf("> 1 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
  20.337 +        //dprintf("> 1 deflate next_in=%p next_out=%p\n", s->zstream.next_in, s->zstream.next_out);
  20.338 +        err = zerror(s, deflate(&s->zstream, Z_NO_FLUSH));
  20.339 +        //dprintf("> 2 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
  20.340 +        //dprintf("> 2 deflate next_in=%p next_out=%p\n", s->zstream.next_in, s->zstream.next_out);
  20.341 +        if(err) goto exit;
  20.342 +    }
  20.343 +    err = n;
  20.344 +    s->plain_bytes += n;
  20.345 +    if(size != 1) err /= size;
  20.346 +  exit:
  20.347 +    //dprintf("< err=%d\n", err);
  20.348 +    return err;
  20.349 +}
  20.350 +
  20.351 +
  20.352 +/** Read from the underlying stream.
  20.353 + *
  20.354 + * @param io input
  20.355 + * @param buf where to put input
  20.356 + * @param size size of data elements
  20.357 + * @param count number of data elements to read
  20.358 + * @return number of data elements read
  20.359 + */
  20.360 +static int lzi_read(IOStream *io, void *buf, size_t size, size_t count){
  20.361 +    int err, zerr;
  20.362 +    int n = size * count;
  20.363 +    LZIState *s = lzi_state(io);
  20.364 +
  20.365 +    //dprintf("> size=%d count=%d n=%d\n", size, count, n);
  20.366 +    if(!LZIState_readable(s)){
  20.367 +        err = -EINVAL;
  20.368 +        goto exit;
  20.369 +    }
  20.370 +    s->zstream.next_out = buf;
  20.371 +    s->zstream.avail_out = n;
  20.372 +    while(s->zstream.avail_out){
  20.373 +        if(s->zstream.avail_in == 0){
  20.374 +            err = read_block(s);
  20.375 +        }
  20.376 +        //dprintf("> 1 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
  20.377 +        zerr = inflate(&s->zstream, Z_NO_FLUSH);
  20.378 +        //dprintf("> 2 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
  20.379 +        if(zerr == Z_STREAM_END) break;
  20.380 +        //dprintf("> zerr=%d\n", zerr);
  20.381 +        err = zerror(s, zerr);
  20.382 +        if(err) goto exit;
  20.383 +    }
  20.384 +    err = n - s->zstream.avail_out;
  20.385 +    s->plain_bytes += err;
  20.386 +    if(size != 1) err /= size;
  20.387 +  exit:
  20.388 +    set_error(s, err);
  20.389 +    //dprintf("< err=%d\n", err);
  20.390 +    return err;
  20.391 +}
  20.392 +
  20.393 +/** Print to the underlying stream.
  20.394 + * Returns 0 if the formatted output is too big for the internal buffer.
  20.395 + *
  20.396 + * @param io lzi stream
  20.397 + * @param msg format to use
  20.398 + * @param args arguments
  20.399 + * @return result of the print
  20.400 + */
  20.401 +static int lzi_print(IOStream *io, const char *msg, va_list args){
  20.402 +    char buf[1024];
  20.403 +    int buf_n = sizeof(buf);
  20.404 +    int n;
  20.405 +    LZIState *s = lzi_state(io);
  20.406 +    if(!LZIState_writeable(s)){
  20.407 +        n = -EINVAL;
  20.408 +        goto exit;
  20.409 +    }
  20.410 +    n = vsnprintf(buf, buf_n, (char*)msg, args);
  20.411 +    if(n < 0) goto exit;
  20.412 +    if(n > buf_n){
  20.413 +        n = 0;
  20.414 +    } else {
  20.415 +        n = lzi_write(io, buf, 1, n);
  20.416 +    }
  20.417 +  exit:
  20.418 +    return n;
  20.419 +}
  20.420 +
  20.421 +/** Read a character from the underlying stream
  20.422 + *
  20.423 + * @param io lzi stream
  20.424 + * @return character read, IOSTREAM_EOF on end of file (or error)
  20.425 + */
  20.426 +static int lzi_getc(IOStream *io){
  20.427 +    int err;
  20.428 +    char c;
  20.429 +    err = lzi_read(io, &c, 1, 1);
  20.430 +    if(err < 1) c = EOF;
  20.431 +    err = (c==EOF ? IOSTREAM_EOF : c);
  20.432 +    return err;
  20.433 +}
  20.434 +
  20.435 +static int flush_output(LZIState *s, int mode){
  20.436 +    int err = 0, zerr;
  20.437 +    int done = 0;
  20.438 +    int avail_out_old;
  20.439 +    int count = 10;
  20.440 +
  20.441 +    //dprintf("> avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
  20.442 +    if(s->flushed == 1 + mode) goto exit;
  20.443 +    //s->zstream.avail_in = 0; /* should be zero already anyway */
  20.444 +    for(;;){
  20.445 +        // Write any available output.
  20.446 +        if(done || s->zstream.avail_out == 0){
  20.447 +            err = write_block(s);
  20.448 +            if(err) goto exit;
  20.449 +            if(done) break;
  20.450 +        }
  20.451 +        //dprintf("> 1 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
  20.452 +        avail_out_old = s->zstream.avail_out;
  20.453 +        zerr = deflate(&s->zstream, mode);
  20.454 +        err = zerror(s, zerr);
  20.455 +        //dprintf("> 2 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
  20.456 +        //dprintf("> deflate=%d\n", err);
  20.457 +        //done = (s->zstream.avail_out != 0);
  20.458 +        //done = (s->zstream.avail_in == 0) && (s->zstream.avail_out == avail_out_old);
  20.459 +        if(0 && mode == Z_FINISH){
  20.460 +            done = (zerr ==  Z_STREAM_END);
  20.461 +        } else {
  20.462 +            done = (s->zstream.avail_in == 0)
  20.463 +                //&& (s->zstream.avail_out == avail_out_old)
  20.464 +                && (s->zstream.avail_out != 0);
  20.465 +        }
  20.466 +    }
  20.467 +    s->flushed = 1 + mode;
  20.468 +  exit:
  20.469 +    //dprintf("< err=%d\n", err);
  20.470 +    return err;
  20.471 +}
  20.472 +
  20.473 +/** Flush any pending input to the underlying stream.
  20.474 + *
  20.475 + * @param s lzi stream
  20.476 + * @return 0 on success, error code otherwise
  20.477 + */
  20.478 +static int lzi_flush(IOStream *io){
  20.479 +    int err = 0;
  20.480 +    LZIState *s = lzi_state(io);
  20.481 +    //dprintf(">\n");
  20.482 +    if(!LZIState_writeable(s)){
  20.483 +        err = -EINVAL;
  20.484 +        goto exit;
  20.485 +    }
  20.486 +    err = flush_output(s, Z_SYNC_FLUSH);
  20.487 +    if(err) goto exit;
  20.488 +    err = IOStream_flush(s->io);
  20.489 +  exit:
  20.490 +    set_error(s, err);
  20.491 +    //dprintf("< err=%d\n", err);
  20.492 +    return (err < 0 ? err : 0);
  20.493 +}
  20.494 +
  20.495 +/** Check if a stream has an error.
  20.496 + *
  20.497 + * @param s lzi stream
  20.498 + * @return code if has an error, 0 otherwise
  20.499 + */
  20.500 +static int lzi_error(IOStream *s){
  20.501 +    int err = 0;
  20.502 +    LZIState *state = lzi_state(s);
  20.503 +    err = state->error;
  20.504 +    if(err) goto exit;
  20.505 +    err = IOStream_error(state->io);
  20.506 +  exit:
  20.507 +    return err;
  20.508 +}
  20.509 +
  20.510 +/** Close an lzi stream.
  20.511 + *
  20.512 + * @param s lzi stream to close
  20.513 + * @return result of the close
  20.514 + */
  20.515 +static int lzi_close(IOStream *io){
  20.516 +    int err = 0;
  20.517 +    LZIState *s = lzi_state(io);
  20.518 +    if(LZIState_writeable(s)){
  20.519 +        err = flush_output(s, Z_FINISH);
  20.520 +        if(err) goto exit;
  20.521 +        err = write_terminator(s);
  20.522 +        if(err) goto exit;
  20.523 +        err = IOStream_flush(s->io);
  20.524 +    }   
  20.525 +  exit:
  20.526 +    err = IOStream_close(s->io);
  20.527 +    set_error(s, err);
  20.528 +    return err;
  20.529 +}
  20.530 +
  20.531 +/** Free an lzi stream.
  20.532 + *
  20.533 + * @param s lzi stream
  20.534 + */
  20.535 +static void lzi_free(IOStream *s){
  20.536 +    LZIState *state = lzi_state(s);
  20.537 +    IOStream_free(state->io);
  20.538 +    LZIState_free(state);
  20.539 +    s->data = NULL;
  20.540 +}
  20.541 +
  20.542 +/** Create an lzi stream for an IOStream.
  20.543 + *
  20.544 + * @param io stream to wrap
  20.545 + * @return new IOStream using f for i/o
  20.546 + */
  20.547 +IOStream *lzi_stream_new(IOStream *io, const char *mode){
  20.548 +    int err = -ENOMEM;
  20.549 +    int flags = 0;
  20.550 +    IOStream *zio = NULL;
  20.551 +    LZIState *state = NULL;
  20.552 +
  20.553 +    zio = ALLOCATE(IOStream);
  20.554 +    if(!zio) goto exit;
  20.555 +    err = mode_flags(mode, &flags);
  20.556 +    if(err) goto exit;
  20.557 +    state = LZIState_new(io, flags);
  20.558 +    if(!state) goto exit;
  20.559 +    err = 0;
  20.560 +    zio->data = state;
  20.561 +    zio->methods = &lzi_methods;
  20.562 +  exit:
  20.563 +    if(err){
  20.564 +        if(state) LZIState_free(state);
  20.565 +        if(zio) deallocate(zio);
  20.566 +        zio = NULL;
  20.567 +    }
  20.568 +    return zio;
  20.569 +}
  20.570 +
  20.571 +/** IOStream version of fdopen().
  20.572 + *
  20.573 + * @param fd file descriptor
  20.574 + * @param flags giving the mode to open in (as for fdopen())
  20.575 + * @return new stream for the open file, or NULL if failed
  20.576 + */
  20.577 +IOStream *lzi_stream_fdopen(int fd, const char *mode){
  20.578 +    int err = -ENOMEM;
  20.579 +    IOStream *io = NULL, *zio = NULL;
  20.580 +    io = file_stream_fdopen(fd, mode);
  20.581 +    if(!io) goto exit;
  20.582 +    zio = lzi_stream_new(io, mode);
  20.583 +    if(!io) goto exit;
  20.584 +    err = 0;
  20.585 +  exit:
  20.586 +    if(err){
  20.587 +        IOStream_free(io);
  20.588 +        IOStream_free(zio);
  20.589 +        zio = NULL;
  20.590 +    }
  20.591 +    return zio;
  20.592 +}
  20.593 +#endif
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/tools/lib/lzi_stream.h	Mon Jun 28 15:03:15 2004 +0000
    21.3 @@ -0,0 +1,36 @@
    21.4 +#/* $Id: lzi_stream.h,v 1.3 2003/09/30 15:22:53 mjw Exp $ */
    21.5 +/*
    21.6 + * Copyright (C) 2003 Hewlett-Packard Company.
    21.7 + *
    21.8 + * This library is free software; you can redistribute it and/or modify
    21.9 + * it under the terms of the GNU Lesser General Public License as published by
   21.10 + * the Free Software Foundation; either version 2.1 of the License, or
   21.11 + * (at your option) any later version.
   21.12 + *
   21.13 + * This library is distributed in the hope that it will be useful,
   21.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   21.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   21.16 + * GNU Lesser General Public License for more details.
   21.17 + *
   21.18 + * You should have received a copy of the GNU Lesser General Public License
   21.19 + * along with this library; if not, write to the Free Software
   21.20 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   21.21 + */
   21.22 +
   21.23 +#ifndef _SP_LZI_STREAM_H_
   21.24 +#define _SP_LZI_STREAM_H_
   21.25 +
   21.26 +#ifndef __KERNEL__
   21.27 +#include "iostream.h"
   21.28 +
   21.29 +extern IOStream *lzi_stream_new(IOStream *io, const char *mode);
   21.30 +extern IOStream *lzi_stream_fopen(const char *file, const char *mode);
   21.31 +extern IOStream *lzi_stream_fdopen(int fd, const char *mode);
   21.32 +extern IOStream *lzi_stream_io(IOStream *zio);
   21.33 +
   21.34 +extern int lzi_stream_plain_bytes(IOStream *io);
   21.35 +extern int lzi_stream_comp_bytes(IOStream *io);
   21.36 +extern float lzi_stream_ratio(IOStream *io);
   21.37 +
   21.38 +#endif
   21.39 +#endif /* !_SP_FILE_STREAM_H_ */
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/tools/lib/lzo_stream.c	Mon Jun 28 15:03:15 2004 +0000
    22.3 @@ -0,0 +1,596 @@
    22.4 +/* $Id: lzo_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $ */
    22.5 +#define __FILE_ID_INFO "$Id: lzo_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $"
    22.6 +#include <what.h>
    22.7 +static char __rcsid[] __attribute__((unused)) = WHAT_ID __FILE_ID_INFO;
    22.8 +/*
    22.9 + * Copyright (C) 2003 Hewlett-Packard Company.
   22.10 + *
   22.11 + * This library is free software; you can redistribute it and/or modify
   22.12 + * it under the terms of the GNU Lesser General Public License as published by
   22.13 + * the Free Software Foundation; either version 2.1 of the License, or
   22.14 + * (at your option) any later version.
   22.15 + *
   22.16 + * This library is distributed in the hope that it will be useful,
   22.17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   22.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   22.19 + * GNU Lesser General Public License for more details.
   22.20 + *
   22.21 + * You should have received a copy of the GNU Lesser General Public License
   22.22 + * along with this library; if not, write to the Free Software
   22.23 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   22.24 + */
   22.25 +
   22.26 +/** @file
   22.27 + * An IOStream implementation using LZO to provide compression and decompression.
   22.28 + * This is designed to provide reasonable compression without output latency.
   22.29 + * Flushing an LZO stream flushes all pending data to the underlying stream.
   22.30 + * This is essential for stream-based (e.g. networked) applications.
   22.31 + *
   22.32 + * A compressed data stream is a sequence of blocks.
   22.33 + * Each block except the last is the plain data size followed by the compressed data size
   22.34 + * and the compressed data. The last block has plain data size zero and omits the rest.
   22.35 + * Sizes are 4-byte unsigned in network order. If the compressed size is smaller than
   22.36 + * the plain size the block data is compressed, otherwise it is plain (uncompressed).
   22.37 + *
   22.38 + * This format allows compressed data to be read from a stream without reading
   22.39 + * past the logical end of compressed data.
   22.40 + *
   22.41 + * @author Mike Wray <mike.wray@hpl.hp.com>
   22.42 + */
   22.43 +#ifndef __KERNEL__
   22.44 +
   22.45 +#include <stdio.h>
   22.46 +#include <stdlib.h>
   22.47 +#include <errno.h>
   22.48 +#include <string.h>
   22.49 +
   22.50 +#include "lzo1x.h"
   22.51 +
   22.52 +#include "allocate.h"
   22.53 +#include "lzo_stream.h"
   22.54 +#include "file_stream.h"
   22.55 +#include "marshal.h"
   22.56 +
   22.57 +#define dprintf(fmt, args...) fprintf(stdout, "[DEBUG] LZO>%s" fmt, __FUNCTION__, ##args)
   22.58 +#define wprintf(fmt, args...) fprintf(stderr, "[WARN]  LZO>%s" fmt, __FUNCTION__, ##args)
   22.59 +#define iprintf(fmt, args...) fprintf(stdout, "[INFO]  LZO>%s" fmt, __FUNCTION__, ##args)
   22.60 +#define eprintf(fmt, args...) fprintf(stderr, "[ERROR] LZO>%s" fmt, __FUNCTION__, ##args)
   22.61 +
   22.62 +static int lzo_read(IOStream *s, void *buf, size_t size, size_t count);
   22.63 +static int lzo_write(IOStream *s, const void *buf, size_t size, size_t count);
   22.64 +static int lzo_print(IOStream *s, const char *msg, va_list args);
   22.65 +static int lzo_getc(IOStream *s);
   22.66 +static int lzo_error(IOStream *s);
   22.67 +static int lzo_close(IOStream *s);
   22.68 +static void lzo_free(IOStream *s);
   22.69 +static int lzo_flush(IOStream *s);
   22.70 +
   22.71 +enum {
   22.72 +    LZO_WRITE = 1,
   22.73 +    LZO_READ = 2,
   22.74 +};
   22.75 +
   22.76 +/** Methods used by a gzFile* IOStream. */
   22.77 +static const IOMethods lzo_methods = {
   22.78 +    read: lzo_read,
   22.79 +    write: lzo_write,
   22.80 +    print: lzo_print,
   22.81 +    getc:  lzo_getc,
   22.82 +    error: lzo_error,
   22.83 +    close: lzo_close,
   22.84 +    free:  lzo_free,
   22.85 +    flush: lzo_flush,
   22.86 +};
   22.87 +
   22.88 +//#define PLAIN_SIZE (64 * 1024)
   22.89 +//#define PLAIN_SIZE (128 * 1024)
   22.90 +#define PLAIN_SIZE (512 * 1024)
   22.91 +
   22.92 +//#define NOCOMPRESS
   22.93 +
   22.94 +typedef struct LZOState {
   22.95 +    /** Flags. */
   22.96 +    int flags;
   22.97 +    /** Error indicator. */
   22.98 +    int error;
   22.99 +    /** Underlying stream for I/O. */
  22.100 +    IOStream *io;
  22.101 +    /** Working memory (only needed for compression, not decompression). */
  22.102 +    lzo_byte *memory;
  22.103 +    /** Buffer for plain (uncompressed) data. */
  22.104 +    lzo_byte *plain;
  22.105 +    /** Size of the plain buffer. */
  22.106 +    lzo_uint plain_size;
  22.107 +    /** Pointer into the plain buffer. */
  22.108 +    lzo_byte *plain_ptr;
  22.109 +    /** Number of bytes of plain data available. */
  22.110 +    lzo_uint plain_n;
  22.111 +    /** Buffer for compressed data. */
  22.112 +    lzo_byte *comp;
  22.113 +    /** Size of the compressed buffer. */
  22.114 +    lzo_uint comp_size;
  22.115 +
  22.116 +    int plain_bytes;
  22.117 +    int comp_bytes;
  22.118 +} LZOState;
  22.119 +
  22.120 +void LZOState_free(LZOState *z){
  22.121 +    if(!z) return;
  22.122 +    deallocate(z->memory);
  22.123 +    deallocate(z->plain);
  22.124 +    deallocate(z->comp);
  22.125 +    deallocate(z);
  22.126 +}
  22.127 +
  22.128 +/** Maximum size of compressed data for the given plain data size.
  22.129 + *
  22.130 + * @param plain_size size of plain data
  22.131 + * @return maximum size of compressed data
  22.132 + */
  22.133 +static int comp_size(int plain_size){
  22.134 +    return plain_size + (plain_size / 64) + 16 + 3;
  22.135 +}
  22.136 +
  22.137 +static int mode_flags(const char *mode, int *flags){
  22.138 +    int err = 0;
  22.139 +    int r=0, w=0;
  22.140 +    if(!mode){
  22.141 +        err = -EINVAL;
  22.142 +        goto exit;
  22.143 +    }
  22.144 +    for(; *mode; mode++){
  22.145 +        if(*mode == 'w') w = 1;
  22.146 +        if(*mode == 'r') r = 1;
  22.147 +    }
  22.148 +    if(r + w != 1){
  22.149 +        err = -EINVAL;
  22.150 +        goto exit;
  22.151 +    }
  22.152 +    if(r) *flags |= LZO_READ;
  22.153 +    if(w) *flags |= LZO_WRITE;
  22.154 +  exit:
  22.155 +    return err;
  22.156 +}
  22.157 +
  22.158 +/** Get the stream state.
  22.159 + * 
  22.160 + * @param s lzo stream
  22.161 + * @return stream state.
  22.162 + */
  22.163 +static inline LZOState * lzo_state(IOStream *s){
  22.164 +    return s->data;
  22.165 +}
  22.166 +
  22.167 +IOStream *lzo_stream_io(IOStream *s){
  22.168 +    LZOState *state = lzo_state(s);
  22.169 +    return state->io;
  22.170 +}
  22.171 +
  22.172 +static inline void set_error(LZOState *state, int err){
  22.173 +    if(err < 0 && !state->error){
  22.174 +        state->error = err;
  22.175 +    }
  22.176 +}
  22.177 +
  22.178 +int lzo_stream_plain_bytes(IOStream *s){
  22.179 +    LZOState *state = lzo_state(s);
  22.180 +    return state->plain_bytes;
  22.181 +}
  22.182 +
  22.183 +int lzo_stream_comp_bytes(IOStream *s){
  22.184 +    LZOState *state = lzo_state(s);
  22.185 +    return state->comp_bytes;
  22.186 +}
  22.187 +
  22.188 +float lzo_stream_ratio(IOStream *s){
  22.189 +    LZOState *state = lzo_state(s);
  22.190 +    float ratio = 0.0;
  22.191 +    if(state->comp_bytes){
  22.192 +        ratio = ((float) state->comp_bytes)/((float) state->plain_bytes);
  22.193 +    }
  22.194 +    return ratio;
  22.195 +}
  22.196 +
  22.197 +static inline int LZOState_writeable(LZOState *state){
  22.198 +    return (state->flags & LZO_WRITE) != 0;
  22.199 +}
  22.200 +
  22.201 +static inline int LZOState_readable(LZOState *state){
  22.202 +    return (state->flags & LZO_READ) != 0;
  22.203 +}
  22.204 +
  22.205 +LZOState * LZOState_new(IOStream *io, int flags){
  22.206 +    int err = -ENOMEM;
  22.207 +    LZOState *z = ALLOCATE(LZOState);
  22.208 +    //dprintf(">\n");
  22.209 +    if(!z) goto exit;
  22.210 +    z->io = io;
  22.211 +    z->flags = flags;
  22.212 +    if(LZOState_writeable(z)){
  22.213 +        z->memory = allocate(LZO1X_1_MEM_COMPRESS);
  22.214 +        if(!z->memory) goto exit;
  22.215 +    }
  22.216 +    z->plain_size = PLAIN_SIZE;
  22.217 +    z->plain = allocate(z->plain_size);
  22.218 +    if(!z->plain) goto exit;
  22.219 +    z->plain_ptr = z->plain;
  22.220 +    z->comp_size = comp_size(z->plain_size);
  22.221 +    z->comp = allocate(z->comp_size);
  22.222 +    if(!z->comp) goto exit;
  22.223 +    err = 0;
  22.224 +  exit:
  22.225 +    if(err){
  22.226 +        LZOState_free(z);
  22.227 +        z = NULL;
  22.228 +    }
  22.229 +    //dprintf("< z=%p\n", z);
  22.230 +    return z;
  22.231 +}
  22.232 +
  22.233 +static int lzo_compress(LZOState *state){
  22.234 +    int err = 0;
  22.235 +    int k, comp_n;
  22.236 +    //dprintf(">\n");
  22.237 +    //dprintf(">plain=%p plain_n=%d comp=%p memory=%p\n", state->plain, state->plain_n, state->comp, state->memory);
  22.238 +    // Compress the plain buffer.
  22.239 +    err = lzo1x_1_compress(state->plain, state->plain_n,
  22.240 +                           state->comp, &comp_n,
  22.241 +                           state->memory);
  22.242 +    //dprintf("> err=%d plain_n=%d comp_n=%d\n", err, state->plain_n, comp_n);
  22.243 +    // Write plain size, compressed size.
  22.244 +    err = marshal_uint32(state->io, state->plain_n);
  22.245 +    if(err) goto exit;
  22.246 +    err = marshal_uint32(state->io, comp_n);
  22.247 +    if(err) goto exit;
  22.248 +    //dprintf("> write data...\n");
  22.249 +    // Write the smaller of the compressed and plain data.
  22.250 +    if(state->plain_n < comp_n){
  22.251 +        k = state->plain_n;
  22.252 +        err = marshal_bytes(state->io, state->plain, state->plain_n);
  22.253 +    } else {
  22.254 +        k = comp_n;
  22.255 +        err = marshal_bytes(state->io, state->comp, comp_n);
  22.256 +    }
  22.257 +    if(err) goto exit;
  22.258 +    // Total output bytes.
  22.259 +    k+= 8;
  22.260 +    //dprintf("> wrote %d bytes\n", k);
  22.261 +    state->plain_bytes += state->plain_n;
  22.262 +    state->comp_bytes += k;
  22.263 +    //dprintf("> plain=%d, comp=%d, ratio=%3.2f\n",
  22.264 +    //        state->plain_bytes, state->comp_bytes,
  22.265 +    //        ((float)state->comp_bytes)/((float)state->plain_bytes));
  22.266 +    // Reset the plain buffer.
  22.267 +    state->plain_ptr = state->plain;
  22.268 +    state->plain_n = 0;
  22.269 +    err = k;
  22.270 +  exit:
  22.271 +    //dprintf("< err=%d\n", err);
  22.272 +    return err;
  22.273 +}
  22.274 +
  22.275 +static int lzo_decompress(LZOState *state){
  22.276 +    int plain_n, comp_n;
  22.277 +    int err, k;
  22.278 +    //dprintf(">\n");
  22.279 +    err = unmarshal_uint32(state->io, &plain_n);
  22.280 +    //dprintf("> err=%d plain_n=%d\n", err, plain_n);
  22.281 +    if(err) goto exit;
  22.282 +    state->comp_bytes += 4;
  22.283 +    if(plain_n == 0) goto exit;
  22.284 +    err = unmarshal_uint32(state->io, &comp_n);
  22.285 +    //dprintf("> err=%d comp_n=%d\n", err, comp_n);
  22.286 +    if(err) goto exit;
  22.287 +    state->comp_bytes += 4;
  22.288 +    if(plain_n > state->plain_size){
  22.289 +        err = -EINVAL;
  22.290 +        goto exit;
  22.291 +    }
  22.292 +    if(comp_n > plain_n){
  22.293 +        //dprintf("> reading plain data %d...\n", plain_n);
  22.294 +        k = plain_n;
  22.295 +        err = unmarshal_bytes(state->io, state->plain, plain_n);
  22.296 +        state->plain_n = plain_n;
  22.297 +    } else {
  22.298 +        //dprintf("> reading comp data %d...\n", comp_n);
  22.299 +        k = comp_n;
  22.300 +        err = unmarshal_bytes(state->io, state->comp, comp_n);
  22.301 +        //dprintf("> decompress comp_n=%d\n", comp_n);
  22.302 +        err = lzo1x_decompress(state->comp, comp_n,
  22.303 +                               state->plain, &state->plain_n,
  22.304 +                               state->memory);
  22.305 +        //dprintf("> err=%d plain=%d state->plain_n=%d\n", err, plain_n, state->plain_n);
  22.306 +        if(err != LZO_E_OK || state->plain_n != plain_n){
  22.307 +            // Bad. Corrupted input.
  22.308 +            err = -EINVAL;
  22.309 +            eprintf("> Corrupted!\n");
  22.310 +            goto exit;
  22.311 +        }
  22.312 +    }
  22.313 +    state->comp_bytes += k;
  22.314 +    state->plain_bytes += state->plain_n;
  22.315 +    state->plain_ptr = state->plain;
  22.316 +    err = k;
  22.317 +  exit:
  22.318 +    //dprintf("< err=%d\n", err);
  22.319 +    return err;
  22.320 +}
  22.321 +
  22.322 +/** Write to the underlying stream using fwrite();
  22.323 + *
  22.324 + * @param stream destination
  22.325 + * @param buf data
  22.326 + * @param size size of data elements
  22.327 + * @param count number of data elements to write
  22.328 + * @return number of data elements written
  22.329 + */
  22.330 +static int lzo_write(IOStream *s, const void *buf, size_t size, size_t count){
  22.331 +    int err = 0;
  22.332 +    int n = size * count; // Total number of bytes to write.
  22.333 +    int chunk;            // Size of chunk to write.
  22.334 +    int remaining;        // Number of bytes remaining to write.
  22.335 +    int space;            // Amount of space left in plain buffer.
  22.336 +    LZOState *state = lzo_state(s);
  22.337 +#ifdef NOCOMPRESS
  22.338 +    //dprintf("> buf=%p size=%d count=%d\n", buf, size, count);
  22.339 +    err = IOStream_write(state->io, buf, size, count);
  22.340 +    //dprintf("< err=%d\n", err);
  22.341 +#else
  22.342 +    //dprintf("> buf=%p size=%d count=%d n=%d\n", buf, size, count, n);
  22.343 +    remaining = n;
  22.344 +    space = state->plain_size - state->plain_n;
  22.345 +    //dprintf("> plain=%p plain_ptr=%p plain_n=%d space=%d\n",
  22.346 +    //        state->plain, state->plain_ptr, state->plain_n, space);
  22.347 +    while(remaining){
  22.348 +        chunk = remaining;
  22.349 +        if(chunk > space) chunk = space;
  22.350 +        //dprintf("> memcpy %p %p %d\n", state->plain_ptr, buf, chunk);
  22.351 +        memcpy(state->plain_ptr, buf, chunk);
  22.352 +        remaining -= chunk;
  22.353 +        space -= chunk;
  22.354 +        state->plain_ptr += chunk;
  22.355 +        state->plain_n += chunk;
  22.356 +        if(space == 0){
  22.357 +            // Input buffer is full. Compress and write it.
  22.358 +            err = lzo_compress(state);
  22.359 +            if(err < 0) goto exit;
  22.360 +            space = state->plain_size - state->plain_n;
  22.361 +        }
  22.362 +    }
  22.363 +    err = (size > 1 ? n / size : n);
  22.364 +  exit:
  22.365 +    set_error(state, err);
  22.366 +#endif
  22.367 +    return err;
  22.368 +}
  22.369 +
  22.370 +
  22.371 +/** Read from the underlying stream.
  22.372 + *
  22.373 + * @param stream input
  22.374 + * @param buf where to put input
  22.375 + * @param size size of data elements
  22.376 + * @param count number of data elements to read
  22.377 + * @return number of data elements read
  22.378 + */
  22.379 +static int lzo_read(IOStream *s, void *buf, size_t size, size_t count){
  22.380 +    int err = 0;
  22.381 +    int k = 0;                     // Number of (plain) bytes read.
  22.382 +    int remaining = size * count;  // Number of bytes remaining to read.
  22.383 +    int chunk;                     // Size of chunk to read.
  22.384 +    LZOState *state = lzo_state(s);
  22.385 +#ifdef NOCOMPRESS
  22.386 +    //dprintf("> buf=%p size=%d count=%d\n", buf, size, count);
  22.387 +    err = IOStream_read(state->io, buf, size, count);
  22.388 +    //dprintf("< err=%d\n", err);
  22.389 +#else
  22.390 +    if(!(state->flags & LZO_READ)){
  22.391 +        err = -EINVAL;
  22.392 +        goto exit;
  22.393 +    }
  22.394 +    while(remaining){
  22.395 +        if(state->plain_n == 0){
  22.396 +            // No more plain input, decompress some more.
  22.397 +            err = lzo_decompress(state);
  22.398 +            if(err < 0) goto exit;
  22.399 +            // Stop reading if there is no more input.
  22.400 +            if(err == 0 || state->plain_n == 0) break;
  22.401 +        }
  22.402 +        chunk = remaining;
  22.403 +        if(chunk > state->plain_n) chunk = state->plain_n;
  22.404 +        memcpy(buf, state->plain_ptr, chunk);
  22.405 +        k += chunk;
  22.406 +        buf += chunk;
  22.407 +        state->plain_ptr += chunk;
  22.408 +        state->plain_n -= chunk;
  22.409 +        remaining -= chunk;
  22.410 +    }
  22.411 +    err = k;
  22.412 +  exit:
  22.413 +    set_error(state, err);
  22.414 +#endif
  22.415 +    return err;
  22.416 +}
  22.417 +
  22.418 +/** Print to the underlying stream.
  22.419 + * Returns 0 if the formatted output is too big for the internal buffer.
  22.420 + *
  22.421 + * @param s lzo stream
  22.422 + * @param msg format to use
  22.423 + * @param args arguments
  22.424 + * @return result of the print
  22.425 + */
  22.426 +static int lzo_print(IOStream *s, const char *msg, va_list args){
  22.427 +    char buf[1024];
  22.428 +    int buf_n = sizeof(buf);
  22.429 +    int n;
  22.430 +    LZOState *state = lzo_state(s);
  22.431 +    if(!LZOState_writeable(state)){
  22.432 +        n = -EINVAL;
  22.433 +        goto exit;
  22.434 +    }
  22.435 +    n = vsnprintf(buf, buf_n, (char*)msg, args);
  22.436 +    if(n < 0) goto exit;
  22.437 +    if(n > buf_n){
  22.438 +        n = 0;
  22.439 +    } else {
  22.440 +        n = lzo_write(s, buf, 1, n);
  22.441 +    }
  22.442 +  exit:
  22.443 +    return n;
  22.444 +}
  22.445 +
  22.446 +/** Read a character from the underlying stream
  22.447 + *
  22.448 + * @param s lzo stream
  22.449 + * @return character read, IOSTREAM_EOF on end of file (or error)
  22.450 + */
  22.451 +static int lzo_getc(IOStream *s){
  22.452 +    int err;
  22.453 +    char c;
  22.454 +    err = lzo_read(s, &c, 1, 1);
  22.455 +    if(err < 1) c = EOF;
  22.456 +    err = (c==EOF ? IOSTREAM_EOF : c);
  22.457 +    return err;
  22.458 +}
  22.459 +
  22.460 +/** Flush any pending input to the underlying stream.
  22.461 + *
  22.462 + * @param s lzo stream
  22.463 + * @return 0 on success, error code otherwise
  22.464 + */
  22.465 +static int lzo_flush(IOStream *s){
  22.466 +    int err = 0;
  22.467 +    LZOState *state = lzo_state(s);
  22.468 +    //dprintf(">\n");
  22.469 +#ifdef NOCOMPRESS
  22.470 +    err = IOStream_flush(state->io);
  22.471 +#else    
  22.472 +    if(!LZOState_writeable(state)){
  22.473 +        err = -EINVAL;
  22.474 +        goto exit;
  22.475 +    }
  22.476 +    if(state->plain_n){
  22.477 +        err = lzo_compress(state);
  22.478 +        if(err < 0) goto exit;
  22.479 +    }
  22.480 +    err = IOStream_flush(state->io);
  22.481 +  exit:
  22.482 +    set_error(state, err);
  22.483 +#endif
  22.484 +    //dprintf("< err=%d\n", err);
  22.485 +    return (err < 0 ? err : 0);
  22.486 +}
  22.487 +
  22.488 +/** Check if a stream has an error.
  22.489 + *
  22.490 + * @param s lzo stream
  22.491 + * @return code if has an error, 0 otherwise
  22.492 + */
  22.493 +static int lzo_error(IOStream *s){
  22.494 +    int err = 0;
  22.495 +    LZOState *state = lzo_state(s);
  22.496 +    err = state->error;
  22.497 +    if(err) goto exit;
  22.498 +    err = IOStream_error(state->io);
  22.499 +  exit:
  22.500 +    return err;
  22.501 +}
  22.502 +
  22.503 +int lzo_stream_finish(IOStream *s){
  22.504 +    int err = 0;
  22.505 +    LZOState *state = lzo_state(s);
  22.506 +    if(!LZOState_writeable(state)){
  22.507 +        err = -EINVAL;
  22.508 +        goto exit;
  22.509 +    }
  22.510 +    err = lzo_flush(s);
  22.511 +    if(err < 0) goto exit;
  22.512 +    err = marshal_int32(state->io, 0);
  22.513 +  exit:
  22.514 +    return err;
  22.515 +}        
  22.516 +
  22.517 +/** Close an lzo stream.
  22.518 + *
  22.519 + * @param s lzo stream to close
  22.520 + * @return result of the close
  22.521 + */
  22.522 +static int lzo_close(IOStream *s){
  22.523 +    int err = 0;
  22.524 +    LZOState *state = lzo_state(s);
  22.525 +#ifdef NOCOMPRESS
  22.526 +    err = IOStream_close(state->io);
  22.527 +#else    
  22.528 +    if(LZOState_writeable(state)){
  22.529 +        err = lzo_stream_finish(s);
  22.530 +    }        
  22.531 +    err = IOStream_close(state->io);
  22.532 +    set_error(state, err);
  22.533 +#endif
  22.534 +    return err;
  22.535 +}
  22.536 +
  22.537 +/** Free an lzo stream.
  22.538 + *
  22.539 + * @param s lzo stream
  22.540 + */
  22.541 +static void lzo_free(IOStream *s){
  22.542 +    LZOState *state = lzo_state(s);
  22.543 +    IOStream_free(state->io);
  22.544 +    LZOState_free(state);
  22.545 +    s->data = NULL;
  22.546 +}
  22.547 +
  22.548 +/** Create an lzo stream for an IOStream.
  22.549 + *
  22.550 + * @param io stream to wrap
  22.551 + * @return new IOStream using f for i/o
  22.552 + */
  22.553 +IOStream *lzo_stream_new(IOStream *io, const char *mode){
  22.554 +    int err = -ENOMEM;
  22.555 +    int flags = 0;
  22.556 +    IOStream *zio = NULL;
  22.557 +    LZOState *state = NULL;
  22.558 +
  22.559 +    zio = ALLOCATE(IOStream);
  22.560 +    if(!zio) goto exit;
  22.561 +    err = mode_flags(mode, &flags);
  22.562 +    if(err) goto exit;
  22.563 +    state = LZOState_new(io, flags);
  22.564 +    if(!state) goto exit;
  22.565 +    err = 0;
  22.566 +    zio->data = state;
  22.567 +    zio->methods = &lzo_methods;
  22.568 +  exit:
  22.569 +    if(err){
  22.570 +        if(state) LZOState_free(state);
  22.571 +        if(zio) deallocate(zio);
  22.572 +        zio = NULL;
  22.573 +    }
  22.574 +    return zio;
  22.575 +}
  22.576 +
  22.577 +/** IOStream version of fdopen().
  22.578 + *
  22.579 + * @param fd file descriptor
  22.580 + * @param flags giving the mode to open in (as for fdopen())
  22.581 + * @return new stream for the open file, or NULL if failed
  22.582 + */
  22.583 +IOStream *lzo_stream_fdopen(int fd, const char *mode){
  22.584 +    int err = -ENOMEM;
  22.585 +    IOStream *io = NULL, *zio = NULL;
  22.586 +    io = file_stream_fdopen(fd, mode);
  22.587 +    if(!io) goto exit;
  22.588 +    zio = lzo_stream_new(io, mode);
  22.589 +    if(!io) goto exit;
  22.590 +    err = 0;
  22.591 +  exit:
  22.592 +    if(err){
  22.593 +        IOStream_free(io);
  22.594 +        IOStream_free(zio);
  22.595 +        zio = NULL;
  22.596 +    }
  22.597 +    return zio;
  22.598 +}
  22.599 +#endif
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/tools/lib/lzo_stream.h	Mon Jun 28 15:03:15 2004 +0000
    23.3 @@ -0,0 +1,36 @@
    23.4 +#/* $Id: lzo_stream.h,v 1.3 2003/09/30 15:22:53 mjw Exp $ */
    23.5 +/*
    23.6 + * Copyright (C) 2003 Hewlett-Packard Company.
    23.7 + *
    23.8 + * This library is free software; you can redistribute it and/or modify
    23.9 + * it under the terms of the GNU Lesser General Public License as published by
   23.10 + * the Free Software Foundation; either version 2.1 of the License, or
   23.11 + * (at your option) any later version.
   23.12 + *
   23.13 + * This library is distributed in the hope that it will be useful,
   23.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   23.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   23.16 + * GNU Lesser General Public License for more details.
   23.17 + *
   23.18 + * You should have received a copy of the GNU Lesser General Public License
   23.19 + * along with this library; if not, write to the Free Software
   23.20 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   23.21 + */
   23.22 +
   23.23 +#ifndef _SP_LZO_STREAM_H_
   23.24 +#define _SP_LZO_STREAM_H_
   23.25 +
   23.26 +#ifndef __KERNEL__
   23.27 +#include "iostream.h"
   23.28 +
   23.29 +extern IOStream *lzo_stream_new(IOStream *io, const char *mode);
   23.30 +extern IOStream *lzo_stream_fopen(const char *file, const char *mode);
   23.31 +extern IOStream *lzo_stream_fdopen(int fd, const char *mode);
   23.32 +extern IOStream *lzo_stream_io(IOStream *zio);
   23.33 +
   23.34 +extern int lzo_stream_plain_bytes(IOStream *io);
   23.35 +extern int lzo_stream_comp_bytes(IOStream *io);
   23.36 +extern float lzo_stream_ratio(IOStream *io);
   23.37 +
   23.38 +#endif
   23.39 +#endif /* !_SP_FILE_STREAM_H_ */
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/tools/lib/marshal.c	Mon Jun 28 15:03:15 2004 +0000
    24.3 @@ -0,0 +1,207 @@
    24.4 +#include <errno.h>
    24.5 +#include "sys_net.h"
    24.6 +#include "allocate.h"
    24.7 +#include "marshal.h"
    24.8 +
    24.9 +#define dprintf(fmt, args...) IOStream_print(iostdout, "[DEBUG] %s" fmt, __FUNCTION__, ##args)
   24.10 +#define wprintf(fmt, args...) IOStream_print(iostderr, "[WARN]  %s" fmt, __FUNCTION__, ##args)
   24.11 +#define iprintf(fmt, args...) IOStream_print(iostdout, "[INFO]  %s" fmt, __FUNCTION__, ##args)
   24.12 +#define eprintf(fmt, args...) IOStream_print(iostderr, "[ERROR] %s" fmt, __FUNCTION__, ##args)
   24.13 +
   24.14 +
   24.15 +#define ARRAY_SIZE(ary) (sizeof(ary)/sizeof((ary)[0]))
   24.16 +
   24.17 +/* Messages are coded as msgid followed by message fields.
   24.18 + * Initial message on any channel is hello - so can check version
   24.19 + * compatibility.
   24.20 + *
   24.21 + * char* -> uint16_t:n <n bytes>
   24.22 + * ints/uints go as suitable number of bytes (e.g. uint16_t is 2 bytes).
   24.23 + * optional fields go as '1' <val> or '0' (the 0/1 is 1 byte).
   24.24 + * lists go as ('1' <elt>)* '0'
   24.25 + */
   24.26 +
   24.27 +int marshal_flush(IOStream *io){
   24.28 +    int err  = 0;
   24.29 +    err = IOStream_flush(io);
   24.30 +    return err;
   24.31 +}
   24.32 +
   24.33 +int marshal_bytes(IOStream *io, void *s, uint32_t s_n){
   24.34 +    int err = 0;
   24.35 +    int n;
   24.36 +    n = IOStream_write(io, s, s_n);
   24.37 +    if(n < 0){
   24.38 +        err = n;
   24.39 +    } else if (n < s_n){
   24.40 +        wprintf("> Wanted %d, got %d\n", s_n, n);
   24.41 +        err = -EIO;
   24.42 +    }
   24.43 +    return err;
   24.44 +}
   24.45 +
   24.46 +int unmarshal_bytes(IOStream *io, void *s, uint32_t s_n){
   24.47 +    int err = 0;
   24.48 +    int n;
   24.49 +    //dprintf("> s_n=%d\n", s_n);
   24.50 +    n = IOStream_read(io, s, s_n);
   24.51 +    //dprintf("> n=%d\n", n);
   24.52 +    if(n < 0){
   24.53 +        err = n;
   24.54 +    } else if(n < s_n){
   24.55 +        wprintf("> Wanted %d, got %d\n", s_n, n);
   24.56 +        err = -EIO;
   24.57 +    }
   24.58 +    //dprintf("< err=%d\n", err);
   24.59 +    return err;
   24.60 +}
   24.61 +
   24.62 +int marshal_uint8(IOStream *io, uint8_t x){
   24.63 +    return marshal_bytes(io, &x, sizeof(x));
   24.64 +}
   24.65 +
   24.66 +int unmarshal_uint8(IOStream *io, uint8_t *x){
   24.67 +    return unmarshal_bytes(io, x, sizeof(*x));
   24.68 +}
   24.69 +
   24.70 +int marshal_uint16(IOStream *io, uint16_t x){
   24.71 +    x = htons(x);
   24.72 +    return marshal_bytes(io, &x, sizeof(x));
   24.73 +}
   24.74 +
   24.75 +int unmarshal_uint16(IOStream *io, uint16_t *x){
   24.76 +    int err = 0;
   24.77 +    err = unmarshal_bytes(io, x, sizeof(*x));
   24.78 +    *x = ntohs(*x);
   24.79 +    return err;
   24.80 +}
   24.81 +
   24.82 +int marshal_int32(IOStream *io, int32_t x){
   24.83 +    int err = 0;
   24.84 +    //dprintf("> x=%d\n", x);
   24.85 +    x = htonl(x);
   24.86 +    err = marshal_bytes(io, &x, sizeof(x));
   24.87 +    //dprintf("< err=%d\n", err);
   24.88 +    return err;
   24.89 +}
   24.90 +
   24.91 +int unmarshal_int32(IOStream *io, int32_t *x){
   24.92 +    int err = 0;
   24.93 +    //dprintf(">\n");
   24.94 +    err = unmarshal_bytes(io, x, sizeof(*x));
   24.95 +    *x = ntohl(*x);
   24.96 +    //dprintf("< err=%d x=%d\n", err, *x);
   24.97 +    return err;
   24.98 +}
   24.99 +
  24.100 +int marshal_uint32(IOStream *io, uint32_t x){
  24.101 +    int err = 0;
  24.102 +    //dprintf("> x=%u\n", x);
  24.103 +    x = htonl(x);
  24.104 +    err = marshal_bytes(io, &x, sizeof(x));
  24.105 +    //dprintf("< err=%d\n", err);
  24.106 +    return err;
  24.107 +}
  24.108 +
  24.109 +int unmarshal_uint32(IOStream *io, uint32_t *x){
  24.110 +    int err = 0;
  24.111 +    //dprintf(">\n");
  24.112 +    err = unmarshal_bytes(io, x, sizeof(*x));
  24.113 +    *x = ntohl(*x);
  24.114 +    //dprintf("< err=%d x=%u\n", err, *x);
  24.115 +    return err;
  24.116 +}
  24.117 +
  24.118 +int marshal_uint64(IOStream *io, uint64_t x){
  24.119 +    int err;
  24.120 +    err = marshal_uint32(io, (uint32_t) ((x >> 32) & 0xffffffff));
  24.121 +    if(err) goto exit;
  24.122 +    err = marshal_uint32(io, (uint32_t) ( x        & 0xffffffff));
  24.123 +  exit:
  24.124 +    return err;
  24.125 +}
  24.126 +
  24.127 +int unmarshal_uint64(IOStream *io, uint64_t *x){
  24.128 +    int err = 0;
  24.129 +    uint32_t hi, lo;
  24.130 +    err = unmarshal_uint32(io, &hi);
  24.131 +    if(err) goto exit;
  24.132 +    err = unmarshal_uint32(io, &lo);
  24.133 +    *x = (((uint64_t) hi) << 32) | lo;
  24.134 +  exit:
  24.135 +    return err;
  24.136 +}
  24.137 +
  24.138 +int marshal_net16(IOStream *io, net16_t x){
  24.139 +    return marshal_bytes(io, &x, sizeof(x));
  24.140 +}
  24.141 +
  24.142 +int unmarshal_net16(IOStream *io, net16_t *x){
  24.143 +    int err = 0;
  24.144 +    err = unmarshal_bytes(io, x, sizeof(*x));
  24.145 +    return err;
  24.146 +}
  24.147 +
  24.148 +int marshal_net32(IOStream *io, net32_t x){
  24.149 +    return marshal_bytes(io, &x, sizeof(x));
  24.150 +}
  24.151 +
  24.152 +int unmarshal_net32(IOStream *io, net32_t *x){
  24.153 +    int err = 0;
  24.154 +    err = unmarshal_bytes(io, x, sizeof(*x));
  24.155 +    return err;
  24.156 +}
  24.157 +
  24.158 +int marshal_string(IOStream *io, char *s, uint32_t s_n){
  24.159 +    int err;
  24.160 +    //dprintf("> s=%s\n", s);
  24.161 +    err = marshal_uint32(io, s_n);
  24.162 +    if(err) goto exit;
  24.163 +    err = marshal_bytes(io, s, s_n);
  24.164 +  exit:
  24.165 +    //dprintf("< err=%d\n", err);
  24.166 +    return err;
  24.167 +}
  24.168 +
  24.169 +int unmarshal_string(IOStream *io, char *s, uint32_t s_n){
  24.170 +    int err = 0, val_n = 0;
  24.171 +    //dprintf(">\n");
  24.172 +    err = unmarshal_uint32(io, &val_n);
  24.173 +    if(err) goto exit;
  24.174 +    if(val_n >= s_n){
  24.175 +        err = -EINVAL;
  24.176 +        goto exit;
  24.177 +    }
  24.178 +    err = unmarshal_bytes(io, s, val_n);
  24.179 +    if(err) goto exit;
  24.180 +    s[val_n] = '\0';
  24.181 +  exit:
  24.182 +    //dprintf("< err=%d s=%s\n", err, s);
  24.183 +    return err;
  24.184 +}
  24.185 +
  24.186 +int unmarshal_new_string(IOStream *io, char **s, uint32_t *s_n){
  24.187 +    int err = 0, val_n = 0;
  24.188 +    char *val = NULL;
  24.189 +    //dprintf(">\n");
  24.190 +    err = unmarshal_uint32(io, &val_n);
  24.191 +    if(err) goto exit;
  24.192 +    val = allocate(val_n + 1);
  24.193 +    if(!val){
  24.194 +        err = -ENOMEM;
  24.195 +        goto exit;
  24.196 +    }
  24.197 +    err = unmarshal_bytes(io, val, val_n);
  24.198 +    if(err) goto exit;
  24.199 +    val[val_n] = '\0';
  24.200 +  exit:
  24.201 +    if(err){
  24.202 +        if(val) deallocate(val);
  24.203 +        val = NULL;
  24.204 +        val_n = 0;
  24.205 +    }
  24.206 +    *s = val;
  24.207 +    if(s_n) *s_n = val_n;
  24.208 +    //dprintf("< err=%d s=%s\n", err, *s);
  24.209 +    return err;
  24.210 +}
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/tools/lib/marshal.h	Mon Jun 28 15:03:15 2004 +0000
    25.3 @@ -0,0 +1,43 @@
    25.4 +/* $Id: marshal.h,v 1.1 2003/10/17 15:48:43 mjw Exp $ */
    25.5 +#ifndef _SP_MARSHAL_H_
    25.6 +#define _SP_MARSHAL_H_
    25.7 +
    25.8 +#include "iostream.h"
    25.9 +
   25.10 +/** A 16-bit uint in network order, e.g. a port number. */
   25.11 +typedef uint16_t net16_t;
   25.12 +
   25.13 +/** A 32-bit uint in network order, e.g. an IP address. */
   25.14 +typedef uint32_t net32_t;
   25.15 +
   25.16 +extern int marshal_flush(IOStream *io);
   25.17 +
   25.18 +extern int marshal_bytes(IOStream *io, void *s, uint32_t s_n);
   25.19 +extern int unmarshal_bytes(IOStream *io, void *s, uint32_t s_n);
   25.20 +
   25.21 +extern int marshal_uint8(IOStream *io, uint8_t x);
   25.22 +extern int unmarshal_uint8(IOStream *io, uint8_t *x);
   25.23 +
   25.24 +extern int marshal_uint16(IOStream *io, uint16_t x);
   25.25 +extern int unmarshal_uint16(IOStream *io, uint16_t *x);
   25.26 +
   25.27 +extern int marshal_uint32(IOStream *io, uint32_t x);
   25.28 +extern int unmarshal_uint32(IOStream *io, uint32_t *x);
   25.29 +
   25.30 +extern int marshal_int32(IOStream *io, int32_t x);
   25.31 +extern int unmarshal_int32(IOStream *io, int32_t *x);
   25.32 +
   25.33 +extern int marshal_uint64(IOStream *io, uint64_t x);
   25.34 +extern int unmarshal_uint64(IOStream *io, uint64_t *x);
   25.35 +
   25.36 +extern int marshal_net16(IOStream *io, net16_t x);
   25.37 +extern int unmarshal_net16(IOStream *io, net16_t *x);
   25.38 +
   25.39 +extern int marshal_net32(IOStream *io, net32_t x);
   25.40 +extern int unmarshal_net32(IOStream *io, net32_t *x);
   25.41 +
   25.42 +extern int marshal_string(IOStream *io, char *s, uint32_t s_n);
   25.43 +extern int unmarshal_string(IOStream *io, char *s, uint32_t s_n);
   25.44 +extern int unmarshal_new_string(IOStream *io, char **s, uint32_t *s_n);
   25.45 +
   25.46 +#endif /* ! _SP_MARSHAL_H_ */
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/tools/lib/socket_stream.c	Mon Jun 28 15:03:15 2004 +0000
    26.3 @@ -0,0 +1,259 @@
    26.4 +/* $Id: socket_stream.c,v 1.9 2004/03/05 14:45:34 mjw Exp $ */
    26.5 +/*
    26.6 + * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    26.7 + *
    26.8 + * This library is free software; you can redistribute it and/or modify
    26.9 + * it under the terms of the GNU Lesser General Public License as published by
   26.10 + * the Free Software Foundation; either version 2.1 of the License, or
   26.11 + * (at your option) any later version.
   26.12 + *
   26.13 + * This library is distributed in the hope that it will be useful,
   26.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   26.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   26.16 + * GNU Lesser General Public License for more details.
   26.17 + *
   26.18 + * You should have received a copy of the GNU Lesser General Public License
   26.19 + * along with this library; if not, write to the Free Software
   26.20 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   26.21 + */
   26.22 +
   26.23 +/** @file
   26.24 + * An IOStream implementation using sockets.
   26.25 + */
   26.26 +
   26.27 +#include <stdio.h>
   26.28 +#include <stdlib.h>
   26.29 +#include <string.h>
   26.30 +#include <unistd.h>
   26.31 +#include <errno.h>
   26.32 +#include "allocate.h"
   26.33 +#include "socket_stream.h"
   26.34 +
   26.35 +#define MODULE_NAME "sock"
   26.36 +#define DEBUG 0
   26.37 +//#undef DEBUG
   26.38 +#include "debug.h"
   26.39 +
   26.40 +static int socket_read(IOStream *s, void *buf, size_t n);
   26.41 +static int socket_write(IOStream *s, const void *buf, size_t n);
   26.42 +static int socket_error(IOStream *s);
   26.43 +static int socket_close(IOStream *s);
   26.44 +static void socket_free(IOStream *s);
   26.45 +static int socket_flush(IOStream *s);
   26.46 +
   26.47 +/** Methods used by a socket IOStream. */
   26.48 +static const IOMethods socket_methods = {
   26.49 +    read:  socket_read,
   26.50 +    write: socket_write,
   26.51 +    error: socket_error,
   26.52 +    close: socket_close,
   26.53 +    free:  socket_free,
   26.54 +    flush: socket_flush,
   26.55 +};
   26.56 +
   26.57 +/** Get the socket data.
   26.58 + * 
   26.59 + * @param io socket stream
   26.60 + * @return data
   26.61 + */
   26.62 +static inline SocketData * socket_data(IOStream *io){
   26.63 +    return (SocketData *)io->data;
   26.64 +}
   26.65 +
   26.66 +/** Test if a stream is a socket stream.
   26.67 + *
   26.68 + * @param io stream
   26.69 + * @return 0 if a socket stream, -EINVAL if not
   26.70 + */
   26.71 +int socket_stream_check(IOStream *io){
   26.72 +    return (io && io->methods == &socket_methods ? 0 : -EINVAL);
   26.73 +}
   26.74 +
   26.75 +/** Get the data for a socket stream.
   26.76 + *
   26.77 + * @param io stream
   26.78 + * @param data return value for the data
   26.79 + * @return 0 if a socket stream, -EINVAL if not
   26.80 + */
   26.81 +int socket_stream_data(IOStream *io, SocketData **data){
   26.82 +    int err = socket_stream_check(io);
   26.83 +    if(err){
   26.84 +        *data = NULL;
   26.85 +    } else {
   26.86 +        *data = socket_data(io);
   26.87 +    }
   26.88 +    return err;
   26.89 +}
   26.90 +
   26.91 +/** Set the destination address for a socket stream.
   26.92 + *
   26.93 + * @param io stream
   26.94 + * @param addr address
   26.95 + * @return 0 if a socket stream, -EINVAL if not
   26.96 + */
   26.97 +int socket_stream_set_addr(IOStream *io, struct sockaddr_in *addr){
   26.98 +    int err = 0;
   26.99 +    SocketData *data = NULL;
  26.100 +    err = socket_stream_data(io, &data);
  26.101 +    if(!err){
  26.102 +        data->daddr = *addr;
  26.103 +    }
  26.104 +    return err;
  26.105 +}
  26.106 +
  26.107 +/** Set the send flags for a socket stream.
  26.108 + *
  26.109 + * @param io stream
  26.110 + * @param flags flags
  26.111 + * @return 0 if a socket stream, -EINVAL if not
  26.112 + */
  26.113 +int socket_stream_set_flags(IOStream *io, int flags){
  26.114 +    int err = 0;
  26.115 +    SocketData *data = NULL;
  26.116 +    err = socket_stream_data(io, &data);
  26.117 +    if(!err){
  26.118 +        data->flags = flags;
  26.119 +    }
  26.120 +    return err;
  26.121 +}
  26.122 +
  26.123 +/** Write to the underlying socket using sendto.
  26.124 + *
  26.125 + * @param stream input
  26.126 + * @param buf where to put input
  26.127 + * @param n number of bytes to write
  26.128 + * @return number of bytes written
  26.129 + */
  26.130 +static int socket_write(IOStream *s, const void *buf, size_t n){
  26.131 +    SocketData *data = socket_data(s);
  26.132 +    struct sockaddr *daddr = (struct sockaddr *)&data->daddr;
  26.133 +    socklen_t daddr_n = sizeof(data->daddr);
  26.134 +    int k;
  26.135 +    dprintf("> sock=%d addr=%s:%d n=%d\n",
  26.136 +            data->fd, inet_ntoa(data->daddr.sin_addr), ntohs(data->daddr.sin_port), n);
  26.137 +    if(0){
  26.138 +        struct sockaddr_in self = {};
  26.139 +        socklen_t self_n;
  26.140 +        getsockname(data->fd, (struct sockaddr *)&self, &self_n);
  26.141 +        dprintf("> sockname sock=%d %s:%d\n",
  26.142 +                data->fd, inet_ntoa(self.sin_addr), ntohs(self.sin_port));
  26.143 +    }
  26.144 +    k = sendto(data->fd, buf, n, data->flags, daddr, daddr_n);
  26.145 +    dprintf("> sendto=%d\n", k);
  26.146 +    return k;
  26.147 +}
  26.148 +
  26.149 +/** Read from the underlying stream using recv();
  26.150 + *
  26.151 + * @param stream input
  26.152 + * @param buf where to put input
  26.153 + * @param n number of bytes to read
  26.154 + * @return number of bytes read
  26.155 + */
  26.156 +static int socket_read(IOStream *s, void *buf, size_t n){
  26.157 +    SocketData *data = socket_data(s);
  26.158 +    int k;
  26.159 +    struct sockaddr *saddr = (struct sockaddr *)&data->saddr;
  26.160 +    socklen_t saddr_n = sizeof(data->saddr);
  26.161 +    k = recvfrom(data->fd, buf, n, data->flags, saddr, &saddr_n);
  26.162 +    return k;
  26.163 +}
  26.164 +
  26.165 +/** Print to the underlying socket.
  26.166 + *
  26.167 + * @param s socket stream
  26.168 + * @param msg format to use
  26.169 + * @param args arguments
  26.170 + * @return result of the print
  26.171 + */
  26.172 +static int socket_print(IOStream *s, const char *msg, va_list args){
  26.173 +    SocketData *data = socket_data(s);
  26.174 +    int n;
  26.175 +    n = vsnprintf(data->buf, data->buf_n - 1, msg, args);
  26.176 +    if(0 < n && n < data->buf_n){
  26.177 +        socket_write(s, data->buf, n);
  26.178 +    }
  26.179 +    return n;
  26.180 +}
  26.181 +
  26.182 +/** Read a character from the underlying socket
  26.183 + *
  26.184 + * @param s socket stream
  26.185 + * @return character read, IOSTREAM_EOF on end of socket (or error)
  26.186 + */
  26.187 +static int socket_getc(IOStream *s){
  26.188 +    char b;
  26.189 +    int n, c;
  26.190 +    n = socket_read(s, &b, 1);
  26.191 +    c = (n <= 0 ? IOSTREAM_EOF : b);
  26.192 +    return c;
  26.193 +}
  26.194 +
  26.195 +/** Flush the socket (no-op).
  26.196 + *
  26.197 + * @param s socket stream
  26.198 + * @return 0 on success, error code otherwise
  26.199 + */
  26.200 +static int socket_flush(IOStream *s){
  26.201 +    return 0;
  26.202 +}
  26.203 +
  26.204 +/** Check if a socket stream has an error (no-op).
  26.205 + *
  26.206 + * @param s socket stream
  26.207 + * @return 1 if has an error, 0 otherwise
  26.208 + */
  26.209 +static int socket_error(IOStream *s){
  26.210 +    // Read SOL_SOCKET/SO_ERROR ?
  26.211 +    return 0;
  26.212 +}
  26.213 +
  26.214 +/** Close a socket stream.
  26.215 + *
  26.216 + * @param s socket stream to close
  26.217 + * @return result of the close
  26.218 + */
  26.219 +static int socket_close(IOStream *s){
  26.220 +    SocketData *data = socket_data(s);
  26.221 +    return close(data->fd);
  26.222 +}
  26.223 +
  26.224 +/** Free a socket stream.
  26.225 + *
  26.226 + * @param s socket stream
  26.227 + */
  26.228 +static void socket_free(IOStream *s){
  26.229 +    SocketData *data = socket_data(s);
  26.230 +    deallocate(data);
  26.231 +}
  26.232 +
  26.233 +/** Create an IOStream for a socket.
  26.234 + *
  26.235 + * @param fd socket to wtap
  26.236 + * @return new IOStream using fd for i/o
  26.237 + */
  26.238 +IOStream *socket_stream_new(int fd){
  26.239 +    int err = -ENOMEM;
  26.240 +    IOStream *io = NULL;
  26.241 +    SocketData *data = NULL;
  26.242 +
  26.243 +    io = ALLOCATE(IOStream);
  26.244 +    if(!io) goto exit;
  26.245 +    io->methods = &socket_methods;
  26.246 +    data = ALLOCATE(SocketData);
  26.247 +    if(!data) goto exit;
  26.248 +    io->data = data;
  26.249 +    data->fd = fd;
  26.250 +    data->buf_n = sizeof(data->buf);
  26.251 +    err = 0;
  26.252 +  exit:
  26.253 +    if(err){
  26.254 +        if(io){
  26.255 +            if(data) deallocate(data);
  26.256 +            deallocate(io);
  26.257 +            io = NULL;
  26.258 +        }
  26.259 +    }
  26.260 +    return io;
  26.261 +}
  26.262 +
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/tools/lib/socket_stream.h	Mon Jun 28 15:03:15 2004 +0000
    27.3 @@ -0,0 +1,54 @@
    27.4 +/* $Id: socket_stream.h,v 1.2 2004/03/04 17:38:13 mjw Exp $ */
    27.5 +/*
    27.6 + * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    27.7 + *
    27.8 + * This library is free software; you can redistribute it and/or modify
    27.9 + * it under the terms of the GNU Lesser General Public License as published by
   27.10 + * the Free Software Foundation; either version 2.1 of the License, or
   27.11 + * (at your option) any later version.
   27.12 + *
   27.13 + * This library is distributed in the hope that it will be useful,
   27.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   27.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   27.16 + * GNU Lesser General Public License for more details.
   27.17 + *
   27.18 + * You should have received a copy of the GNU Lesser General Public License
   27.19 + * along with this library; if not, write to the Free Software
   27.20 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   27.21 + */
   27.22 +
   27.23 +#ifndef _XEN_LIB_SOCKET_STREAM_H_
   27.24 +#define _XEN_LIB_SOCKET_STREAM_H_
   27.25 +
   27.26 +#ifndef __KERNEL__
   27.27 +#include "iostream.h"
   27.28 +#include <stdio.h>
   27.29 +
   27.30 +#include <sys/socket.h>
   27.31 +#include <netinet/in.h>
   27.32 +#include <arpa/inet.h>
   27.33 +
   27.34 +/** Data associated with a socket stream. */
   27.35 +typedef struct SocketData {
   27.36 +    /** The socket file descriptor. */
   27.37 +    int fd;
   27.38 +    /** Source address from last read (recvfrom). */
   27.39 +    struct sockaddr_in saddr;
   27.40 +    /** Destination address for writes (sendto). */
   27.41 +    struct sockaddr_in daddr;
   27.42 +    /** Write flags (sendto). */
   27.43 +    int flags;
   27.44 +    /** Buffer size. */
   27.45 +    int buf_n;
   27.46 +    /** Buffer for formatted printing. */
   27.47 +    char buf[1024];
   27.48 +} SocketData;
   27.49 +
   27.50 +extern IOStream *socket_stream_new(int fd);
   27.51 +extern int socket_stream_data(IOStream *io, SocketData **data);
   27.52 +extern int socket_stream_check(IOStream *io);
   27.53 +extern int socket_stream_set_addr(IOStream *io, struct sockaddr_in *addr);
   27.54 +extern int socket_stream_set_flags(IOStream *io, int flags);
   27.55 +
   27.56 +#endif
   27.57 +#endif /* !_XEN_LIB_SOCKET_STREAM_H_ */
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/tools/lib/string_stream.c	Mon Jun 28 15:03:15 2004 +0000
    28.3 @@ -0,0 +1,174 @@
    28.4 +/*
    28.5 + * Copyright (C) 2001, 2002 Hewlett-Packard Company.
    28.6 + *
    28.7 + * This library is free software; you can redistribute it and/or modify
    28.8 + * it under the terms of the GNU Lesser General Public License as published by
    28.9 + * the Free Software Foundation; either version 2.1 of the License, or
   28.10 + * (at your option) any later version.
   28.11 + *
   28.12 + * This library is distributed in the hope that it will be useful,
   28.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   28.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   28.15 + * GNU Lesser General Public License for more details.
   28.16 + *
   28.17 + * You should have received a copy of the GNU Lesser General Public License
   28.18 + * along with this library; if not, write to the Free Software
   28.19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   28.20 + */
   28.21 +
   28.22 +/** @file
   28.23 + * IOStream subtype for input and output to strings.
   28.24 + * Usable from user or kernel code (with __KERNEL__ defined).
   28.25 + */
   28.26 +
   28.27 +#include "sys_string.h"
   28.28 +#include "string_stream.h"
   28.29 +#include "allocate.h"
   28.30 +
   28.31 +static int string_print(IOStream *io, const char *msg, va_list args);
   28.32 +static int string_getc(IOStream *io);
   28.33 +static int string_error(IOStream *io);
   28.34 +static int string_close(IOStream *io);
   28.35 +static void string_free(IOStream *io);
   28.36 +
   28.37 +/** Methods for a string stream. */
   28.38 +static IOMethods string_methods = {
   28.39 +    //print: string_print,
   28.40 +    //getc:  string_getc,
   28.41 +    error: string_error,
   28.42 +    close: string_close,
   28.43 +    free:  string_free,
   28.44 +};
   28.45 +
   28.46 +/** Get the string stream state.
   28.47 + *
   28.48 + * @param io string stream
   28.49 + * @return state
   28.50 + */
   28.51 +static inline StringData *get_string_data(IOStream *io){
   28.52 +    return (StringData*)io->data;
   28.53 +}
   28.54 +
   28.55 +/** Read a character from a string stream.
   28.56 + *
   28.57 + * @param io string stream
   28.58 + * @return character read, IOSTREAM_EOF if no more input
   28.59 + */
   28.60 +static int string_getc(IOStream *io){
   28.61 +    StringData *data = get_string_data(io);
   28.62 +    int c = IOSTREAM_EOF;
   28.63 +    char *s = data->in;
   28.64 +
   28.65 +    if(s && s < data->end){
   28.66 +        c = (unsigned)*s;
   28.67 +        data->in = s+1;
   28.68 +    }
   28.69 +    return c;
   28.70 +}
   28.71 +
   28.72 +/** Print to a string stream.
   28.73 + * Formats the data to an internal buffer and prints it.
   28.74 + * The formatted data must fit into the internal buffer.
   28.75 + *
   28.76 + * @param io string stream
   28.77 + * @param format print format
   28.78 + * @param args print arguments
   28.79 + * @return result of the print
   28.80 + */
   28.81 +static int string_print(IOStream *io, const char *msg, va_list args){
   28.82 +    StringData *data = get_string_data(io);
   28.83 +    int k = data->end - data->out;
   28.84 +    int n = vsnprintf(data->out, k, (char*)msg, args);
   28.85 +    if(n < 0 || n > k ){
   28.86 +        n = k;
   28.87 +        IOStream_close(io);
   28.88 +    } else {
   28.89 +        data->out += n;
   28.90 +    }
   28.91 +    return n;
   28.92 +}
   28.93 +
   28.94 +/** Test if a string stream has an error.
   28.95 + *
   28.96 + * @param io string stream
   28.97 + * @return 0 if ok, error code otherwise
   28.98 + */
   28.99 +static int string_error(IOStream *io){
  28.100 +    StringData *data = get_string_data(io);
  28.101 +    return data->out == NULL;
  28.102 +}
  28.103 +
  28.104 +/** Close a string stream.
  28.105 + *
  28.106 + * @param io string stream
  28.107 + * @return 0
  28.108 + */
  28.109 +static int string_close(IOStream *io){
  28.110 +    StringData *data = get_string_data(io);
  28.111 +    data->in = NULL;
  28.112 +    data->out = NULL;
  28.113 +    return 0;
  28.114 +}
  28.115 +
  28.116 +/** Free a string stream.
  28.117 + * The stream must have been allocated, not statically created.
  28.118 + * The stream state is freed, but the underlying string is not.
  28.119 + *
  28.120 + * @param io string stream
  28.121 + */
  28.122 +static void string_free(IOStream *io){
  28.123 +    StringData *data = get_string_data(io);
  28.124 +    zero(data, sizeof(*data));
  28.125 +    deallocate(data);
  28.126 +}
  28.127 +
  28.128 +/** Get the methods to use for a string stream.
  28.129 + *
  28.130 + * @return methods
  28.131 + */
  28.132 +IOMethods *string_stream_get_methods(void){
  28.133 +    return &string_methods;
  28.134 +}
  28.135 +
  28.136 +/** Initialise a string stream, usually from static data.
  28.137 + *
  28.138 + * @param io address of IOStream to fill in
  28.139 + * @param data address of StringData to fill in
  28.140 + * @param s string to use
  28.141 + * @param n length of the string
  28.142 + */
  28.143 +void string_stream_init(IOStream *io, StringData *data, char *s, int n){
  28.144 +    if(data && io){
  28.145 +        zero(data, sizeof(*data));
  28.146 +        data->string = (char*)s;
  28.147 +        data->in = data->string;
  28.148 +        data->out = data->string;
  28.149 +        data->size = n;
  28.150 +        data->end = data->string + n;
  28.151 +        zero(io, sizeof(*io));
  28.152 +        io->methods = &string_methods;
  28.153 +        io->data = data;
  28.154 +    }
  28.155 +}
  28.156 +
  28.157 +/** Allocate and initialise a string stream.
  28.158 + *
  28.159 + * @param s string to use
  28.160 + * @param n length of the string
  28.161 + * @return new stream (free using IOStream_free)
  28.162 + */
  28.163 +IOStream *string_stream_new(char *s, int n){
  28.164 +    int ok = 0;
  28.165 +    StringData *data = ALLOCATE(StringData);
  28.166 +    IOStream *io = ALLOCATE(IOStream);
  28.167 +    if(data && io){
  28.168 +        ok = 1;
  28.169 +        string_stream_init(io, data, s, n);
  28.170 +    }
  28.171 +    if(!ok){
  28.172 +        deallocate(data);
  28.173 +        deallocate(io);
  28.174 +        io = NULL;
  28.175 +    }
  28.176 +    return io;
  28.177 +}
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/tools/lib/string_stream.h	Mon Jun 28 15:03:15 2004 +0000
    29.3 @@ -0,0 +1,46 @@
    29.4 +/* $Id: string_stream.h,v 1.1 2003/08/22 14:25:48 mjw Exp $ */
    29.5 +/*
    29.6 + * Copyright (C) 2001, 2002 Hewlett-Packard Company.
    29.7 + *
    29.8 + * This library is free software; you can redistribute it and/or modify
    29.9 + * it under the terms of the GNU Lesser General Public License as published by
   29.10 + * the Free Software Foundation; either version 2.1 of the License, or
   29.11 + * (at your option) any later version.
   29.12 + *
   29.13 + * This library is distributed in the hope that it will be useful,
   29.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   29.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   29.16 + * GNU Lesser General Public License for more details.
   29.17 + *
   29.18 + * You should have received a copy of the GNU Lesser General Public License
   29.19 + * along with this library; if not, write to the Free Software
   29.20 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   29.21 + */
   29.22 +
   29.23 +#ifndef _SP_STRING_STREAM_H_
   29.24 +#define _SP_STRING_STREAM_H_
   29.25 +
   29.26 +#include "iostream.h"
   29.27 +
   29.28 +/** Internal state for a string stream.
   29.29 + * Exposed here so that string streams can be statically created, using
   29.30 + * string_stream_init().
   29.31 + */
   29.32 +typedef struct {
   29.33 +    /** The string used for input and ouput. */
   29.34 +    char *string;
   29.35 +    /** Output pointer. */
   29.36 +    char *out;
   29.37 +    /** Input pointer. */
   29.38 +    char *in;
   29.39 +    /** Length of string. */
   29.40 +    int size;
   29.41 +    /** End marker. */
   29.42 +    char *end;
   29.43 +} StringData;
   29.44 +
   29.45 +extern IOMethods *string_stream_get_methods(void);
   29.46 +extern IOStream *string_stream_new(char *s, int n);
   29.47 +extern void string_stream_init(IOStream *stream, StringData *data, char *s, int n);
   29.48 +
   29.49 +#endif /* !_SP_STRING_STREAM_H_ */
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/tools/lib/sxpr.c	Mon Jun 28 15:03:15 2004 +0000
    30.3 @@ -0,0 +1,935 @@
    30.4 +/*
    30.5 + *
    30.6 + * This library is free software; you can redistribute it and/or modify
    30.7 + * it under the terms of the GNU Lesser General Public License as
    30.8 + * published by the Free Software Foundation; either version 2.1 of the
    30.9 + * License, or  (at your option) any later version. This library is 
   30.10 + * distributed in the  hope that it will be useful, but WITHOUT ANY
   30.11 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or
   30.12 + * FITNESS FOR A PARTICULAR PURPOSE.
   30.13 + * See the GNU Lesser General Public License for more details.
   30.14 + *
   30.15 + * You should have received a copy of the GNU Lesser General Public License
   30.16 + * along with this library; if not, write to the Free Software Foundation,
   30.17 + * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   30.18 + */
   30.19 +
   30.20 +#include <stdarg.h>
   30.21 +#include "sys_string.h"
   30.22 +#include "lexis.h"
   30.23 +#include "sys_net.h"
   30.24 +#include "hash_table.h"
   30.25 +#include "sxpr.h"
   30.26 +
   30.27 +#include <errno.h>
   30.28 +#undef free
   30.29 +
   30.30 +/** @file
   30.31 + * General representation of sxprs.
   30.32 + * Includes print, equal, and free functions for the sxpr types.
   30.33 + *
   30.34 + * Zero memory containing an Sxpr will have the value ONONE - this is intentional.
   30.35 + * When a function returning an sxpr cannot allocate memory we return ONOMEM.
   30.36 + *
   30.37 + */
   30.38 +
   30.39 +static int atom_print(IOStream *io, Sxpr obj, unsigned flags);
   30.40 +static int atom_equal(Sxpr x, Sxpr y);
   30.41 +static void atom_free(Sxpr obj);
   30.42 +
   30.43 +static int string_print(IOStream *io, Sxpr obj, unsigned flags);
   30.44 +static int string_equal(Sxpr x, Sxpr y);
   30.45 +static void string_free(Sxpr obj);
   30.46 +
   30.47 +static int cons_print(IOStream *io, Sxpr obj, unsigned flags);
   30.48 +static int cons_equal(Sxpr x, Sxpr y);
   30.49 +static void cons_free(Sxpr obj);
   30.50 +
   30.51 +static int null_print(IOStream *io, Sxpr obj, unsigned flags);
   30.52 +static int none_print(IOStream *io, Sxpr obj, unsigned flags);
   30.53 +static int int_print(IOStream *io, Sxpr obj, unsigned flags);
   30.54 +static int bool_print(IOStream *io, Sxpr obj, unsigned flags);
   30.55 +
   30.56 +/** Type definitions. */
   30.57 +static SxprType types[1024] = {
   30.58 +    [T_NONE]     { type:    T_NONE,     name: "none",       print: none_print      },
   30.59 +    [T_NULL]     { type:    T_NULL,     name: "null",       print: null_print      },
   30.60 +    [T_UINT]     { type:    T_UINT,     name: "int",        print: int_print,      },
   30.61 +    [T_BOOL]     { type:    T_BOOL,     name: "bool",       print: bool_print,     },
   30.62 +    [T_ATOM]     { type:    T_ATOM,     name: "atom",       print: atom_print,
   30.63 +		   pointer: TRUE,
   30.64 +		   free:    atom_free,
   30.65 +		   equal:   atom_equal,
   30.66 +		 },
   30.67 +    [T_STRING]   { type:    T_STRING,   name: "string",     print: string_print,
   30.68 +		   pointer: TRUE,
   30.69 +		   free:    string_free,
   30.70 +		   equal:   string_equal,
   30.71 +		 },
   30.72 +    [T_CONS]     { type:    T_CONS,     name: "cons",       print: cons_print,
   30.73 +		   pointer: TRUE,
   30.74 +		   free:    cons_free,
   30.75 +		   equal:   cons_equal,
   30.76 +		 },
   30.77 +};
   30.78 +
   30.79 +/** Number of entries in the types array. */
   30.80 +static int type_sup = sizeof(types)/sizeof(types[0]);
   30.81 +
   30.82 +/** Get the type definition for a given type code.
   30.83 + *
   30.84 + * @param ty type code
   30.85 + * @return type definition or null
   30.86 + */
   30.87 +SxprType *get_sxpr_type(int ty){
   30.88 +    if(0 <= ty && ty < type_sup){
   30.89 +        return types+ty;
   30.90 +    }
   30.91 +    return NULL;
   30.92 +}
   30.93 +
   30.94 +/** The default print function.
   30.95 + *
   30.96 + * @param io stream to print to
   30.97 + * @param x sxpr to print
   30.98 + * @param flags print flags
   30.99 + * @return number of bytes written on success
  30.100 + */
  30.101 +int default_print(IOStream *io, Sxpr x, unsigned flags){
  30.102 +    return IOStream_print(io, "#<%u %lu>\n", get_type(x), get_ul(x));
  30.103 +}
  30.104 +
  30.105 +/** The default equal function.
  30.106 + * Uses eq().
  30.107 + *
  30.108 + * @param x sxpr to compare
  30.109 + * @param y sxpr to compare
  30.110 + * @return 1 if equal, 0 otherwise
  30.111 + */
  30.112 +int default_equal(Sxpr x, Sxpr y){
  30.113 +    return eq(x, y);
  30.114 +}
  30.115 +
  30.116 +/** General sxpr print function.
  30.117 + * Prints an sxpr on a stream using the print function for the sxpr type.
  30.118 + * Printing is controlled by flags from the PrintFlags enum.
  30.119 + * If PRINT_TYPE is in the flags the sxpr type is printed before the sxpr
  30.120 + * (for debugging).
  30.121 + *
  30.122 + * @param io stream to print to
  30.123 + * @param x sxpr to print
  30.124 + * @param flags print flags
  30.125 + * @return number of bytes written
  30.126 + */
  30.127 +int objprint(IOStream *io, Sxpr x, unsigned flags){
  30.128 +    SxprType *def = get_sxpr_type(get_type(x));
  30.129 +    ObjPrintFn *print_fn = (def && def->print ? def->print : default_print);
  30.130 +    int k = 0;
  30.131 +    if(!io) return k;
  30.132 +    if(flags & PRINT_TYPE){
  30.133 +	k += IOStream_print(io, "%s:", def->name);
  30.134 +    }
  30.135 +    k += print_fn(io, x, flags);
  30.136 +    return k;
  30.137 +}
  30.138 +
  30.139 +/** General sxpr free function.
  30.140 + * Frees an sxpr using the free function for its type.
  30.141 + * Free functions must recursively free any subsxprs.
  30.142 + * If no function is defined then the default is to
  30.143 + * free sxprs whose type has pointer true.
  30.144 + * Sxprs must not be used after freeing.
  30.145 + *
  30.146 + * @param x sxpr to free
  30.147 + */
  30.148 +void objfree(Sxpr x){
  30.149 +    SxprType *def = get_sxpr_type(get_type(x));
  30.150 +
  30.151 +    if(def){
  30.152 +	if(def->free){
  30.153 +	    def->free(x);
  30.154 +	} else if (def->pointer){
  30.155 +	    hfree(x);
  30.156 +	}
  30.157 +    }
  30.158 +}
  30.159 +
  30.160 +/** General sxpr equality function.
  30.161 + * Compares x and y using the equal function for x.
  30.162 + * Uses default_equal() if x has no equal function.
  30.163 + *
  30.164 + * @param x sxpr to compare
  30.165 + * @param y sxpr to compare
  30.166 + * @return 1 if equal, 0 otherwise
  30.167 + */
  30.168 +int objequal(Sxpr x, Sxpr y){
  30.169 +    SxprType *def = get_sxpr_type(get_type(x));
  30.170 +    ObjEqualFn *equal_fn = (def && def->equal ? def->equal : default_equal);
  30.171 +    return equal_fn(x, y);
  30.172 +}
  30.173 +
  30.174 +/** Search for a key in an alist.
  30.175 + * An alist is a list of conses, where the cars
  30.176 + * of the conses are the keys. Compares keys using equality.
  30.177 + *
  30.178 + * @param k key
  30.179 + * @param l alist to search
  30.180 + * @return first element of l with car k, or ONULL
  30.181 + */
  30.182 +Sxpr assoc(Sxpr k, Sxpr l){
  30.183 +    for( ; CONSP(l) ; l = CDR(l)){
  30.184 +        Sxpr x = CAR(l);
  30.185 +        if(CONSP(x) && objequal(k, CAR(x))){
  30.186 +            return x;   
  30.187 +        }
  30.188 +    }
  30.189 +    return ONULL;
  30.190 +}
  30.191 +
  30.192 +/** Search for a key in an alist.
  30.193 + * An alist is a list of conses, where the cars
  30.194 + * of the conses are the keys. Compares keys using eq.
  30.195 + *
  30.196 + * @param k key
  30.197 + * @param l alist to search
  30.198 + * @return first element of l with car k, or ONULL
  30.199 + */
  30.200 +Sxpr assocq(Sxpr k, Sxpr l){
  30.201 +    for( ; CONSP(l); l = CDR(l)){
  30.202 +        Sxpr x = CAR(l);
  30.203 +        if(CONSP(x) && eq(k, CAR(x))){
  30.204 +            return x;
  30.205 +        }
  30.206 +    }
  30.207 +    return ONULL;
  30.208 +}
  30.209 +
  30.210 +/** Add a new key and value to an alist.
  30.211 + *
  30.212 + * @param k key
  30.213 + * @param l value
  30.214 + * @param l alist
  30.215 + * @return l with the new cell added to the front
  30.216 + */
  30.217 +Sxpr acons(Sxpr k, Sxpr v, Sxpr l){
  30.218 +    Sxpr x, y;
  30.219 +    x = cons_new(k, v);
  30.220 +    if(NOMEMP(x)) return x;
  30.221 +    y = cons_new(x, l);
  30.222 +    if(NOMEMP(y)) cons_free_cells(x);
  30.223 +    return y;
  30.224 +}
  30.225 +
  30.226 +/** Test if a list contains an element.
  30.227 + * Uses sxpr equality.
  30.228 + *
  30.229 + * @param l list
  30.230 + * @param x element to look for
  30.231 + * @return a tail of l with x as car, or ONULL
  30.232 + */
  30.233 +Sxpr cons_member(Sxpr l, Sxpr x){
  30.234 +    for( ; CONSP(l) && !eq(x, CAR(l)); l = CDR(l)){}
  30.235 +    return l;
  30.236 +}
  30.237 +
  30.238 +/** Test if a list contains an element satisfying a test.
  30.239 + * The test function is called with v and an element of the list.
  30.240 + *
  30.241 + * @param l list
  30.242 + * @param test_fn test function to use
  30.243 + * @param v value for first argument to the test
  30.244 + * @return a tail of l with car satisfying the test, or 0
  30.245 + */
  30.246 +Sxpr cons_member_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v){
  30.247 +    for( ; CONSP(l) && !test_fn(v, CAR(l)); l = CDR(l)){ }
  30.248 +    return l;
  30.249 +}
  30.250 +
  30.251 +/** Test if the elements of list 't' are a subset of the elements
  30.252 + * of list 's'. Element order is not significant.
  30.253 + *
  30.254 + * @param s element list to check subset of
  30.255 + * @param t element list to check if is a subset
  30.256 + * @return 1 if is a subset, 0 otherwise
  30.257 + */
  30.258 +int cons_subset(Sxpr s, Sxpr t){
  30.259 +    for( ; CONSP(t); t = CDR(t)){
  30.260 +	if(!CONSP(cons_member(s, CAR(t)))){
  30.261 +	    return 0;
  30.262 +	}
  30.263 +    }
  30.264 +    return 1;
  30.265 +}
  30.266 +
  30.267 +/** Test if two lists have equal sets of elements.
  30.268 + * Element order is not significant.
  30.269 + *
  30.270 + * @param s list to check
  30.271 + * @param t list to check
  30.272 + * @return 1 if equal, 0 otherwise
  30.273 + */
  30.274 +int cons_set_equal(Sxpr s, Sxpr t){
  30.275 +    return cons_subset(s, t) && cons_subset(t, s);
  30.276 +}
  30.277 +
  30.278 +#ifdef USE_GC
  30.279 +/*============================================================================*/
  30.280 +/* The functions inside this ifdef are only safe if GC is used.
  30.281 + * Otherwise they may leak memory.
  30.282 + */
  30.283 +
  30.284 +/** Remove an element from a list (GC only).
  30.285 + * Uses sxpr equality and removes all instances, even
  30.286 + * if there are more than one.
  30.287 + *
  30.288 + * @param l list to remove elements from
  30.289 + * @param x element to remove
  30.290 + * @return modified input list
  30.291 + */
  30.292 +Sxpr cons_remove(Sxpr l, Sxpr x){
  30.293 +    return cons_remove_if(l, eq, x);
  30.294 +}
  30.295 +
  30.296 +/** Remove elements satisfying a test (GC only).
  30.297 + * The test function is called with v and an element of the set.
  30.298 + *
  30.299 + * @param l list to remove elements from
  30.300 + * @param test_fn function to use to decide if an element should be removed
  30.301 + * @return modified input list
  30.302 + */
  30.303 +Sxpr cons_remove_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v){
  30.304 +    Sxpr prev = ONULL, elt, next;
  30.305 +
  30.306 +    for(elt = l; CONSP(elt); elt = next){
  30.307 +        next = CDR(elt);
  30.308 +        if(test_fn(v, CAR(elt))){
  30.309 +            if(NULLP(prev)){
  30.310 +                l = next;
  30.311 +            } else {
  30.312 +                CDR(prev) = next;
  30.313 +            }
  30.314 +        }
  30.315 +    }
  30.316 +    return l;
  30.317 +}
  30.318 +
  30.319 +/** Set the value for a key in an alist (GC only).
  30.320 + * If the key is present, changes the value, otherwise
  30.321 + * adds a new cell.
  30.322 + *
  30.323 + * @param k key
  30.324 + * @param v value
  30.325 + * @param l alist
  30.326 + * @return modified or extended list
  30.327 + */
  30.328 +Sxpr setf(Sxpr k, Sxpr v, Sxpr l){
  30.329 +    Sxpr e = assoc(k, l);
  30.330 +    if(NULLP(e)){
  30.331 +        l = acons(k, v, l);
  30.332 +    } else {
  30.333 +        CAR(CDR(e)) = v;
  30.334 +    }
  30.335 +    return l;
  30.336 +}
  30.337 +/*============================================================================*/
  30.338 +#endif /* USE_GC */
  30.339 +
  30.340 +/** Create a new atom with the given name.
  30.341 + *
  30.342 + * @param name the name
  30.343 + * @return new atom
  30.344 + */
  30.345 +Sxpr atom_new(char *name){
  30.346 +    Sxpr n, obj = ONOMEM;
  30.347 +
  30.348 +    n = string_new(name);
  30.349 +    if(NOMEMP(n)) goto exit;
  30.350 +    obj = HALLOC(ObjAtom, T_ATOM);
  30.351 +    if(NOMEMP(obj)) goto exit;
  30.352 +    OBJ_ATOM(obj)->name = n;
  30.353 +  exit:
  30.354 +    return obj;
  30.355 +}
  30.356 +
  30.357 +/** Free an atom.
  30.358 + *
  30.359 + * @param obj to free
  30.360 + */
  30.361 +void atom_free(Sxpr obj){
  30.362 +    // Interned atoms are shared, so do not free.
  30.363 +    if(OBJ_ATOM(obj)->interned) return;
  30.364 +    objfree(OBJ_ATOM(obj)->name);
  30.365 +    hfree(obj);
  30.366 +}
  30.367 +
  30.368 +/** Print an atom. Prints the atom name.
  30.369 + *
  30.370 + * @param io stream to print to
  30.371 + * @param obj to print
  30.372 + * @param flags print flags
  30.373 + * @return number of bytes printed
  30.374 + */
  30.375 +int atom_print(IOStream *io, Sxpr obj, unsigned flags){
  30.376 +    //return string_print(io, OBJ_ATOM(obj)->name, (flags | PRINT_RAW));
  30.377 +    return string_print(io, OBJ_ATOM(obj)->name, flags);
  30.378 +}
  30.379 +
  30.380 +/** Atom equality.
  30.381 + *
  30.382 + * @param x to compare
  30.383 + * @param y to compare
  30.384 + * @return 1 if equal, 0 otherwise
  30.385 + */
  30.386 +int atom_equal(Sxpr x, Sxpr y){
  30.387 +    int ok;
  30.388 +    ok = eq(x, y);
  30.389 +    if(ok) goto exit;
  30.390 +    ok = ATOMP(y) && string_equal(OBJ_ATOM(x)->name, OBJ_ATOM(y)->name);
  30.391 +    if(ok) goto exit;
  30.392 +    ok = STRINGP(y) && string_equal(OBJ_ATOM(x)->name, y);
  30.393 +  exit:
  30.394 +    return ok;
  30.395 +}
  30.396 +
  30.397 +/** Get the name of an atom.
  30.398 + *
  30.399 + * @param obj atom
  30.400 + * @return name
  30.401 + */
  30.402 +char * atom_name(Sxpr obj){
  30.403 +    return string_string(OBJ_ATOM(obj)->name);
  30.404 +}
  30.405 +
  30.406 +/** Get the C string from a string sxpr.
  30.407 + *
  30.408 + * @param obj string sxpr
  30.409 + * @return string
  30.410 + */
  30.411 +char * string_string(Sxpr obj){
  30.412 +    return OBJ_STRING(obj);
  30.413 +}
  30.414 +
  30.415 +/** Get the length of a string.
  30.416 + *
  30.417 + * @param obj string
  30.418 + * @return length
  30.419 + */
  30.420 +int string_length(Sxpr obj){
  30.421 +    return strlen(OBJ_STRING(obj));
  30.422 +}
  30.423 +
  30.424 +/** Create a new string. The input string is copied,
  30.425 + * and must be null-terminated.
  30.426 + *
  30.427 + * @param s characters to put in the string
  30.428 + * @return new sxpr
  30.429 + */
  30.430 +Sxpr string_new(char *s){
  30.431 +    int n = (s ? strlen(s) : 0);
  30.432 +    Sxpr obj;
  30.433 +    obj = halloc(n+1, T_STRING);
  30.434 +    if(!NOMEMP(obj)){
  30.435 +        char *str = OBJ_STRING(obj);
  30.436 +        strncpy(str, s, n);
  30.437 +        str[n] = '\0';
  30.438 +    }
  30.439 +    return obj;
  30.440 +}
  30.441 +
  30.442 +/** Free a string.
  30.443 + *
  30.444 + * @param obj to free
  30.445 + */
  30.446 +void string_free(Sxpr obj){
  30.447 +    hfree(obj);
  30.448 +}
  30.449 +
  30.450 +/** Determine if a string needs escapes when printed
  30.451 + * using the given flags.
  30.452 + *
  30.453 + * @param str string to check
  30.454 + * @param flags print flags
  30.455 + * @return 1 if needs escapes, 0 otherwise
  30.456 + */
  30.457 +int needs_escapes(char *str, unsigned flags){
  30.458 +    char *c;
  30.459 +    int val = 0;
  30.460 +
  30.461 +    if(str){
  30.462 +	for(c=str; *c; c++){
  30.463 +	    if(in_alpha_class(*c)) continue;
  30.464 +	    if(in_decimal_digit_class(*c)) continue;
  30.465 +	    if(in_class(*c, "/._+:@~-")) continue;
  30.466 +	    val = 1;
  30.467 +	    break;
  30.468 +	}
  30.469 +    }
  30.470 +    //printf("\n> val=%d str=|%s|\n", val, str);
  30.471 +    return val;
  30.472 +}
  30.473 +
  30.474 +/** Print a string to a stream, with escapes if necessary.
  30.475 + *
  30.476 + * @param io stream to print to
  30.477 + * @param str string
  30.478 + * @param flags print flags
  30.479 + * @return number of bytes written
  30.480 + */
  30.481 +int _string_print(IOStream *io, char *str, unsigned flags){
  30.482 +    int k = 0;
  30.483 +    if((flags & PRINT_RAW) || !needs_escapes(str, flags)){
  30.484 +        k += IOStream_print(io, str);
  30.485 +    } else {
  30.486 +	k += IOStream_print(io, "\"");
  30.487 +	if(str){
  30.488 +            char *s;
  30.489 +            for(s = str; *s; s++){
  30.490 +                if(*s < ' ' || *s >= 127 ){
  30.491 +                    switch(*s){
  30.492 +                    case '\a': k += IOStream_print(io, "\\a");  break;
  30.493 +                    case '\b': k += IOStream_print(io, "\\b");  break;
  30.494 +                    case '\f': k += IOStream_print(io, "\\f");  break;
  30.495 +                    case '\n': k += IOStream_print(io, "\\n");  break;
  30.496 +                    case '\r': k += IOStream_print(io, "\\r");  break;
  30.497 +                    case '\t': k += IOStream_print(io, "\\t");  break;
  30.498 +                    case '\v': k += IOStream_print(io, "\\v");  break;
  30.499 +                    default:
  30.500 +                        // Octal escape;
  30.501 +                        k += IOStream_print(io, "\\%o", *s);
  30.502 +                        break;
  30.503 +                    }
  30.504 +                } else if(*s == c_double_quote ||
  30.505 +                          *s == c_single_quote ||
  30.506 +                          *s == c_escape){
  30.507 +                    k += IOStream_print(io, "\\%c", *s);
  30.508 +                } else {
  30.509 +                    k+= IOStream_print(io, "%c", *s);
  30.510 +                }
  30.511 +            }
  30.512 +	}
  30.513 +	k += IOStream_print(io, "\"");
  30.514 +    }
  30.515 +    return k;
  30.516 +}
  30.517 +
  30.518 +/** Print a string to a stream, with escapes if necessary.
  30.519 + *
  30.520 + * @param io stream to print to
  30.521 + * @param obj string
  30.522 + * @param flags print flags
  30.523 + * @return number of bytes written
  30.524 + */
  30.525 +int string_print(IOStream *io, Sxpr obj, unsigned flags){
  30.526 +    return _string_print(io, OBJ_STRING(obj), flags);
  30.527 +}
  30.528 +
  30.529 +/** Compare an sxpr with a string for equality.
  30.530 + *
  30.531 + * @param x string to compare with
  30.532 + * @param y sxpr to compare
  30.533 + * @return 1 if equal, 0 otherwise
  30.534 + */
  30.535 +int string_equal(Sxpr x, Sxpr y){
  30.536 +    int ok = 0;
  30.537 +    ok = eq(x,y);
  30.538 +    if(ok) goto exit;
  30.539 +    ok = has_type(y, T_STRING) && !strcmp(OBJ_STRING(x), OBJ_STRING(y));
  30.540 +    if(ok) goto exit;
  30.541 +    ok = has_type(y, T_ATOM) && !strcmp(OBJ_STRING(x), atom_name(y));
  30.542 +  exit:
  30.543 +    return ok;
  30.544 +}
  30.545 +
  30.546 +/** Create a new cons cell.
  30.547 + * The cell is ONOMEM if either argument is.
  30.548 + *
  30.549 + * @param car sxpr for the car
  30.550 + * @param cdr sxpr for the cdr
  30.551 + * @return new cons
  30.552 + */
  30.553 +Sxpr cons_new(Sxpr car, Sxpr cdr){
  30.554 +    Sxpr obj;
  30.555 +    if(NOMEMP(car) || NOMEMP(cdr)){
  30.556 +        obj = ONOMEM;
  30.557 +    } else {
  30.558 +        obj = HALLOC(ObjCons, T_CONS);
  30.559 +        if(!NOMEMP(obj)){
  30.560 +            ObjCons *z = OBJ_CONS(obj);
  30.561 +            z->car = car;
  30.562 +            z->cdr = cdr;
  30.563 +        }
  30.564 +    }
  30.565 +    return obj;
  30.566 +}
  30.567 +
  30.568 +/** Push a new element onto a list.
  30.569 + *
  30.570 + * @param list list to add to
  30.571 + * @param elt element to add
  30.572 + * @return 0 if successful, error code otherwise
  30.573 + */
  30.574 +int cons_push(Sxpr *list, Sxpr elt){
  30.575 +    Sxpr l;
  30.576 +    l = cons_new(elt, *list);
  30.577 +    if(NOMEMP(l)) return -ENOMEM;
  30.578 +    *list = l;
  30.579 +    return 0;
  30.580 +}
  30.581 +
  30.582 +/** Free a cons. Recursively frees the car and cdr.
  30.583 + *
  30.584 + * @param obj to free
  30.585 + */
  30.586 +void cons_free(Sxpr obj){
  30.587 +    Sxpr next;
  30.588 +    for(; CONSP(obj); obj = next){
  30.589 +	next = CDR(obj);
  30.590 +	objfree(CAR(obj));
  30.591 +	hfree(obj);
  30.592 +    }
  30.593 +    if(!NULLP(obj)){
  30.594 +	objfree(obj);
  30.595 +    }
  30.596 +}
  30.597 +
  30.598 +/** Free a cons and its cdr cells, but not the car sxprs.
  30.599 + * Does nothing if called on something that is not a cons.
  30.600 + *
  30.601 + * @param obj to free
  30.602 + */
  30.603 +void cons_free_cells(Sxpr obj){
  30.604 +    Sxpr next;
  30.605 +    for(; CONSP(obj); obj = next){
  30.606 +	next = CDR(obj);
  30.607 +	hfree(obj);
  30.608 +    }
  30.609 +}
  30.610 +
  30.611 +/** Print a cons.
  30.612 + * Prints the cons in list format if the cdrs are conses.
  30.613 + * uses pair (dot) format if the last cdr is not a cons (or null).
  30.614 + *
  30.615 + * @param io stream to print to
  30.616 + * @param obj to print
  30.617 + * @param flags print flags
  30.618 + * @return number of bytes written
  30.619 + */
  30.620 +int cons_print(IOStream *io, Sxpr obj, unsigned flags){
  30.621 +    int first = 1;
  30.622 +    int k = 0;
  30.623 +    k += IOStream_print(io, "(");
  30.624 +    for( ; CONSP(obj) ; obj = CDR(obj)){
  30.625 +        if(first){ 
  30.626 +            first = 0;
  30.627 +        } else {
  30.628 +            k += IOStream_print(io, " ");
  30.629 +        }
  30.630 +        k += objprint(io, CAR(obj), flags);
  30.631 +    }
  30.632 +    if(!NULLP(obj)){
  30.633 +        k += IOStream_print(io, " . ");
  30.634 +        k += objprint(io, obj, flags);
  30.635 +    }
  30.636 +    k += IOStream_print(io, ")");
  30.637 +    return (IOStream_error(io) ? -1 : k);
  30.638 +}
  30.639 +
  30.640 +/** Compare a cons with another sxpr for equality.
  30.641 + * If y is a cons, compares the cars and cdrs recursively.
  30.642 + *
  30.643 + * @param x cons to compare
  30.644 + * @param y sxpr to compare
  30.645 + * @return 1 if equal, 0 otherwise
  30.646 + */
  30.647 +int cons_equal(Sxpr x, Sxpr y){
  30.648 +    return CONSP(y) &&
  30.649 +        objequal(CAR(x), CAR(y)) &&
  30.650 +        objequal(CDR(x), CDR(y));
  30.651 +}
  30.652 +
  30.653 +/** Return the length of a cons list.
  30.654 + *
  30.655 + * @param obj list
  30.656 + * @return length
  30.657 + */
  30.658 +int cons_length(Sxpr obj){
  30.659 +    int count = 0;
  30.660 +    for( ; CONSP(obj); obj = CDR(obj)){
  30.661 +        count++;
  30.662 +    }
  30.663 +    return count;
  30.664 +}
  30.665 +
  30.666 +/** Destructively reverse a cons list in-place.
  30.667 + * If the argument is not a cons it is returned unchanged.
  30.668 + * 
  30.669 + * @param l to reverse
  30.670 + * @return reversed list
  30.671 + */
  30.672 +Sxpr nrev(Sxpr l){
  30.673 +    if(CONSP(l)){
  30.674 +	// Iterate down the cells in the list making the cdr of
  30.675 +	// each cell point to the previous cell. The last cell 
  30.676 +	// is the head of the reversed list.
  30.677 +	Sxpr prev = ONULL;
  30.678 +	Sxpr cell = l;
  30.679 +	Sxpr next;
  30.680 +
  30.681 +	while(1){
  30.682 +	    next = CDR(cell);
  30.683 +	    CDR(cell) = prev;
  30.684 +	    if(!CONSP(next)) break;
  30.685 +	    prev = cell;
  30.686 +	    cell = next;
  30.687 +	}
  30.688 +	l = cell;
  30.689 +    }
  30.690 +    return l;
  30.691 +}
  30.692 +
  30.693 +/** Print the null sxpr.	
  30.694 + *
  30.695 + * @param io stream to print to
  30.696 + * @param obj to print
  30.697 + * @param flags print flags
  30.698 + * @return number of bytes written
  30.699 + */
  30.700 +static int null_print(IOStream *io, Sxpr obj, unsigned flags){
  30.701 +    return IOStream_print(io, "()");
  30.702 +}
  30.703 +
  30.704 +/** Print the `unspecified' sxpr none.
  30.705 + *
  30.706 + * @param io stream to print to
  30.707 + * @param obj to print
  30.708 + * @param flags print flags
  30.709 + * @return number of bytes written
  30.710 + */
  30.711 +static int none_print(IOStream *io, Sxpr obj, unsigned flags){
  30.712 +    return IOStream_print(io, "<none>");
  30.713 +}
  30.714 +
  30.715 +/** Print an integer.
  30.716 + *
  30.717 + * @param io stream to print to
  30.718 + * @param obj to print
  30.719 + * @param flags print flags
  30.720 + * @return number of bytes written
  30.721 + */
  30.722 +static int int_print(IOStream *io, Sxpr obj, unsigned flags){
  30.723 +    return IOStream_print(io, "%d", OBJ_INT(obj));
  30.724 +}
  30.725 +
  30.726 +/** Print a boolean.
  30.727 + *
  30.728 + * @param io stream to print to
  30.729 + * @param obj to print
  30.730 + * @param flags print flags
  30.731 + * @return number of bytes written
  30.732 + */
  30.733 +static int bool_print(IOStream *io, Sxpr obj, unsigned flags){
  30.734 +    return IOStream_print(io, (OBJ_UINT(obj) ? k_true : k_false));
  30.735 +}
  30.736 +
  30.737 +int sxprp(Sxpr obj, Sxpr name){
  30.738 +    return CONSP(obj) && objequal(CAR(obj), name);
  30.739 +}
  30.740 +
  30.741 +/** Get the name of an element.
  30.742 + * 
  30.743 + * @param obj element
  30.744 + * @return name
  30.745 + */
  30.746 +Sxpr sxpr_name(Sxpr obj){
  30.747 +    Sxpr val = ONONE;
  30.748 +    if(CONSP(obj)){
  30.749 +        val = CAR(obj);
  30.750 +    } else if(STRINGP(obj) || ATOMP(obj)){
  30.751 +        val = obj;
  30.752 +    }
  30.753 +    return val;
  30.754 +}
  30.755 +
  30.756 +int sxpr_is(Sxpr obj, char *s){
  30.757 +    if(ATOMP(obj)) return !strcmp(atom_name(obj), s);
  30.758 +    if(STRINGP(obj)) return !strcmp(string_string(obj), s);
  30.759 +    return 0;
  30.760 +}
  30.761 +
  30.762 +int sxpr_elementp(Sxpr obj, Sxpr name){
  30.763 +    return CONSP(obj) && objequal(CAR(obj), name);
  30.764 +}
  30.765 +
  30.766 +/** Get the attributes of an sxpr.
  30.767 + * 
  30.768 + * @param obj sxpr
  30.769 + * @return attributes
  30.770 + */
  30.771 +Sxpr sxpr_attributes(Sxpr obj){
  30.772 +    Sxpr val = ONULL;
  30.773 +    if(CONSP(obj)){
  30.774 +        obj = CDR(obj);
  30.775 +        if(CONSP(obj)){
  30.776 +            obj = CAR(obj);
  30.777 +            if(sxprp(obj, intern("@"))){
  30.778 +                val = CDR(obj);
  30.779 +            }
  30.780 +        }
  30.781 +    }
  30.782 +    return val;
  30.783 +}
  30.784 +
  30.785 +Sxpr sxpr_attribute(Sxpr obj, Sxpr key, Sxpr def){
  30.786 +    Sxpr val = ONONE;
  30.787 +    val = assoc(sxpr_attributes(obj), key);
  30.788 +    if(CONSP(val) && CONSP(CDR(val))){
  30.789 +        val = CADR(def);
  30.790 +    } else {
  30.791 +        val = def;
  30.792 +    }
  30.793 +    return val;
  30.794 +}
  30.795 +
  30.796 +/** Get the children of an sxpr.
  30.797 + * 
  30.798 + * @param obj sxpr
  30.799 + * @return children
  30.800 + */
  30.801 +Sxpr sxpr_children(Sxpr obj){
  30.802 +    Sxpr val = ONULL;
  30.803 +    if(CONSP(obj)){
  30.804 +        val = CDR(obj);
  30.805 +        if(CONSP(val) && sxprp(CAR(val), intern("@"))){
  30.806 +            val = CDR(val);
  30.807 +        }
  30.808 +    }
  30.809 +    return val;
  30.810 +}
  30.811 +
  30.812 +Sxpr sxpr_child(Sxpr obj, Sxpr name, Sxpr def){
  30.813 +    Sxpr val = ONONE;
  30.814 +    Sxpr l;
  30.815 +    for(l = sxpr_children(obj); CONSP(l); l = CDR(l)){
  30.816 +        if(sxprp(CAR(l), name)){
  30.817 +            val = CAR(l);
  30.818 +            break;
  30.819 +        }
  30.820 +    }
  30.821 +    if(NONEP(val)) val = def;
  30.822 +    return val;
  30.823 +}
  30.824 +
  30.825 +Sxpr sxpr_child0(Sxpr obj, Sxpr def){
  30.826 +    Sxpr val = ONONE;
  30.827 +    Sxpr l = sxpr_children(obj);
  30.828 +    if(CONSP(l)){
  30.829 +        val = CAR(l);
  30.830 +    } else {
  30.831 +        val = def;
  30.832 +    }
  30.833 +    return val;
  30.834 +}
  30.835 +
  30.836 +Sxpr sxpr_child_value(Sxpr obj, Sxpr name, Sxpr def){
  30.837 +    Sxpr val = ONONE;
  30.838 +    val = sxpr_child(obj, name, ONONE);
  30.839 +    if(NONEP(val)){
  30.840 +        val = def;
  30.841 +    } else {
  30.842 +        val = sxpr_child0(val, def);
  30.843 +    }
  30.844 +    return val;
  30.845 +}
  30.846 +
  30.847 +/** Table of interned symbols. Indexed by symbol name. */
  30.848 +static HashTable *symbols = NULL;
  30.849 +
  30.850 +/** Hash function for entries in the symbol table.
  30.851 + *
  30.852 + * @param key to hash
  30.853 + * @return hashcode
  30.854 + */
  30.855 +static Hashcode sym_hash_fn(void *key){
  30.856 +    return hash_string((char*)key);
  30.857 +}
  30.858 +
  30.859 +/** Key equality function for the symbol table.
  30.860 + *
  30.861 + * @param x to compare
  30.862 + * @param y to compare
  30.863 + * @return 1 if equal, 0 otherwise
  30.864 + */
  30.865 +static int sym_equal_fn(void *x, void *y){
  30.866 +    return !strcmp((char*)x, (char*)y);
  30.867 +}
  30.868 +
  30.869 +/** Entry free function for the symbol table.
  30.870 + *
  30.871 + * @param table the entry is in
  30.872 + * @param entry being freed
  30.873 + */
  30.874 +static void sym_free_fn(HashTable *table, HTEntry *entry){
  30.875 +    if(entry){
  30.876 +	objfree(((ObjAtom*)entry->value)->name);
  30.877 +	HTEntry_free(entry);
  30.878 +    }
  30.879 +}
  30.880 +	
  30.881 +/** Initialize the symbol table.
  30.882 + *
  30.883 + * @return 0 on sucess, error code otherwise
  30.884 + */
  30.885 +static int init_symbols(void){
  30.886 +    symbols = HashTable_new(100);
  30.887 +    if(symbols){
  30.888 +        symbols->key_hash_fn = sym_hash_fn;
  30.889 +        symbols->key_equal_fn = sym_equal_fn;
  30.890 +	symbols->entry_free_fn = sym_free_fn;
  30.891 +        return 0;
  30.892 +    }
  30.893 +    return -1;
  30.894 +}
  30.895 +
  30.896 +/** Cleanup the symbol table. Frees the table and all its symbols.
  30.897 + */
  30.898 +void cleanup_symbols(void){
  30.899 +    HashTable_free(symbols);
  30.900 +    symbols = NULL;
  30.901 +}
  30.902 +
  30.903 +/** Get the interned symbol with the given name.
  30.904 + * No new symbol is created.
  30.905 + *
  30.906 + * @return symbol or null
  30.907 + */
  30.908 +Sxpr get_symbol(char *sym){
  30.909 +    HTEntry *entry;
  30.910 +    if(!symbols){
  30.911 +	if(init_symbols()) return ONOMEM;
  30.912 +	return ONULL;
  30.913 +    }
  30.914 +    entry = HashTable_get_entry(symbols, sym);
  30.915 +    if(entry){
  30.916 +        return OBJP(T_ATOM, entry->value);
  30.917 +    } else {
  30.918 +        return ONULL;
  30.919 +    }
  30.920 +}
  30.921 +
  30.922 +/** Get the interned symbol with the given name.
  30.923 + * Creates a new symbol if necessary.
  30.924 + *
  30.925 + * @return symbol
  30.926 + */
  30.927 +Sxpr intern(char *sym){
  30.928 +    Sxpr symbol = get_symbol(sym);
  30.929 +    if(NULLP(symbol)){
  30.930 +	if(!symbols) return ONOMEM;
  30.931 +        symbol = atom_new(sym);
  30.932 +        if(!NOMEMP(symbol)){
  30.933 +	    OBJ_ATOM(symbol)->interned = TRUE;
  30.934 +            HashTable_add(symbols, atom_name(symbol), get_ptr(symbol));
  30.935 +        }
  30.936 +    }
  30.937 +    return symbol;
  30.938 +}
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/tools/lib/sxpr.h	Mon Jun 28 15:03:15 2004 +0000
    31.3 @@ -0,0 +1,413 @@
    31.4 +/*
    31.5 + *
    31.6 + * This library is free software; you can redistribute it and/or modify
    31.7 + * it under the terms of the GNU Lesser General Public License as
    31.8 + * published by the Free Software Foundation; either version 2.1 of the
    31.9 + * License, or  (at your option) any later version. This library is 
   31.10 + * distributed in the  hope that it will be useful, but WITHOUT ANY
   31.11 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or
   31.12 + * FITNESS FOR A PARTICULAR PURPOSE.
   31.13 + * See the GNU Lesser General Public License for more details.
   31.14 + *
   31.15 + * You should have received a copy of the GNU Lesser General Public License
   31.16 + * along with this library; if not, write to the Free Software Foundation,
   31.17 + * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   31.18 + */
   31.19 +#ifndef _XEN_LIB_SXPR_H_
   31.20 +#define _XEN_LIB_SXPR_H_
   31.21 +
   31.22 +#include <stdint.h>
   31.23 +
   31.24 +#include "hash_table.h"
   31.25 +#include "iostream.h"
   31.26 +#include "allocate.h"
   31.27 +
   31.28 +/** @file
   31.29 + * Definitions for rules and sxprs.
   31.30 + */
   31.31 +
   31.32 +#ifndef NULL
   31.33 +#define NULL 0
   31.34 +#endif
   31.35 +
   31.36 +#ifndef TRUE
   31.37 +#define TRUE 1
   31.38 +#endif
   31.39 +
   31.40 +#ifndef FALSE
   31.41 +#define FALSE 0
   31.42 +#endif
   31.43 +
   31.44 +/** Sxpr type. */
   31.45 +typedef int16_t TypeCode;
   31.46 +
   31.47 +/** A typed sxpr handle.*/
   31.48 +typedef struct Sxpr {
   31.49 +    /** Sxpr type. */
   31.50 +    TypeCode type;
   31.51 +    union {
   31.52 +	/** Sxpr value. */
   31.53 +        unsigned long ul;
   31.54 +	/** Pointer. */
   31.55 +        void *ptr;
   31.56 +    } v;
   31.57 +} Sxpr;
   31.58 +
   31.59 +/** Sxpr type to indicate out of memory. */
   31.60 +#define T_NOMEM      ((TypeCode)-1)
   31.61 +/** The 'unspecified' sxpr. */
   31.62 +#define T_NONE       ((TypeCode)0)
   31.63 +/** The empty list. */
   31.64 +#define T_NULL       ((TypeCode)1)
   31.65 +/** Unsigned integer. */
   31.66 +#define T_UINT       ((TypeCode)2)
   31.67 +/** A string. */
   31.68 +#define T_STRING     ((TypeCode)3)
   31.69 +/** An atom. */
   31.70 +#define T_ATOM       ((TypeCode)4)
   31.71 +/** A boolean. */
   31.72 +#define T_BOOL       ((TypeCode)5)
   31.73 +
   31.74 +/** A cons (pair or list). */
   31.75 +#define T_CONS       ((TypeCode)10)
   31.76 +
   31.77 +/** An error. */
   31.78 +#define T_ERR        ((TypeCode)40)
   31.79 +
   31.80 +/** An atom. */
   31.81 +typedef struct ObjAtom {
   31.82 +    Sxpr name;
   31.83 +    Hashcode hashcode;
   31.84 +    int interned;
   31.85 +} ObjAtom;
   31.86 +
   31.87 +/** A cons (pair). */
   31.88 +typedef struct ObjCons {
   31.89 +    Sxpr car;
   31.90 +    Sxpr cdr;
   31.91 +} ObjCons;
   31.92 +
   31.93 +/** A vector. */
   31.94 +typedef struct ObjVector {
   31.95 +    int n;
   31.96 +    Sxpr data[0];
   31.97 +} ObjVector;
   31.98 +
   31.99 +/** Flags for sxpr printing. */
  31.100 +enum PrintFlags {
  31.101 +    PRINT_RAW           = 0x001,
  31.102 +    PRINT_TYPE          = 0x002,
  31.103 +    PRINT_PRETTY        = 0x004,
  31.104 +    PRINT_NUM           = 0x008,
  31.105 +};
  31.106 +
  31.107 +/** An integer sxpr.
  31.108 + *
  31.109 + * @param ty type
  31.110 + * @param val integer value
  31.111 + */
  31.112 +#define OBJI(ty, val) (Sxpr){ type: (ty), v: { ul: (val) }}
  31.113 +
  31.114 +/** A pointer sxpr.
  31.115 + * If the pointer is non-null, returns an sxpr containing it.
  31.116 + * If the pointer is null, returns ONOMEM.
  31.117 + *
  31.118 + * @param ty type
  31.119 + * @param val pointer
  31.120 + */
  31.121 +#define OBJP(ty, val) ((val) ? (Sxpr){ type: (ty), v: { ptr: (val) }} : ONOMEM)
  31.122 +
  31.123 +/** Make an integer sxpr containing a pointer.
  31.124 + *
  31.125 + * @param val pointer
  31.126 + */
  31.127 +#define PTR(val) OBJP(T_UINT, (void*)(val))
  31.128 +
  31.129 +/** Make an integer sxpr.
  31.130 + * @param x value
  31.131 + */
  31.132 +#define OINT(x)       OBJI(T_UINT,  x)
  31.133 +
  31.134 +/** Make an error sxpr.
  31.135 + *
  31.136 + * @param x value
  31.137 + */
  31.138 +#define OERR(x)       OBJI(T_ERR,   x)
  31.139 +
  31.140 +/** Out of memory constant. */
  31.141 +#define ONOMEM        OBJI(T_NOMEM, 0)
  31.142 +
  31.143 +/** The `unspecified' constant. */
  31.144 +#define ONONE         OBJI(T_NONE,  0)
  31.145 +
  31.146 +/** Empty list constant. */
  31.147 +#define ONULL         OBJI(T_NULL,  0)
  31.148 +
  31.149 +/** False constant. */
  31.150 +#define OFALSE        OBJI(T_BOOL,  0)
  31.151 +
  31.152 +/** True constant. */
  31.153 +#define OTRUE         OBJI(T_BOOL,  1)
  31.154 +
  31.155 +/* Recognizers for the various sxpr types.  */
  31.156 +#define ATOMP(obj)        has_type(obj, T_ATOM)
  31.157 +#define BOOLP(obj)        has_type(obj, T_BOOL)
  31.158 +#define CONSP(obj)        has_type(obj, T_CONS)
  31.159 +#define ERRP(obj)         has_type(obj, T_ERR)
  31.160 +#define INTP(obj)         has_type(obj, T_UINT)
  31.161 +#define NOMEMP(obj)       has_type(obj, T_NOMEM)
  31.162 +#define NONEP(obj)        has_type(obj, T_NONE)
  31.163 +#define NULLP(obj)        has_type(obj, T_NULL)
  31.164 +#define STRINGP(obj)      has_type(obj, T_STRING)
  31.165 +
  31.166 +#define TRUEP(obj)    get_ul(obj)
  31.167 +
  31.168 +/** Convert an sxpr to an unsigned integer. */
  31.169 +#define OBJ_UINT(x)   get_ul(x)
  31.170 +/** Convert an sxpr to an integer. */
  31.171 +#define OBJ_INT(x)    (int)get_ul(x)
  31.172 +
  31.173 +/* Conversions of sxprs to their values.
  31.174 + * No checking is done.
  31.175 + */
  31.176 +#define OBJ_STRING(x)  ((char*)get_ptr(x))
  31.177 +#define OBJ_CONS(x)    ((ObjCons*)get_ptr(x))
  31.178 +#define OBJ_ATOM(x)    ((ObjAtom*)get_ptr(x))
  31.179 +#define OBJ_SET(x)     ((ObjSet*)get_ptr(x))
  31.180 +#define CAR(x)         (OBJ_CONS(x)->car)
  31.181 +#define CDR(x)         (OBJ_CONS(x)->cdr)
  31.182 +
  31.183 +#define CAAR(x)        (CAR(CAR(x)))
  31.184 +#define CADR(x)        (CAR(CDR(x)))
  31.185 +#define CDAR(x)        (CDR(CAR(x)))
  31.186 +#define CDDR(x)        (CDR(CDR(x)))
  31.187 +
  31.188 +/** Get the integer value from an sxpr.
  31.189 + *
  31.190 + * @param obj sxpr
  31.191 + * @return value
  31.192 + */
  31.193 +static inline unsigned long get_ul(Sxpr obj){
  31.194 +    return obj.v.ul;
  31.195 +}
  31.196 +
  31.197 +/** Get the pointer value from an sxpr.
  31.198 + *
  31.199 + * @param obj sxpr
  31.200 + * @return value
  31.201 + */
  31.202 +static inline void * get_ptr(Sxpr obj){
  31.203 +    return obj.v.ptr;
  31.204 +}
  31.205 +
  31.206 +/** Create an sxpr containing a pointer.
  31.207 + *
  31.208 + * @param type typecode
  31.209 + * @param val pointer
  31.210 + * @return sxpr
  31.211 + */
  31.212 +static inline Sxpr obj_ptr(TypeCode type, void *val){
  31.213 +    return (Sxpr){ type: type, v: { ptr: val } };
  31.214 +}
  31.215 +
  31.216 +/** Create an sxpr containing an integer.
  31.217 + *
  31.218 + * @param type typecode
  31.219 + * @param val integer
  31.220 + * @return sxpr
  31.221 + */
  31.222 +static inline Sxpr obj_ul(TypeCode type, unsigned long val){
  31.223 +    return (Sxpr){ type: type, v: { ul: val } };
  31.224 +}
  31.225 +
  31.226 +/** Get the type of an sxpr.
  31.227 + *
  31.228 + * @param obj sxpr
  31.229 + * @return type
  31.230 + */
  31.231 +static inline TypeCode get_type(Sxpr obj){
  31.232 +    return obj.type;
  31.233 +}
  31.234 +
  31.235 +/** Check the type of an sxpr.
  31.236 + *
  31.237 + * @param obj sxpr
  31.238 + * @param type to check
  31.239 + * @return 1 if has the type, 0 otherwise
  31.240 + */
  31.241 +static inline int has_type(Sxpr obj, TypeCode type){
  31.242 +    return get_type(obj) == type;
  31.243 +}
  31.244 +
  31.245 +/** Compare sxprs for literal equality of type and value.
  31.246 + *
  31.247 + * @param x sxpr to compare
  31.248 + * @param y sxpr to compare
  31.249 + * @return 1 if equal, 0 otherwise
  31.250 + */
  31.251 +static inline int eq(Sxpr x, Sxpr y){
  31.252 +    return ((get_type(x) == get_type(y)) && (get_ul(x) == get_ul(y)));
  31.253 +}
  31.254 +
  31.255 +/** Checked version of CAR
  31.256 + *
  31.257 + * @param x sxpr
  31.258 + * @return CAR if a cons, x otherwise
  31.259 + */
  31.260 +static inline Sxpr car(Sxpr x){
  31.261 +    return (CONSP(x) ? CAR(x) : x);
  31.262 +}
  31.263 +
  31.264 +/** Checked version of CDR.
  31.265 + *
  31.266 + * @param x sxpr
  31.267 + * @return CDR if a cons, null otherwise
  31.268 + */
  31.269 +static inline Sxpr cdr(Sxpr x){
  31.270 +    return (CONSP(x) ? CDR(x) : ONULL);
  31.271 +}
  31.272 +
  31.273 +/** Allocate some memory and return an sxpr containing it.
  31.274 + * Returns ONOMEM if allocation failed.
  31.275 + *
  31.276 + * @param n number of bytes to allocate
  31.277 + * @param ty typecode
  31.278 + * @return sxpr
  31.279 + */
  31.280 +static inline Sxpr halloc(size_t n,  TypeCode ty){
  31.281 +    return OBJP(ty, allocate(n));
  31.282 +}
  31.283 +
  31.284 +/** Allocate an sxpr containing a pointer to the given type.
  31.285 + *
  31.286 + * @param ty type (uses sizeof to determine how many bytes to allocate)
  31.287 + * @param code typecode
  31.288 + * @return sxpr, ONOMEM if allocation failed
  31.289 + */
  31.290 +#define HALLOC(ty, code) halloc(sizeof(ty), code)
  31.291 +
  31.292 +typedef int ObjPrintFn(IOStream *io, Sxpr obj, unsigned flags);
  31.293 +typedef int ObjEqualFn(Sxpr obj, Sxpr other);
  31.294 +typedef void ObjFreeFn(Sxpr obj);
  31.295 +
  31.296 +/** An sxpr type definition. */
  31.297 +typedef struct SxprType {
  31.298 +    TypeCode type;
  31.299 +    char *name;
  31.300 +    int pointer;
  31.301 +    ObjPrintFn *print;
  31.302 +    ObjEqualFn *equal;
  31.303 +    ObjFreeFn *free;
  31.304 +} SxprType;
  31.305 +
  31.306 +
  31.307 +extern SxprType *get_sxpr_type(int ty);
  31.308 +
  31.309 +/** Free the pointer in an sxpr.
  31.310 + *
  31.311 + * @param x sxpr containing a pointer
  31.312 + */
  31.313 +static inline void hfree(Sxpr x){
  31.314 +    deallocate(get_ptr(x));
  31.315 +}
  31.316 +
  31.317 +extern int objprint(IOStream *io, Sxpr x, unsigned flags);
  31.318 +extern int objequal(Sxpr x, Sxpr y);
  31.319 +extern void objfree(Sxpr x);
  31.320 +
  31.321 +extern void cons_free_cells(Sxpr obj);
  31.322 +extern Sxpr intern(char *s);
  31.323 +
  31.324 +extern Sxpr assoc(Sxpr k, Sxpr l);
  31.325 +extern Sxpr assocq(Sxpr k, Sxpr l);
  31.326 +extern Sxpr acons(Sxpr k, Sxpr v, Sxpr l);
  31.327 +extern Sxpr nrev(Sxpr l);
  31.328 +extern Sxpr cons_member(Sxpr l, Sxpr x);
  31.329 +extern Sxpr cons_member_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v);
  31.330 +extern int cons_subset(Sxpr s, Sxpr t);
  31.331 +extern int cons_set_equal(Sxpr s, Sxpr t);
  31.332 +
  31.333 +#ifdef USE_GC
  31.334 +extern Sxpr cons_remove(Sxpr l, Sxpr x);
  31.335 +extern Sxpr cons_remove_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v);
  31.336 +#endif
  31.337 +
  31.338 +extern Sxpr atom_new(char *name);
  31.339 +extern char * atom_name(Sxpr obj);
  31.340 +
  31.341 +extern Sxpr string_new(char *s);
  31.342 +extern char * string_string(Sxpr obj);
  31.343 +extern int string_length(Sxpr obj);
  31.344 +
  31.345 +extern Sxpr cons_new(Sxpr car, Sxpr cdr);
  31.346 +extern int cons_push(Sxpr *list, Sxpr elt);
  31.347 +extern int cons_length(Sxpr obj);
  31.348 +
  31.349 +Sxpr sxpr_name(Sxpr obj);
  31.350 +int sxpr_is(Sxpr obj, char *s);
  31.351 +int sxpr_elementp(Sxpr obj, Sxpr name);
  31.352 +Sxpr sxpr_attributes(Sxpr obj);
  31.353 +Sxpr sxpr_attribute(Sxpr obj, Sxpr key, Sxpr def);
  31.354 +Sxpr sxpr_children(Sxpr obj);
  31.355 +Sxpr sxpr_child(Sxpr obj, Sxpr name, Sxpr def);
  31.356 +Sxpr sxpr_child0(Sxpr obj, Sxpr def);
  31.357 +Sxpr sxpr_child_value(Sxpr obj, Sxpr name, Sxpr def);
  31.358 +
  31.359 +/** Create a new atom.
  31.360 + *
  31.361 + * @param s atom name
  31.362 + * @return new atom
  31.363 + */
  31.364 +static inline Sxpr mkatom(char *s){
  31.365 +    return atom_new(s);
  31.366 +}
  31.367 +
  31.368 +/** Create a new string sxpr.
  31.369 + *
  31.370 + * @param s string bytes (copied)
  31.371 + * @return new string
  31.372 + */
  31.373 +static inline Sxpr mkstring(char *s){
  31.374 +    return string_new(s);
  31.375 +}
  31.376 +
  31.377 +/** Create an integer sxpr.
  31.378 + *
  31.379 + * @param i value
  31.380 + * @return sxpr
  31.381 + */
  31.382 +static inline Sxpr mkint(int i){
  31.383 +    return OBJI(T_UINT, i);
  31.384 +}
  31.385 +
  31.386 +/** Create a boolean sxpr.
  31.387 + *
  31.388 + * @param b value
  31.389 + * @return sxpr
  31.390 + */
  31.391 +static inline Sxpr mkbool(int b){
  31.392 +    return OBJI(T_BOOL, (b ? 1 : 0));
  31.393 +}
  31.394 +
  31.395 +/* Constants used in parsing and printing. */
  31.396 +#define k_list_open    "("
  31.397 +#define c_list_open    '('
  31.398 +#define k_list_close   ")"
  31.399 +#define c_list_close   ')'
  31.400 +#define k_true         "true"
  31.401 +#define k_false        "false"
  31.402 +
  31.403 +#define c_var          '$'
  31.404 +#define c_escape       '\\'
  31.405 +#define c_single_quote '\''
  31.406 +#define c_double_quote '"'
  31.407 +#define c_string_open  c_double_quote
  31.408 +#define c_string_close c_double_quote
  31.409 +#define c_data_open    '['
  31.410 +#define c_data_close   ']'
  31.411 +#define c_binary       '*'
  31.412 +#define c_eval         '!'
  31.413 +#define c_concat_open  '{'
  31.414 +#define c_concat_close '}'
  31.415 +
  31.416 +#endif /* ! _XEN_LIB_SXPR_H_ */
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/tools/lib/sxpr_parser.c	Mon Jun 28 15:03:15 2004 +0000
    32.3 @@ -0,0 +1,897 @@
    32.4 +
    32.5 +#ifdef __KERNEL__
    32.6 +#  include <linux/config.h>
    32.7 +#  include <linux/module.h>
    32.8 +#  include <linux/kernel.h>
    32.9 +#  include <linux/string.h>
   32.10 +#  include <linux/errno.h>
   32.11 +#else
   32.12 +#  include <stdlib.h>
   32.13 +#  include <errno.h>
   32.14 +#endif
   32.15 +
   32.16 +#include "iostream.h"
   32.17 +#include "lexis.h"
   32.18 +#include "sxpr_parser.h"
   32.19 +#include "sys_string.h"
   32.20 +
   32.21 +/** @file
   32.22 + * Sxpr parsing.
   32.23 + *
   32.24 + * So that the parser does not leak memory, all sxprs constructed by
   32.25 + * the parser must be freed on error.  On successful parse the sxpr
   32.26 + * returned becomes the responsibility of the caller.
   32.27 + *
   32.28 + * @author Mike Wray <mike.wray@hpl.hp.com>
   32.29 + */
   32.30 +
   32.31 +#define dprintf(fmt, args...) IOStream_print(iostdout, "[DEBUG] %s" fmt, __FUNCTION__, ##args)
   32.32 +#define printf(fmt, args...)   IOStream_print(iostdout, fmt, ##args)
   32.33 +
   32.34 +static void reset(Parser *z);
   32.35 +static int inputchar(Parser *p, char c);
   32.36 +static int savechar(Parser *p, char c);
   32.37 +extern void parse_error(Parser *in);
   32.38 +extern void parse_error_id(Parser *in, ParseErrorId id);
   32.39 +
   32.40 +static int begin_start(Parser *p, char c);
   32.41 +static int state_start(Parser *p, char c);
   32.42 +static int end_start(Parser *p);
   32.43 +
   32.44 +static int begin_comment(Parser *p, char c);
   32.45 +static int state_comment(Parser *p, char c);
   32.46 +static int end_comment(Parser *p);
   32.47 +
   32.48 +static int begin_string(Parser *p, char c);
   32.49 +static int state_string(Parser *p, char c);
   32.50 +static int end_string(Parser *p);
   32.51 +static int state_escape(Parser *p, char c);
   32.52 +static int state_octal(Parser *p, char c);
   32.53 +static int state_hex(Parser *p, char c);
   32.54 +
   32.55 +static int begin_atom(Parser *p, char c);
   32.56 +static int state_atom(Parser *p, char c);
   32.57 +static int end_atom(Parser *p);
   32.58 +
   32.59 +static int state_list(Parser *p, char c);
   32.60 +static int begin_list(Parser *p, char c);
   32.61 +static int end_list(Parser *p);
   32.62 +
   32.63 +/** Print a parse error.
   32.64 + *
   32.65 + * @param in parser
   32.66 + * @param msg format followed by printf arguments
   32.67 + */
   32.68 +void eprintf(Parser *in, char *msg, ...){
   32.69 +    va_list args;
   32.70 +    if(in->error_out){
   32.71 +        va_start(args, msg);
   32.72 +        IOStream_vprint(in->error_out, msg, args);
   32.73 +        va_end(args);
   32.74 +    }
   32.75 +}
   32.76 +
   32.77 +/** Print a parse warning.
   32.78 + *
   32.79 + * @param in parser
   32.80 + * @param msg format followed by printf arguments
   32.81 + */
   32.82 +void wprintf(Parser *in, char *msg, ...){
   32.83 +    va_list args;
   32.84 +    if(in->error_out){
   32.85 +        va_start(args, msg);
   32.86 +        IOStream_vprint(in->error_out, msg, args);
   32.87 +        va_end(args);
   32.88 +    }
   32.89 +}
   32.90 +
   32.91 +/*============================================================================*/
   32.92 +
   32.93 +/** Record defining the message for a parse error. */
   32.94 +typedef struct {
   32.95 +  ParseErrorId id;
   32.96 +  char *message;
   32.97 +} ParseError;
   32.98 +
   32.99 +/** Format for printing parse error messages. */
  32.100 +#define PARSE_ERR_FMT "parse error> line %3d, column %2d: %s"
  32.101 +
  32.102 +/** Message catalog for the parse error codes. */
  32.103 +static ParseError catalog[] = {
  32.104 +  { PARSE_ERR_UNSPECIFIED,            "unspecified error" },
  32.105 +  { PARSE_ERR_NOMEM,                  "out of memory" },
  32.106 +  { PARSE_ERR_UNEXPECTED_EOF,         "unexpected end of input" },
  32.107 +  { PARSE_ERR_TOKEN_TOO_LONG,         "token too long" },
  32.108 +  { PARSE_ERR_INVALID_SYNTAX,         "syntax error" },
  32.109 +  { PARSE_ERR_INVALID_ESCAPE,         "invalid escape" },
  32.110 +  { 0, NULL }
  32.111 +};
  32.112 +
  32.113 +/** Number of entries in the message catalog. */
  32.114 +const static int catalog_n = sizeof(catalog)/sizeof(ParseError);
  32.115 +
  32.116 +void ParserState_free(ParserState *z){
  32.117 +    if(!z) return;
  32.118 +    objfree(z->val);
  32.119 +    deallocate(z);
  32.120 +}
  32.121 +
  32.122 +int ParserState_new(ParserStateFn *fn, ParserState *parent, ParserState **val){
  32.123 +    int err = 0;
  32.124 +    ParserState *z;
  32.125 +    z = ALLOCATE(ParserState);
  32.126 +    if(z){
  32.127 +        z->fn = fn;
  32.128 +        z->parent = parent;
  32.129 +        z->val = ONULL;
  32.130 +    } else {
  32.131 +        err = -ENOMEM;
  32.132 +    }
  32.133 +    if(!err) *val = z;
  32.134 +    return err;
  32.135 +}
  32.136 +
  32.137 +/** Free a parser.
  32.138 + * No-op if the parser is null.
  32.139 + *
  32.140 + * @param z parser 
  32.141 + */
  32.142 +void Parser_free(Parser *z){
  32.143 +    if(!z) return;
  32.144 +    objfree(z->val);
  32.145 +    z->val = ONONE;
  32.146 +    deallocate(z);
  32.147 +}
  32.148 +
  32.149 +/** Create a new parser. The error stream defaults to null.
  32.150 + */
  32.151 +Parser * Parser_new(void){
  32.152 +    Parser *z = ALLOCATE(Parser);
  32.153 +    int err = -ENOMEM;
  32.154 +  
  32.155 +    if(!z) goto exit;
  32.156 +    err = 0;
  32.157 +    reset(z);
  32.158 +  exit:
  32.159 +    if(err){
  32.160 +        Parser_free(z);
  32.161 +        z = NULL;
  32.162 +    }
  32.163 +    return z;
  32.164 +}
  32.165 +
  32.166 +/** Get the next character.
  32.167 + * Records the character read in the parser,
  32.168 + * and sets the line and character counts.
  32.169 + *
  32.170 + * @param p parser
  32.171 + * @return error flag: 0 on success, non-zero on error
  32.172 + */
  32.173 +static int inputchar(Parser *p, char c){
  32.174 +    int err = 0;
  32.175 +    if(c=='\n'){
  32.176 +        p->line_no++;
  32.177 +        p->char_no = 0;
  32.178 +    } else {
  32.179 +        p->char_no++;
  32.180 +    }
  32.181 +    return err;
  32.182 +}
  32.183 +
  32.184 +static int savechar(Parser *p, char c){
  32.185 +    int err = 0;
  32.186 +    if(p->buf_i >= p->buf_n){
  32.187 +        err = -ENOMEM;
  32.188 +        goto exit;
  32.189 +    }
  32.190 +    p->buf[p->buf_i] = c;
  32.191 +    p->buf_i++;
  32.192 +  exit:
  32.193 +    return err;
  32.194 +}
  32.195 +
  32.196 +int Parser_input_char(Parser *p, char c){
  32.197 +    int err = 0;
  32.198 +    if(at_eof(p)){
  32.199 +        //skip;
  32.200 +    } else {
  32.201 +        inputchar(p, c);
  32.202 +    }
  32.203 +    if(!p->state){
  32.204 +        err = begin_start(p, c);
  32.205 +        if(err) goto exit;
  32.206 +    }
  32.207 +    err = p->state->fn(p, c);
  32.208 +  exit:
  32.209 +    return err;
  32.210 +}
  32.211 +
  32.212 +int Parser_input_eof(Parser *p){
  32.213 +    int err = 0;
  32.214 +    p->eof = 1;
  32.215 +    err = Parser_input_char(p, IOSTREAM_EOF);
  32.216 +    return err;
  32.217 +}
  32.218 +
  32.219 +int Parser_input(Parser *p, char *buf, int buf_n){
  32.220 +    int err = 0;
  32.221 +    int i = 0;
  32.222 +    if(buf_n <= 0){
  32.223 +        err = Parser_input_eof(p);
  32.224 +        goto exit;
  32.225 +    }
  32.226 +    for(i = 0; i<buf_n; i++){
  32.227 +        err = Parser_input_char(p, buf[i]);
  32.228 +        if(err) goto exit;
  32.229 +    }
  32.230 +  exit:
  32.231 +    err = (err < 0 ? err : buf_n);
  32.232 +    return err;
  32.233 +}
  32.234 +
  32.235 +int Parser_push(Parser *p, ParserStateFn *fn){
  32.236 +    int err = 0;
  32.237 +    err = ParserState_new(fn, p->state, &p->state);
  32.238 +    return err;
  32.239 +}
  32.240 +        
  32.241 +int Parser_pop(Parser *p){
  32.242 +    int err = 0;
  32.243 +    ParserState *s = p->state;
  32.244 +    p->state = s->parent;
  32.245 +    ParserState_free(s);
  32.246 +    return err;
  32.247 +}
  32.248 +
  32.249 +int Parser_return(Parser *p){
  32.250 +    int err = 0;
  32.251 +    Sxpr val = ONONE;
  32.252 +    if(!p->state){
  32.253 +        err = -EINVAL;
  32.254 +        goto exit;
  32.255 +    }
  32.256 +    val = p->state->val;
  32.257 +    p->state->val = ONONE;
  32.258 +    err = Parser_pop(p);
  32.259 +    if(err) goto exit;
  32.260 +    if(p->state){
  32.261 +        err = cons_push(&p->state->val, val);
  32.262 +    } else {
  32.263 +        val = nrev(val);
  32.264 +        p->val = val;
  32.265 +    }
  32.266 +  exit:
  32.267 +    if(err){
  32.268 +        objfree(val);
  32.269 +    }
  32.270 +    return err;
  32.271 +}
  32.272 +
  32.273 +/** Determine if a character is a separator.
  32.274 + *
  32.275 + * @param p parser
  32.276 + * @param c character to test
  32.277 + * @return 1 if a separator, 0 otherwise
  32.278 + */
  32.279 +static int is_separator(Parser *p, char c){
  32.280 +    return in_sep_class(c);
  32.281 +}
  32.282 +
  32.283 +/** Return the current token.
  32.284 + * The return value points at the internal buffer, so
  32.285 + * it must not be modified (or freed). Use copy_token() if you need a copy.
  32.286 + *
  32.287 + * @param p parser
  32.288 + * @return token
  32.289 + */
  32.290 +char *peek_token(Parser *p){
  32.291 +    return p->buf;
  32.292 +}
  32.293 +
  32.294 +/** Return a copy of the current token.
  32.295 + * The returned value should be freed when finished with.
  32.296 + *
  32.297 + * @param p parser
  32.298 + * @return copy of token
  32.299 + */
  32.300 +char *copy_token(Parser *p){
  32.301 +    return strdup(peek_token(p));
  32.302 +}
  32.303 +
  32.304 +static int do_intern(Parser *p){
  32.305 +    int err = 0;
  32.306 +    Sxpr obj = intern(peek_token(p));
  32.307 +    if(NOMEMP(obj)){
  32.308 +        err = -ENOMEM;
  32.309 +    } else {
  32.310 +        p->state->val = obj;
  32.311 +    }
  32.312 +    return err;
  32.313 +}
  32.314 +
  32.315 +static int do_string(Parser *p){
  32.316 +    int err = 0;
  32.317 +    Sxpr obj;
  32.318 +    obj = string_new(peek_token(p));
  32.319 +    if(NOMEMP(obj)){
  32.320 +        err = -ENOMEM;
  32.321 +    } else {
  32.322 +        p->state->val = obj;
  32.323 +    }
  32.324 +    return err;
  32.325 +}
  32.326 +
  32.327 +void newtoken(Parser *p){
  32.328 +    memset(p->buf, 0, p->buf_n);
  32.329 +    p->buf_i = 0;
  32.330 +    p->tok_begin_line = p->line_no;
  32.331 +    p->tok_begin_char = p->char_no;
  32.332 +}
  32.333 +
  32.334 +int get_escape(char c, char *d){
  32.335 +    int err = 0;
  32.336 +    switch(c){
  32.337 +    case 'a':            *d = '\a'; break;
  32.338 +    case 'b':            *d = '\b'; break;
  32.339 +    case 'f':            *d = '\f'; break;
  32.340 +    case 'n':            *d = '\n'; break;
  32.341 +    case 'r':            *d = '\r'; break;
  32.342 +    case 't':            *d = '\t'; break;
  32.343 +    case 'v':            *d = '\v'; break;
  32.344 +    case c_escape:       *d = c_escape; break;
  32.345 +    case c_single_quote: *d = c_single_quote; break;
  32.346 +    case c_double_quote: *d = c_double_quote; break;
  32.347 +    default:
  32.348 +        err = -EINVAL;
  32.349 +    }
  32.350 +    return err;
  32.351 +}
  32.352 +
  32.353 +
  32.354 +int begin_start(Parser *p, char c){
  32.355 +    return Parser_push(p, state_start);
  32.356 +}
  32.357 +
  32.358 +int state_start(Parser *p, char c){
  32.359 +    int err = 0;
  32.360 +    if(at_eof(p)){
  32.361 +        err = end_start(p);
  32.362 +    } else if(in_space_class(c)){
  32.363 +        //skip
  32.364 +    } else if(in_comment_class(c)){
  32.365 +        begin_comment(p, c);
  32.366 +    } else if(c == c_list_open){
  32.367 +        begin_list(p, c);
  32.368 +    } else if(c == c_list_close){
  32.369 +        parse_error(p);
  32.370 +        err = -EINVAL;
  32.371 +    } else if(in_string_quote_class(c)){
  32.372 +        begin_string(p, c);
  32.373 +    } else if(in_printable_class(c)){
  32.374 +        begin_atom(p, c);
  32.375 +    } else if(c == 0x04){
  32.376 +        //ctrl-D, EOT: end-of-text.
  32.377 +        Parser_input_eof(p);
  32.378 +    } else {
  32.379 +        parse_error(p);
  32.380 +        err = -EINVAL;
  32.381 +    }
  32.382 +    return err;
  32.383 +}
  32.384 +
  32.385 +int end_start(Parser *p){
  32.386 +    int err = 0;
  32.387 +    err = Parser_return(p);
  32.388 +    return err;
  32.389 +}
  32.390 +
  32.391 +int begin_comment(Parser *p, char c){
  32.392 +    int err = 0;
  32.393 +    err = Parser_push(p, state_comment);
  32.394 +    if(err) goto exit;
  32.395 +    err = inputchar(p, c);
  32.396 +  exit:
  32.397 +    return err;
  32.398 +}
  32.399 +
  32.400 +int state_comment(Parser *p, char c){
  32.401 +    int err = 0;
  32.402 +    if(c == '\n' || at_eof(p)){
  32.403 +        err = end_comment(p);
  32.404 +    } else {
  32.405 +        err = inputchar(p, c);
  32.406 +    }
  32.407 +    return err;
  32.408 +}
  32.409 +
  32.410 +int end_comment(Parser *p){
  32.411 +    return Parser_pop(p);
  32.412 +}
  32.413 +
  32.414 +int begin_string(Parser *p, char c){
  32.415 +    int err = 0;
  32.416 +    err = Parser_push(p, state_string);
  32.417 +    if(err) goto exit;
  32.418 +    newtoken(p);
  32.419 +    p->state->delim = c;
  32.420 +  exit:
  32.421 +    return err;
  32.422 +}
  32.423 +
  32.424 +int state_string(Parser *p, char c){
  32.425 +    int err = 0;
  32.426 +    if(at_eof(p)){
  32.427 +        parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
  32.428 +        err = -EINVAL;
  32.429 +    } else if(c == p->state->delim){
  32.430 +        err = end_string(p);
  32.431 +    } else if(c == '\\'){
  32.432 +        err = Parser_push(p, state_escape);
  32.433 +    } else {
  32.434 +        err = savechar(p, c);
  32.435 +    }
  32.436 +    return err;
  32.437 +}
  32.438 +
  32.439 +int end_string(Parser *p){
  32.440 +    int err = 0;
  32.441 +    err = do_string(p);
  32.442 +    if(err) goto exit;
  32.443 +    err = Parser_return(p);
  32.444 +  exit:
  32.445 +    return err;
  32.446 +}
  32.447 +
  32.448 +int state_escape(Parser *p, char c){
  32.449 +    int err = 0;
  32.450 +    char d;
  32.451 +    if(at_eof(p)){
  32.452 +        parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
  32.453 +        err = -EINVAL;
  32.454 +        goto exit;
  32.455 +    }
  32.456 +    if(get_escape(c, &d) == 0){
  32.457 +        err = savechar(p, d);
  32.458 +        if(err) goto exit;
  32.459 +        err = Parser_pop(p);
  32.460 +    } else if(c == 'x'){
  32.461 +        p->state->fn = state_hex;
  32.462 +        p->state->ival = 0;
  32.463 +        p->state->count = 0;
  32.464 +    } else {
  32.465 +        p->state->fn = state_octal;
  32.466 +        p->state->ival = 0;
  32.467 +        p->state->count = 0;
  32.468 +        err = Parser_input_char(p, c);
  32.469 +    }
  32.470 +  exit:
  32.471 +    return err;
  32.472 +}
  32.473 +
  32.474 +int octaldone(Parser *p){
  32.475 +    int err = 0;
  32.476 +    char d = (char)(p->state->ival & 0xff);
  32.477 +    err = Parser_pop(p);
  32.478 +    if(err) goto exit;
  32.479 +    err = Parser_input_char(p, d);
  32.480 +  exit:
  32.481 +    return err;
  32.482 +}
  32.483 +
  32.484 +int octaldigit(Parser *p, char c){
  32.485 +    int err = 0;
  32.486 +    p->state->ival *= 8;
  32.487 +    p->state->ival += c - '0'; 
  32.488 +    p->state->count++;
  32.489 +    if(err) goto exit;
  32.490 +    if(p->state->ival < 0 || p->state->ival > 0xff){
  32.491 +        parse_error(p);
  32.492 +        err = -EINVAL;
  32.493 +        goto exit;
  32.494 +    }
  32.495 +    if(p->state->count == 3){
  32.496 +        err = octaldone(p);
  32.497 +    }
  32.498 +  exit:
  32.499 +    return err;
  32.500 +}
  32.501 +
  32.502 +int state_octal(Parser *p, char c){
  32.503 +    int err = 0;
  32.504 +    if(at_eof(p)){
  32.505 +        parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
  32.506 +        err = -EINVAL;
  32.507 +        goto exit;
  32.508 +    } else if('0' <= c && c <= '7'){
  32.509 +        err = octaldigit(p, c);
  32.510 +    } else {
  32.511 +        err = octaldone(p);
  32.512 +        if(err) goto exit;
  32.513 +        Parser_input_char(p, c);
  32.514 +    }
  32.515 +  exit:
  32.516 +    return err;
  32.517 +}
  32.518 +
  32.519 +int hexdone(Parser *p){
  32.520 +    int err = 0;
  32.521 +    char d = (char)(p->state->ival & 0xff);
  32.522 +    err = Parser_pop(p);
  32.523 +    if(err) goto exit;
  32.524 +    err = Parser_input_char(p, d);
  32.525 +  exit:
  32.526 +    return err;
  32.527 +}
  32.528 +    
  32.529 +int hexdigit(Parser *p, char c, char d){
  32.530 +    int err = 0;
  32.531 +    p->state->ival *= 16;
  32.532 +    p->state->ival += c - d; 
  32.533 +    p->state->count++;
  32.534 +    if(err) goto exit;
  32.535 +    if(p->state->ival < 0 || p->state->ival > 0xff){
  32.536 +        parse_error(p);
  32.537 +        err = -EINVAL;
  32.538 +        goto exit;
  32.539 +    }
  32.540 +    if(p->state->count == 2){
  32.541 +        err = hexdone(p);
  32.542 +    }
  32.543 +  exit:
  32.544 +    return err;
  32.545 +}
  32.546 +    
  32.547 +int state_hex(Parser *p, char c){
  32.548 +    int err = 0;
  32.549 +    if(at_eof(p)){
  32.550 +        parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
  32.551 +        err = -EINVAL;
  32.552 +        goto exit;
  32.553 +    } else if('0' <= c && c <= '9'){
  32.554 +        err = hexdigit(p, c, '0');
  32.555 +    } else if('A' <= c && c <= 'F'){
  32.556 +        err = hexdigit(p, c, 'A');
  32.557 +    } else if('a' <= c && c <= 'f'){
  32.558 +        err = hexdigit(p, c, 'a');
  32.559 +    } else if(p->state->count){
  32.560 +        err =hexdone(p);
  32.561 +        if(err) goto exit;
  32.562 +        Parser_input_char(p, c);
  32.563 +    }
  32.564 +  exit:
  32.565 +    return err;
  32.566 +}
  32.567 +
  32.568 +int begin_atom(Parser *p, char c){
  32.569 +    int err = 0;
  32.570 +    err = Parser_push(p, state_atom);
  32.571 +    if(err) goto exit;
  32.572 +    newtoken(p);
  32.573 +    err = savechar(p, c);
  32.574 +  exit:
  32.575 +    return err;
  32.576 +}
  32.577 +
  32.578 +int state_atom(Parser *p, char c){
  32.579 +    int err = 0;
  32.580 +    if(at_eof(p)){
  32.581 +        err = end_atom(p);
  32.582 +    } else if(is_separator(p, c) ||
  32.583 +              in_space_class(c) ||
  32.584 +              in_comment_class(c)){
  32.585 +        err = end_atom(p);
  32.586 +        if(err) goto exit;
  32.587 +        err = Parser_input_char(p, c);
  32.588 +    } else {
  32.589 +        err = savechar(p, c);
  32.590 +    }
  32.591 +  exit:
  32.592 +    return err;
  32.593 +}
  32.594 +
  32.595 +int end_atom(Parser *p){
  32.596 +    int err = 0;
  32.597 +    err = do_intern(p);
  32.598 +    if(err) goto exit;
  32.599 +    err = Parser_return(p);
  32.600 +  exit:
  32.601 +    return err;
  32.602 +}
  32.603 +
  32.604 +int state_list(Parser *p, char c){
  32.605 +    int err = 0;
  32.606 +    if(at_eof(p)){
  32.607 +        parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
  32.608 +        err = -EINVAL;
  32.609 +    } else if(c == c_list_close){
  32.610 +        p->state->val = nrev(p->state->val);
  32.611 +        err = end_list(p);
  32.612 +    } else {
  32.613 +        err = state_start(p, c);
  32.614 +    }
  32.615 +    return err;
  32.616 +    
  32.617 +}
  32.618 +
  32.619 +int begin_list(Parser *p, char c){
  32.620 +    return Parser_push(p, state_list);
  32.621 +}
  32.622 +
  32.623 +int end_list(Parser *p){
  32.624 +    return Parser_return(p);
  32.625 +}
  32.626 +
  32.627 +/** Reset the fields of a parser to initial values.
  32.628 + *
  32.629 + * @param z parser
  32.630 + */
  32.631 +static void reset(Parser *z){
  32.632 +  IOStream *error_out = z->error_out;
  32.633 +  int flags = z->flags;
  32.634 +  zero(z, sizeof(Parser));
  32.635 +  z->buf_n = sizeof(z->buf) - 1;
  32.636 +  z->buf_i = 0;
  32.637 +  z->line_no = 1;
  32.638 +  z->char_no = 0;
  32.639 +  z->error_out = error_out;
  32.640 +  z->flags = flags;
  32.641 +}
  32.642 +
  32.643 +/** Set the parser error stream.
  32.644 + * Parse errors are reported on the the error stream if it is non-null.
  32.645 + * 
  32.646 + * @param z parser
  32.647 + * @param error_out error stream
  32.648 + */
  32.649 +void set_error_stream(Parser *z, IOStream *error_out){
  32.650 +  if(z){
  32.651 +    z->error_out = error_out;
  32.652 +  }
  32.653 +}
  32.654 +
  32.655 +/** Get the parser error message for an error code.
  32.656 + *
  32.657 + * @param id error code
  32.658 + * @return error message (empty string if the code is unknown)
  32.659 + */
  32.660 +static char *get_message(ParseErrorId id){
  32.661 +  int i;
  32.662 +  for(i=0; i<catalog_n; i++){
  32.663 +    if(id == catalog[i].id){
  32.664 +      return catalog[i].message;
  32.665 +    }
  32.666 +  }
  32.667 +  return "";
  32.668 +}
  32.669 +
  32.670 +/** Get the line number.
  32.671 + *
  32.672 + * @param in parser
  32.673 + */
  32.674 +int get_line(Parser *in){
  32.675 +  return in->line_no;
  32.676 +}
  32.677 +
  32.678 +/** Get the column number.
  32.679 + *
  32.680 + * @param in parser
  32.681 + */
  32.682 +int get_column(Parser *in){
  32.683 +  return in->char_no;
  32.684 +}
  32.685 +
  32.686 +/** Get the line number the current token started on.
  32.687 + *
  32.688 + * @param in parser
  32.689 + */
  32.690 +int get_tok_line(Parser *in){
  32.691 +  return in->tok_begin_line;
  32.692 +}
  32.693 +
  32.694 +/** Get the column number the current token started on.
  32.695 + *
  32.696 + * @param in parser
  32.697 + */
  32.698 +int get_tok_column(Parser *in){
  32.699 +  return in->tok_begin_char;
  32.700 +}
  32.701 +
  32.702 +/** Report a parse error.
  32.703 + * Does nothing if the error stream is null or there is no error.
  32.704 + *
  32.705 + * @param in parser
  32.706 + */
  32.707 +static void report_error(Parser *in){
  32.708 +  if(in->error_out && in->err){
  32.709 +    char *msg = get_message(in->err);
  32.710 +    char *tok = peek_token(in);
  32.711 +    IOStream_print(in->error_out, PARSE_ERR_FMT,
  32.712 +		   get_tok_line(in), get_tok_column(in), msg);
  32.713 +    if(tok && tok[0]){
  32.714 +        IOStream_print(in->error_out, " '%s'", tok);
  32.715 +    }
  32.716 +    IOStream_print(in->error_out, "\n");
  32.717 +  }
  32.718 +}
  32.719 +
  32.720 +/** Get the error message for the current parse error code.
  32.721 + * Does nothing if there is no error.
  32.722 + *
  32.723 + * @param in parser
  32.724 + * @param buf where to place the message
  32.725 + * @param n maximum number of characters to place in buf
  32.726 + * @return current error code (zero for no error)
  32.727 + */
  32.728 +int parse_error_message(Parser *in, char *buf, int n){
  32.729 +    if(in->err){
  32.730 +        char *msg = get_message(in->err);
  32.731 +        snprintf(buf, n, PARSE_ERR_FMT, get_tok_line(in), get_tok_column(in), msg);
  32.732 +    }
  32.733 +    return in->err;
  32.734 +}
  32.735 +
  32.736 +/** Flag an unspecified parse error. All subsequent reads will fail.
  32.737 + *
  32.738 + * @param in parser
  32.739 + */
  32.740 +void parse_error(Parser *in){
  32.741 +    parse_error_id(in, PARSE_ERR_INVALID_SYNTAX);
  32.742 +}
  32.743 +
  32.744 +/** Flag a parse error. All subsequent reads will fail.
  32.745 + * Does not change the parser error code if it is already set.
  32.746 + *
  32.747 + * @param in parser
  32.748 + * @param id error code
  32.749 + */
  32.750 +void parse_error_id(Parser *in, ParseErrorId id){
  32.751 +    if(!in->err){
  32.752 +        in->err = id;
  32.753 +        report_error(in);
  32.754 +    }
  32.755 +}
  32.756 +
  32.757 +/** Test if the parser's error flag is set.
  32.758 + *
  32.759 + * @param in parser
  32.760 + * @return 1 if set, 0 otherwise
  32.761 + */
  32.762 +int has_error(Parser *in){
  32.763 +    return (in->err > 0);
  32.764 +}
  32.765 +
  32.766 +/** Test if the parser is at end of input.
  32.767 + *
  32.768 + * @param in parser
  32.769 + * @return 1 if at EOF, 0 otherwise
  32.770 + */
  32.771 +int at_eof(Parser *p){
  32.772 +    return p->eof;
  32.773 +}
  32.774 +
  32.775 +#ifdef SXPR_PARSER_MAIN
  32.776 +/* Stuff for standalone testing. */
  32.777 +
  32.778 +#include "file_stream.h"
  32.779 +#include "string_stream.h"
  32.780 +
  32.781 +int stringof(Sxpr exp, char **s){
  32.782 +    int err = 0;
  32.783 +    if(ATOMP(exp)){
  32.784 +        *s = atom_name(exp);
  32.785 +    } else if(STRINGP(exp)){
  32.786 +        *s = string_string(exp);
  32.787 +    } else {
  32.788 +        err = -EINVAL;
  32.789 +        *s = NULL;
  32.790 +    }
  32.791 +    return err;
  32.792 +}
  32.793 +
  32.794 +int child_string(Sxpr exp, Sxpr key, char **s){
  32.795 +    int err = 0;
  32.796 +    Sxpr val = sxpr_child_value(exp, key, ONONE);
  32.797 +    err = stringof(val, s);
  32.798 +    return err;
  32.799 +}
  32.800 +
  32.801 +int intof(Sxpr exp, int *v){
  32.802 +    int err = 0;
  32.803 +    char *s;
  32.804 +    unsigned long l;
  32.805 +    if(INTP(exp)){
  32.806 +        *v = OBJ_INT(exp);
  32.807 +    } else {
  32.808 +        err = stringof(exp, &s);
  32.809 +        if(err) goto exit;
  32.810 +        err = convert_atoul(s, &l);
  32.811 +        *v = (int)l;
  32.812 +    }
  32.813 + exit:
  32.814 +    return err;
  32.815 +}
  32.816 +
  32.817 +int child_int(Sxpr exp, Sxpr key, int *v){
  32.818 +    int err = 0;
  32.819 +    Sxpr val = sxpr_child_value(exp, key, ONONE);
  32.820 +    err = intof(val, v);
  32.821 +    return err;
  32.822 +}
  32.823 +
  32.824 +int eval_vnet(Sxpr exp){
  32.825 +    int err = 0;
  32.826 +    Sxpr oid = intern("id");
  32.827 +    int id;
  32.828 +    err = child_int(exp, oid, &id);
  32.829 +    if(err) goto exit;
  32.830 +    dprintf("> vnet id=%d\n", id);
  32.831 + exit:
  32.832 +    dprintf("< err=%d\n", err);
  32.833 +    return err;
  32.834 +}
  32.835 +
  32.836 +int eval_connect(Sxpr exp){
  32.837 +    int err = 0;
  32.838 +    Sxpr ovif = intern("vif");
  32.839 +    Sxpr ovnet = intern("vnet");
  32.840 +    char *vif;
  32.841 +    int vnet;
  32.842 +
  32.843 +    err = child_string(exp, ovif, &vif);
  32.844 +    if(err) goto exit;
  32.845 +    err = child_int(exp, ovnet, &vnet);
  32.846 +    if(err) goto exit;
  32.847 +    dprintf("> connect vif=%s vnet=%d\n", vif, vnet);
  32.848 + exit:
  32.849 +    dprintf("< err=%d\n", err);
  32.850 +    return err;
  32.851 +}
  32.852 +
  32.853 +int eval(Sxpr exp){
  32.854 +    int err = 0;
  32.855 +    Sxpr oconnect = intern("connect");
  32.856 +    Sxpr ovnet = intern("vnet");
  32.857 +    
  32.858 +    if(sxpr_elementp(exp, ovnet)){
  32.859 +        err = eval_vnet(exp);
  32.860 +    } else if(sxpr_elementp(exp, oconnect)){
  32.861 +        err = eval_connect(exp);
  32.862 +    } else {
  32.863 +        err = -EINVAL;
  32.864 +    }
  32.865 +    return err;
  32.866 +}
  32.867 +
  32.868 +/** Main program for testing.
  32.869 + * Parses input and prints it.
  32.870 + *
  32.871 + * @param argc number of arguments
  32.872 + * @param argv arguments
  32.873 + * @return error code
  32.874 + */
  32.875 +int main(int argc, char *argv[]){
  32.876 +    Parser *pin;
  32.877 +    int err = 0;
  32.878 +    char buf[1024];
  32.879 +    int k;
  32.880 +    Sxpr obj, l, x;
  32.881 +
  32.882 +    pin = Parser_new();
  32.883 +    set_error_stream(pin, iostdout);
  32.884 +    dprintf("> parse...\n");
  32.885 +    while(1){
  32.886 +        k = fread(buf, 1, 1024, stdin);
  32.887 +        err = Parser_input(pin, buf, k);
  32.888 +        dprintf("> Parser_input=%d\n", err);
  32.889 +        if(k <= 0) break;
  32.890 +    }
  32.891 +    obj = pin->val;
  32.892 +    for(l = obj ; CONSP(l); l = CDR(l)){
  32.893 +        x = CAR(l);
  32.894 +        objprint(iostdout, x, 0); printf("\n");
  32.895 +        eval(x);
  32.896 +    }
  32.897 +    dprintf("> err=%d\n", err);
  32.898 +    return 0;
  32.899 +}
  32.900 +#endif
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/tools/lib/sxpr_parser.h	Mon Jun 28 15:03:15 2004 +0000
    33.3 @@ -0,0 +1,125 @@
    33.4 +/*
    33.5 + *
    33.6 + * This library is free software; you can redistribute it and/or modify
    33.7 + * it under the terms of the GNU Lesser General Public License as
    33.8 + * published by the Free Software Foundation; either version 2.1 of the
    33.9 + * License, or  (at your option) any later version. This library is 
   33.10 + * distributed in the  hope that it will be useful, but WITHOUT ANY
   33.11 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or
   33.12 + * FITNESS FOR A PARTICULAR PURPOSE.
   33.13 + * See the GNU Lesser General Public License for more details.
   33.14 + *
   33.15 + * You should have received a copy of the GNU Lesser General Public License
   33.16 + * along with this library; if not, write to the Free Software Foundation,
   33.17 + * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   33.18 + */
   33.19 +
   33.20 +#ifndef _XEN_LIB_SXPR_PARSER_H_
   33.21 +#define _XEN_LIB_SXPR_PARSER_H_
   33.22 +
   33.23 +#include "sxpr.h"
   33.24 +#include "iostream.h"
   33.25 +
   33.26 +/** @file
   33.27 + * Sxpr parsing definitions.
   33.28 + */
   33.29 +
   33.30 +/** Size of a parser input buffer.
   33.31 + * Tokens read must fit into this size (including trailing null).
   33.32 + */
   33.33 +#define PARSER_BUF_SIZE 1024
   33.34 +
   33.35 +struct Parser;
   33.36 +typedef int ParserStateFn(struct Parser *, char c);
   33.37 +
   33.38 +typedef struct ParserState {
   33.39 +    struct ParserState *parent;
   33.40 +    Sxpr val;
   33.41 +    int ival;
   33.42 +    int count;
   33.43 +    char delim;
   33.44 +    ParserStateFn *fn;
   33.45 +} ParserState;
   33.46 +
   33.47 +/** Structure representing an input source for the parser.
   33.48 + * Can read from any IOStream implementation.
   33.49 + */
   33.50 +typedef struct Parser {
   33.51 +    Sxpr val;
   33.52 +    /** Error reporting stream (null for no reports). */
   33.53 +    IOStream *error_out;
   33.54 +    int eof;
   33.55 +    /** Error flag. Non-zero if there has been a read error. */
   33.56 +    int err;
   33.57 +    /** Line number on input (from 1). */
   33.58 +    int line_no;
   33.59 +    /** Column number of input (reset on new line). */
   33.60 +    int char_no;
   33.61 +    /** Lookahead character. */
   33.62 +    char c;
   33.63 +    /** Buffer for reading tokens. */
   33.64 +    char buf[PARSER_BUF_SIZE];
   33.65 +    /** Size of token buffer. */
   33.66 +    int buf_n;
   33.67 +    int buf_i;
   33.68 +    /** Line the last token started on. */
   33.69 +    int tok_begin_line;
   33.70 +    /** Character number the last token started on. */
   33.71 +    int tok_begin_char;
   33.72 +    /** Parsing flags. */
   33.73 +    int flags;
   33.74 +    ParserState *state;
   33.75 +} Parser;
   33.76 +
   33.77 +/** Parser error codes. */
   33.78 +typedef enum {
   33.79 +    PARSE_ERR_NONE=0,
   33.80 +    PARSE_ERR_UNSPECIFIED,
   33.81 +    PARSE_ERR_NOMEM,
   33.82 +    PARSE_ERR_UNEXPECTED_EOF,
   33.83 +    PARSE_ERR_TOKEN_TOO_LONG,
   33.84 +    PARSE_ERR_INVALID_SYNTAX,
   33.85 +    PARSE_ERR_INVALID_ESCAPE,
   33.86 +} ParseErrorId;
   33.87 +
   33.88 +
   33.89 +/** Parser flags. */
   33.90 +//enum {
   33.91 +//};
   33.92 +
   33.93 +/** Raise some parser flags.
   33.94 + *
   33.95 + * @param in parser
   33.96 + * @param flags flags mask
   33.97 + */
   33.98 +inline static void parser_flags_raise(Parser *in, int flags){
   33.99 +    in->flags |= flags;
  33.100 +}
  33.101 +
  33.102 +/** Lower some parser flags.
  33.103 + *
  33.104 + * @param in parser
  33.105 + * @param flags flags mask
  33.106 + */
  33.107 +inline static void parser_flags_lower(Parser *in, int flags){
  33.108 +    in->flags &= ~flags;
  33.109 +}
  33.110 +
  33.111 +/** Clear all parser flags.
  33.112 + *
  33.113 + * @param in parser
  33.114 + */
  33.115 +inline static void parser_flags_clear(Parser *in){
  33.116 +    in->flags = 0;
  33.117 +}
  33.118 +
  33.119 +extern void Parser_free(Parser *z);
  33.120 +extern Parser * Parser_new(void);
  33.121 +extern int Parser_input(Parser *p, char *buf, int buf_n);
  33.122 +extern int Parser_input_eof(Parser *p);
  33.123 +
  33.124 +extern int parse_error_message(Parser *in, char *buf, int n);
  33.125 +extern int has_error(Parser *in);
  33.126 +extern int at_eof(Parser *in);
  33.127 +
  33.128 +#endif /* ! _XEN_LIB_SXPR_PARSER_H_ */
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/tools/lib/sys_ctype.h	Mon Jun 28 15:03:15 2004 +0000
    34.3 @@ -0,0 +1,12 @@
    34.4 +#ifndef _XENO_SYS_CTYPE_H_
    34.5 +#define _XENO_SYS_CTYPE_H_
    34.6 +/** @file
    34.7 + ** Replacement for ctype include that can be used
    34.8 + * from user or kernel code.
    34.9 + */
   34.10 +#ifdef __KERNEL__
   34.11 +#  include <linux/ctype.h>
   34.12 +#else
   34.13 +#  include <ctype.h>
   34.14 +#endif
   34.15 +#endif /* ! _XENO_SYS_CTYPE_H_ */
    35.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.2 +++ b/tools/lib/sys_net.c	Mon Jun 28 15:03:15 2004 +0000
    35.3 @@ -0,0 +1,309 @@
    35.4 +/*
    35.5 + * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
    35.6 + *
    35.7 + * This library is free software; you can redistribute it and/or modify
    35.8 + * it under the terms of the GNU Lesser General Public License as
    35.9 + * published by the Free Software Foundation; either version 2.1 of the
   35.10 + * License, or  (at your option) any later version. This library is 
   35.11 + * distributed in the  hope that it will be useful, but WITHOUT ANY
   35.12 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or
   35.13 + * FITNESS FOR A PARTICULAR PURPOSE.
   35.14 + * See the GNU Lesser General Public License for more details.
   35.15 + *
   35.16 + * You should have received a copy of the GNU Lesser General Public License
   35.17 + * along with this library; if not, write to the Free Software Foundation,
   35.18 + * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   35.19 + */
   35.20 +
   35.21 +#include "sys_net.h"
   35.22 +#include "sys_string.h"
   35.23 +
   35.24 +/** @file
   35.25 + * All network data are kept in network order and only converted to
   35.26 + * host order for display. Network data includes IP addresses, port numbers and
   35.27 + * network masks.
   35.28 + */
   35.29 +
   35.30 +/** Maximum value for a port. */
   35.31 +#define PORT_MAX 0xffff
   35.32 +
   35.33 +/** Convert a number of bits to a network mask
   35.34 + * for IP addresses. The number of bits must
   35.35 + * be in the range 1-31.
   35.36 + *
   35.37 + * @param n number of bits to set in the mask
   35.38 + * @return value with n high bits set (in network order)
   35.39 + */
   35.40 +unsigned long bits_to_mask(int n){
   35.41 +    unsigned long mask = (n ? (1 << 31) : 0);
   35.42 +    int i;
   35.43 +    for(i=1; i<n; i++){
   35.44 +        mask |= (mask >> 1);
   35.45 +    }
   35.46 +    return htonl(mask);
   35.47 +}
   35.48 +
   35.49 +/** Convert a network mask to a number of bits.
   35.50 + *
   35.51 + * @param mask network mask in network order
   35.52 + * @return number of bits in mask
   35.53 + */
   35.54 +int mask_to_bits(unsigned long mask){
   35.55 +    // Start with n set to the number of bits in the mask. Then reduce n by
   35.56 +    // the number of low zero bits in the mask.
   35.57 +    int n = 32;
   35.58 +    for(mask = ntohl(mask);
   35.59 +        (mask & 1)==0 && n>0;
   35.60 +        mask >>= 1){
   35.61 +        n--;
   35.62 +    }
   35.63 +    return n;
   35.64 +}
   35.65 +
   35.66 +/** Get the index of the first occurrence of a character in a string.
   35.67 + * Stops at end of string or after n characters.
   35.68 + *
   35.69 + * @param s input string
   35.70 + * @param n maximum number of charactes to search
   35.71 + * @param c character to look for
   35.72 + * @return index of first occurrence, -1 if not found
   35.73 + */
   35.74 +inline static int indexof(const char *s, int n, char c){
   35.75 +    int i;
   35.76 +    for(i=0; i<n && *s; i++, s++){
   35.77 +        if(*s == c) return i;
   35.78 +    }
   35.79 +    return -1;
   35.80 +}
   35.81 +
   35.82 +/** Convert an IPv4 address in dot notation into an unsigned long (in network order).
   35.83 + *
   35.84 + * @param s input string
   35.85 + * @param address where to put the address
   35.86 + * @return 0 on success, -1 on error
   35.87 + */
   35.88 +int get_inet_addr(const char *s, unsigned long *address){
   35.89 +    // Number of bits in a byte.
   35.90 +    const int BYTE_BITS = 8;
   35.91 +    // Number of bytes in a word.
   35.92 +    const int WORD_BYTES = 4;
   35.93 +    // Max value for a component of an address.
   35.94 +    const int ADDR_MAX  = 255;
   35.95 +    // Separator for components of an address.
   35.96 +    const char dot = '.';
   35.97 +
   35.98 +    int n;
   35.99 +    unsigned long addr = 0;
  35.100 +    unsigned long v;
  35.101 +    int i;
  35.102 +    int err = -1;
  35.103 +    // Bit shift for the current byte.
  35.104 +    int shift = BYTE_BITS * (WORD_BYTES - 1);
  35.105 +    char buf[64];
  35.106 +
  35.107 +    n = strlen(s);
  35.108 +    if(n >= sizeof(buf)){
  35.109 +        goto exit;
  35.110 +    }
  35.111 +    for(i=0; i < WORD_BYTES; i++){
  35.112 +        int idx = indexof(s, n, dot);
  35.113 +        idx = (idx < 0 ? strlen(s) : idx);
  35.114 +        strncpy(buf, s, idx); buf[idx]='\0';
  35.115 +        if(convert_atoul(buf, &v)){
  35.116 +            goto exit;
  35.117 +        }
  35.118 +        if(v < 0 || v > ADDR_MAX){
  35.119 +            goto exit;
  35.120 +        }
  35.121 +        addr |= (v << shift);
  35.122 +        if(idx == n) break;
  35.123 +        shift -= BYTE_BITS;
  35.124 +        s += idx+1;
  35.125 +    }
  35.126 +    err = 0;
  35.127 +  exit:
  35.128 +    addr = htonl(addr);
  35.129 +    *address = (err ? 0 : addr);
  35.130 +    return err;
  35.131 +}
  35.132 +
  35.133 +#ifdef __KERNEL__
  35.134 +/** Convert an address in network order to IPv4 dot notation.
  35.135 + * The return value is a static buffer which is overwritten on each call.
  35.136 + *
  35.137 + * @param inaddr address (in network order)
  35.138 + * @return address in dot notation
  35.139 + */
  35.140 +char *inet_ntoa(struct in_addr inaddr){
  35.141 +    static char address[16] = {};
  35.142 +    uint32_t addr = ntohl(inaddr.s_addr);
  35.143 +    snprintf(address, sizeof(address), "%d.%d.%d.%d",
  35.144 +            (unsigned)((addr >> 24) & 0xff),
  35.145 +            (unsigned)((addr >> 16) & 0xff),
  35.146 +            (unsigned)((addr >>  8) & 0xff),
  35.147 +            (unsigned)((addr      ) & 0xff));
  35.148 +    return address;
  35.149 +}
  35.150 +
  35.151 +
  35.152 +/** Convert a string in IPv4 dot notation to an int in network order.
  35.153 + *
  35.154 + * @param address address in dot notation
  35.155 + * @param inp result of conversion (in network order)
  35.156 + * @return 0 on success, error code on error
  35.157 + */
  35.158 +int inet_aton(const char *address, struct in_addr *inp){
  35.159 +    int err = 0; 
  35.160 +    unsigned long addr;
  35.161 +    
  35.162 +    err = get_inet_addr(address, &addr);
  35.163 +    if(err) goto exit;
  35.164 +    inp->s_addr = addr;
  35.165 +  exit:
  35.166 +    return err;
  35.167 +}
  35.168 +#endif
  35.169 +
  35.170 +/** Convert a hostname or IPv4 address string to an address in network order.
  35.171 + *
  35.172 + * @param name input hostname or address string
  35.173 + * @param address where to put the address
  35.174 + * @return 1 if address found OK, 0 otherwise
  35.175 + */
  35.176 +int get_host_address(const char *name, unsigned long *address){
  35.177 +#ifdef __KERNEL__
  35.178 +    return get_inet_addr(name, address) == 0;
  35.179 +#else
  35.180 +    struct hostent *host = gethostbyname(name);
  35.181 +    if(!host){
  35.182 +        return 0;
  35.183 +    }
  35.184 +    *address = ((struct in_addr *)(host->h_addr))->s_addr;
  35.185 +    return 1;
  35.186 +#endif
  35.187 +}
  35.188 +
  35.189 +/** Convert a service name to a port (in network order).
  35.190 + *
  35.191 + * @param name service name
  35.192 + * @param port where to put the port
  35.193 + * @return 1 if service port found OK, 0 otherwise
  35.194 + */
  35.195 +int get_service_port(const char *name, unsigned long *port){
  35.196 +#ifdef __KERNEL__
  35.197 +    return 0;
  35.198 +#else
  35.199 +    struct servent *service;
  35.200 +    service = getservbyname(name, 0);
  35.201 +    if(!service){
  35.202 +        return 0;
  35.203 +    }
  35.204 +    *port = service->s_port;
  35.205 +    return 1;
  35.206 +#endif
  35.207 +}
  35.208 +
  35.209 +/** Convert a port number (in network order) to a service name.
  35.210 + *
  35.211 + * @param port the port number
  35.212 + * @return service name if found OK, 0 otherwise
  35.213 + */
  35.214 +char *get_port_service(unsigned long port){
  35.215 +#ifdef __KERNEL__
  35.216 +    return 0;
  35.217 +#else
  35.218 +    struct servent *service = getservbyport(port, 0);
  35.219 +    return (service ? service->s_name : 0);
  35.220 +#endif
  35.221 +}
  35.222 +
  35.223 +/** Convert a decimal integer or service name to a port (in network order).
  35.224 + *
  35.225 + * @param s input to convert
  35.226 + * @param port where to put the port
  35.227 + * @return 1 if port found OK, 0 otherwise
  35.228 + */
  35.229 +int convert_service_to_port(const char *s, unsigned long *port){
  35.230 +    int ok = 0;
  35.231 +    unsigned long value;
  35.232 +    if(convert_atoul(s, &value)){
  35.233 +        ok = get_service_port(s, &value);
  35.234 +    } else {
  35.235 +        ok = (0 <= value) && (value <= PORT_MAX);
  35.236 +        value = htons((unsigned short)value);
  35.237 +    }
  35.238 +    *port = (ok ? value : 0);
  35.239 +    return ok;
  35.240 +}
  35.241 +
  35.242 +#define MAC_ELEMENT_N  6 // Number of elements in a MAC address.
  35.243 +#define MAC_DIGIT_N    2 // Number of digits in an element in a MAC address.
  35.244 +#define MAC_LENGTH    17 //((MAC_ELEMENT_N * MAC_DIGIT_N) + MAC_ELEMENT_N - 1)
  35.245 +
  35.246 +/** Convert a mac address from a string of the form
  35.247 + * XX:XX:XX:XX:XX:XX to numerical form (an array of 6 unsigned chars).
  35.248 + * Each X denotes a hex digit: 0..9, a..f, A..F.
  35.249 + * Also supports using '-' as the separator instead of ':'.
  35.250 + *
  35.251 + * @param mac_in string to convert
  35.252 + * @param mac destination for the value
  35.253 + * @return 0 on success, -1 on error
  35.254 + */
  35.255 +int mac_aton(const char *mac_in, unsigned char *mac){
  35.256 +    int err = 0;
  35.257 +    int i, j;
  35.258 +    const char *p;
  35.259 +    char sep = 0;
  35.260 +    unsigned char d;
  35.261 +    if(!mac_in || strlen(mac_in) != MAC_LENGTH){
  35.262 +        err = -1;
  35.263 +        goto exit;
  35.264 +    }
  35.265 +    for(i = 0, p = mac_in; i < MAC_ELEMENT_N; i++){
  35.266 +        d = 0;
  35.267 +        if(i){
  35.268 +            if(!sep){
  35.269 +                if(*p == ':' || *p == '-') sep = *p;
  35.270 +            }
  35.271 +            if(sep && *p == sep){
  35.272 +                p++;
  35.273 +            } else {
  35.274 +                err = -1;
  35.275 +                goto exit;
  35.276 +            }
  35.277 +        }
  35.278 +        for(j = 0; j < MAC_DIGIT_N; j++, p++){
  35.279 +            if(j) d <<= 4;
  35.280 +            if(*p >= '0' && *p <= '9'){
  35.281 +                d += (*p - '0');
  35.282 +            } else if(*p >= 'A' && *p <= 'F'){
  35.283 +                d += (*p - 'A') + 10;
  35.284 +            } else if(*p >= 'a' && *p <= 'f'){
  35.285 +                d += (*p - 'a') + 10;
  35.286 +            } else {
  35.287 +                err = -1;
  35.288 +                goto exit;
  35.289 +            }
  35.290 +        }
  35.291 +        mac[i] = d;
  35.292 +    }
  35.293 +  exit:
  35.294 +    return err;
  35.295 +}
  35.296 +
  35.297 +/** Convert a MAC address from numerical form to a string.
  35.298 + *
  35.299 + * @param mac address to convert
  35.300 + * @return static string value
  35.301 + */
  35.302 +char *mac_ntoa(const unsigned char *mac){
  35.303 +    static char buf[MAC_LENGTH + 1];
  35.304 +    int buf_n = sizeof(buf);
  35.305 +
  35.306 +    memset(buf, buf_n, 0);
  35.307 +    snprintf(buf, buf_n, "%02x:%02x:%02x:%02x:%02x:%02x",
  35.308 +             mac[0], mac[1], mac[2],
  35.309 +             mac[3], mac[4], mac[5]);
  35.310 +    buf[buf_n - 1] = '\0';
  35.311 +    return buf;
  35.312 +}
    36.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    36.2 +++ b/tools/lib/sys_net.h	Mon Jun 28 15:03:15 2004 +0000
    36.3 @@ -0,0 +1,78 @@
    36.4 +/*
    36.5 + * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
    36.6 + *
    36.7 + * This library is free software; you can redistribute it and/or modify
    36.8 + * it under the terms of the GNU Lesser General Public License as published by
    36.9 + * the Free Software Foundation; either version 2.1 of the License, or
   36.10 + * (at your option) any later version.
   36.11 + *
   36.12 + * This library is distributed in the hope that it will be useful,
   36.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   36.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   36.15 + * GNU Lesser General Public License for more details.
   36.16 + *
   36.17 + * You should have received a copy of the GNU Lesser General Public License
   36.18 + * along with this library; if not, write to the Free Software
   36.19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   36.20 + */
   36.21 +
   36.22 +#ifndef _XEN_LIB_SYS_NET_H_
   36.23 +#define _XEN_LIB_SYS_NET_H_
   36.24 +/** @file
   36.25 + *
   36.26 + * Replacement for standard network includes.
   36.27 + * Works in user or kernel code.
   36.28 + */
   36.29 +
   36.30 +extern int get_inet_addr(const char *s, unsigned long *address);
   36.31 +extern unsigned long bits_to_mask(int n);
   36.32 +extern int mask_to_bits(unsigned long mask);
   36.33 +extern int get_host_address(const char *name, unsigned long *address);
   36.34 +extern int get_service_port(const char *name, unsigned long *port);
   36.35 +extern char *get_port_service(unsigned long port);
   36.36 +extern int convert_service_to_port(const char *s, unsigned long *port);
   36.37 +
   36.38 +#ifdef __KERNEL__
   36.39 +#include <linux/kernel.h>
   36.40 +#include <linux/types.h>
   36.41 +#include <linux/errno.h>
   36.42 +#include <linux/slab.h>
   36.43 +#include <asm/byteorder.h> 
   36.44 +
   36.45 +#ifndef htonl
   36.46 +#define htonl(x) __constant_htonl(x)
   36.47 +#endif
   36.48 +
   36.49 +#ifndef ntohl
   36.50 +#define ntohl(x) __constant_ntohl(x)
   36.51 +#endif
   36.52 +
   36.53 +#ifndef htons
   36.54 +#define htons(x) __constant_htons(x)
   36.55 +#endif
   36.56 +
   36.57 +#ifndef ntohs
   36.58 +#define ntohs(x) __constant_ntohs(x)
   36.59 +#endif
   36.60 +
   36.61 +#include <linux/in.h>
   36.62 +extern char *inet_ntoa(struct in_addr inaddr);
   36.63 +extern int inet_aton(const char *address, struct in_addr *inp);
   36.64 +
   36.65 +#else
   36.66 +
   36.67 +#include <limits.h>
   36.68 +#include <sys/socket.h>
   36.69 +#include <netinet/in.h>
   36.70 +#include <netdb.h>
   36.71 +#include <arpa/inet.h>
   36.72 +
   36.73 +#endif
   36.74 +
   36.75 +extern char *mac_ntoa(const unsigned char *macaddr);
   36.76 +extern int mac_aton(const char *addr, unsigned char *macaddr);
   36.77 +
   36.78 +#endif /* !_SP_SYS_NET_H_ */
   36.79 +
   36.80 +
   36.81 +
    37.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    37.2 +++ b/tools/lib/sys_string.c	Mon Jun 28 15:03:15 2004 +0000
    37.3 @@ -0,0 +1,138 @@
    37.4 +/*
    37.5 + * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
    37.6 + *
    37.7 + * This library is free software; you can redistribute it and/or modify
    37.8 + * it under the terms of the GNU Lesser General Public License as published by
    37.9 + * the Free Software Foundation; either version 2.1 of the License, or
   37.10 + * (at your option) any later version.
   37.11 + *
   37.12 + * This library is distributed in the hope that it will be useful,
   37.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   37.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   37.15 + * GNU Lesser General Public License for more details.
   37.16 + *
   37.17 + * You should have received a copy of the GNU Lesser General Public License
   37.18 + * along with this library; if not, write to the Free Software
   37.19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   37.20 + */
   37.21 +
   37.22 +#ifdef __KERNEL__
   37.23 +#  include <linux/config.h>
   37.24 +#  include <linux/module.h>
   37.25 +#  include <linux/kernel.h>
   37.26 +#  include <linux/errno.h>
   37.27 +#else
   37.28 +#  include <errno.h>
   37.29 +#endif
   37.30 +
   37.31 +#include "allocate.h"
   37.32 +#include "sys_string.h"
   37.33 +
   37.34 +/** Set the base to use for converting a string to a number.  Base is
   37.35 + * hex if starts with 0x, otherwise decimal.
   37.36 + *
   37.37 + * @param s input string
   37.38 + * @param base where to put the base
   37.39 + * @return rest of s to parse as a number
   37.40 + */
   37.41 +inline static const char * convert_set_base(const char *s, int *base){
   37.42 +    *base = 10;
   37.43 +    if(s){
   37.44 +        if(*s=='0'){
   37.45 +            s++;
   37.46 +            if(*s=='x' || *s=='X'){
   37.47 +                *base = 16;
   37.48 +                s++;
   37.49 +            }
   37.50 +        }
   37.51 +    }
   37.52 +    return s;
   37.53 +}
   37.54 +
   37.55 +/** Get the numerical value of a digit in the given base.
   37.56 + *
   37.57 + * @param c digit character
   37.58 + * @param base to use
   37.59 + * @return numerical value of digit in range 0..base-1 or
   37.60 + * -1 if not in range for the base
   37.61 + */
   37.62 +inline static int convert_get_digit(char c, int base){
   37.63 +    int d;
   37.64 +
   37.65 +    if('0'<=c  && c<='9'){
   37.66 +        d = c - '0';
   37.67 +    } else if('a'<=c && c<='f'){
   37.68 +        d = c - 'a' + 10;
   37.69 +    } else if('A'<=c && c<='F'){
   37.70 +        d = c - 'A' + 10;
   37.71 +    } else {
   37.72 +        d = -1;
   37.73 +    }
   37.74 +    return (d < base ? d : -1);
   37.75 +}
   37.76 +
   37.77 +/** Convert a string to an unsigned long by parsing it as a number.
   37.78 + * Will accept hex or decimal in usual C syntax.
   37.79 + *
   37.80 + * @param str input string
   37.81 + * @param val where to put the result
   37.82 + * @return 0 if converted OK, negative otherwise
   37.83 + */
   37.84 +int convert_atoul(const char *str, unsigned long *val){
   37.85 +    int err = 0;
   37.86 +    unsigned long v = 0;
   37.87 +    int base;
   37.88 +    const char *s = str;
   37.89 +
   37.90 +    if(!s) {
   37.91 +        err = -EINVAL;
   37.92 +        goto exit;
   37.93 +    }
   37.94 +    s = convert_set_base(s, &base);
   37.95 +    for( ; !err && *s; s++){
   37.96 +        int digit = convert_get_digit(*s, base);
   37.97 +        if(digit<0){
   37.98 +            err = -EINVAL;
   37.99 +            goto exit;
  37.100 +        }
  37.101 +        v *= base;
  37.102 +        v += digit;
  37.103 +    } 
  37.104 +  exit:
  37.105 +    *val = (err ? 0 : v);
  37.106 +    return err;
  37.107 +}
  37.108 +
  37.109 +/** Combine a directory path with a relative path to produce
  37.110 + * a new path.
  37.111 + *
  37.112 + * @param s directory path
  37.113 + * @param t relative path
  37.114 + * @return new combined path s/t
  37.115 + */
  37.116 +int path_concat(char *s, char *t, char **val){
  37.117 +    int err = 0;
  37.118 +    int sn, tn, vn;
  37.119 +    char *v;
  37.120 +    sn = strlen(s);
  37.121 +    if(sn > 0 && s[sn-1] == '/'){
  37.122 +        sn--;
  37.123 +    }
  37.124 +    tn = strlen(t);
  37.125 +    if(tn > 0 && t[0] == '/'){
  37.126 +        tn--;
  37.127 +    }
  37.128 +    vn = sn+tn+1;
  37.129 +    v = (char*)allocate(vn+1);
  37.130 +    if(!v){
  37.131 +        err = -ENOMEM;
  37.132 +        goto exit;
  37.133 +    }
  37.134 +    strncpy(v, s, sn);
  37.135 +    v[sn] = '/';
  37.136 +    strncpy(v+sn+1, t, tn);
  37.137 +    v[vn] = '\0';
  37.138 +  exit:
  37.139 +    *val = (err ? NULL : v);
  37.140 +    return err;    
  37.141 +}
    38.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    38.2 +++ b/tools/lib/sys_string.h	Mon Jun 28 15:03:15 2004 +0000
    38.3 @@ -0,0 +1,91 @@
    38.4 +/*
    38.5 + * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
    38.6 + *
    38.7 + * This library is free software; you can redistribute it and/or modify
    38.8 + * it under the terms of the GNU Lesser General Public License as published by
    38.9 + * the Free Software Foundation; either version 2.1 of the License, or
   38.10 + * (at your option) any later version.
   38.11 + *
   38.12 + * This library is distributed in the hope that it will be useful,
   38.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   38.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   38.15 + * GNU Lesser General Public License for more details.
   38.16 + *
   38.17 + * You should have received a copy of the GNU Lesser General Public License
   38.18 + * along with this library; if not, write to the Free Software
   38.19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   38.20 + */
   38.21 +
   38.22 +#ifndef _XEN_LIB_SYS_STRING_H_
   38.23 +#define _XEN_LIB_SYS_STRING_H_
   38.24 +/** @file
   38.25 + * Replacement for standard string includes.
   38.26 + * Works in user or kernel code.
   38.27 + */
   38.28 +/*============================================================================*/
   38.29 +#ifdef __KERNEL__
   38.30 +
   38.31 +#include <linux/config.h>
   38.32 +#include <linux/kernel.h>
   38.33 +#include <linux/string.h>
   38.34 +#include <linux/types.h>
   38.35 +#include <stdarg.h>
   38.36 +#include "allocate.h"
   38.37 +
   38.38 +#if 0
   38.39 +static inline int tolower(int c){
   38.40 +    return (c>='A' && c<='Z' ? (c-'A')+'a' : c);
   38.41 +}
   38.42 +#endif
   38.43 +
   38.44 +static inline int isalpha(int c){
   38.45 +    return (c>='A' && c<='Z') || (c>='a' && c<='z');
   38.46 +}
   38.47 +
   38.48 +static inline int isdigit(int c){
   38.49 +   return (c>='0' && c<='9');
   38.50 +}
   38.51 +
   38.52 +#if 0
   38.53 +static inline int strcasecmp(const char *s1, const char *s2){
   38.54 +	int c1, c2;
   38.55 +
   38.56 +	do {
   38.57 +		c1 = tolower(*s1++);
   38.58 +		c2 = tolower(*s2++);
   38.59 +	} while (c1 && c1 == c2);
   38.60 +	return c1 - c2;
   38.61 +}
   38.62 +#endif
   38.63 +
   38.64 +static inline char * strdup(const char *s){
   38.65 +    int n = (s ? 1+strlen(s) : 0);
   38.66 +    char *copy = (n ? allocate(n) : NULL);
   38.67 +    if(copy){
   38.68 +        strcpy(copy, s);
   38.69 +    }
   38.70 +    return copy;
   38.71 +}
   38.72 +
   38.73 +/*============================================================================*/
   38.74 +#else
   38.75 +#include <string.h>
   38.76 +#include <stdio.h>
   38.77 +
   38.78 +#ifndef _GNU_SOURCE
   38.79 +static inline size_t strnlen(const char *s, size_t n){
   38.80 +    int k = 0;
   38.81 +    if(s){
   38.82 +	for(k=0; *s && k<n; s++, k++){}
   38.83 +    }
   38.84 +    return k;
   38.85 +}
   38.86 +#endif
   38.87 +
   38.88 +#endif
   38.89 +/*============================================================================*/
   38.90 +
   38.91 +extern int convert_atoul(const char *s, unsigned long *v);
   38.92 +extern int path_concat(char *s, char *t, char **val);
   38.93 +
   38.94 +#endif /* !_XEN_LIB_SYS_STRING_H_ */
    39.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    39.2 +++ b/tools/lib/xdr.c	Mon Jun 28 15:03:15 2004 +0000
    39.3 @@ -0,0 +1,246 @@
    39.4 +/* $Id: xdr.c,v 1.3 2003/09/29 13:40:00 mjw Exp $ */
    39.5 +#include "xdr.h"
    39.6 +#include <errno.h>
    39.7 +/** @file
    39.8 + * XDR packer/unpacker for elements.
    39.9 + *
   39.10 + * string -> [T_STRING] [len:u32] <len bytes>
   39.11 + * atom   -> [T_ATOM]   [len:u32] <len bytes>
   39.12 + * uint   -> [T_UINT]   [value]
   39.13 + * cons   -> [T_CONS]   <car> <cdr>
   39.14 + * null   -> [T_NULL]
   39.15 + * none   -> [T_NONE]
   39.16 + * bool   -> [T_BOOL]   { 0:u8 | 1:u8 }
   39.17 + *
   39.18 + * types packed as u16.
   39.19 + *
   39.20 + * So (a b c) -> [T_CONS] a [T_CONS] b [T_CONS] c [T_NULL]
   39.21 + *    ()      -> [T_NULL]
   39.22 + */
   39.23 +
   39.24 +int pack_bool(IOStream *io, int x){
   39.25 +    int err=0;
   39.26 +    err = IOStream_print(io, "%c", 0xff & x);
   39.27 +    if(err > 0) err = 0;
   39.28 +    return err;
   39.29 +}
   39.30 +
   39.31 +int unpack_bool(IOStream *io, int *x){
   39.32 +    int err = 0;
   39.33 +    int c;
   39.34 +    c = IOStream_getc(io);
   39.35 +    *x = (c < 0 ? 0 : c);
   39.36 +    err = IOStream_error(io);
   39.37 +    if(c < 0 && !err) err = -EIO;
   39.38 +    return err;
   39.39 +}
   39.40 +
   39.41 +int pack_ushort(IOStream *io, unsigned short x){
   39.42 +    int err=0;
   39.43 +    err = IOStream_print(io, "%c%c",
   39.44 +                         0xff & (x >>  8),
   39.45 +                         0xff & (x      ));
   39.46 +    if(err > 0) err = 0;
   39.47 +    return err;
   39.48 +}
   39.49 +
   39.50 +int unpack_ushort(IOStream *io, unsigned short *x){
   39.51 +    int err = 0;
   39.52 +    int i, c = 0;
   39.53 +    *x = 0;
   39.54 +    for(i = 0; i< 2; i++){
   39.55 +        c = IOStream_getc(io);
   39.56 +        if(c < 0) break;
   39.57 +        *x <<= 8;
   39.58 +        *x |= (0xff & c);
   39.59 +    }
   39.60 +    err = IOStream_error(io);
   39.61 +    if(c < 0 && !err) err = -EIO;
   39.62 +    return err;
   39.63 +}
   39.64 +
   39.65 +int pack_uint(IOStream *io, unsigned int x){
   39.66 +    int err=0;
   39.67 +    err = IOStream_print(io, "%c%c%c%c",
   39.68 +                         0xff & (x >> 24),
   39.69 +                         0xff & (x >> 16),
   39.70 +                         0xff & (x >>  8),
   39.71 +                         0xff & (x      ));
   39.72 +    if(err > 0) err = 0;
   39.73 +    return err;
   39.74 +}
   39.75 +
   39.76 +int unpack_uint(IOStream *io, unsigned int *x){
   39.77 +    int err = 0;
   39.78 +    int i, c = 0;
   39.79 +    *x = 0;
   39.80 +    for(i = 0; i< 4; i++){
   39.81 +        c = IOStream_getc(io);
   39.82 +        if(c < 0) break;
   39.83 +        *x <<= 8;
   39.84 +        *x |= (0xff & c);
   39.85 +    }
   39.86 +    err = IOStream_error(io);
   39.87 +    if(c < 0 && !err) err = -EIO;
   39.88 +    return err;
   39.89 +}
   39.90 +
   39.91 +int pack_string(IOStream *io, Sxpr x){
   39.92 +    int err = 0;
   39.93 +    int n = string_length(x);
   39.94 +    char *s = string_string(x);
   39.95 +    int i;
   39.96 +    err = pack_uint(io, n);
   39.97 +    if(err) goto exit;
   39.98 +    for(i = 0; i < n; i++){
   39.99 +        err = IOStream_print(io, "%c", s[i]);
  39.100 +        if(err < 0) break;
  39.101 +    }
  39.102 +    if(err > 0) err = 0;
  39.103 +  exit:
  39.104 +    return err;
  39.105 +}
  39.106 +
  39.107 +int unpack_string(IOStream *io, Sxpr *x){
  39.108 +    int err;
  39.109 +    unsigned int n;
  39.110 +    int i, c = 0;
  39.111 +    char *s;
  39.112 +    Sxpr val = ONONE;
  39.113 +    
  39.114 +    err = unpack_uint(io, &n);
  39.115 +    if(err) goto exit;
  39.116 +    val = halloc(n+1, T_STRING);
  39.117 +    if(NOMEMP(val)){
  39.118 +        err = -ENOMEM;
  39.119 +        goto exit;
  39.120 +    }
  39.121 +    s = string_string(val);
  39.122 +    for(i=0; i<n; i++){
  39.123 +        c = IOStream_getc(io);
  39.124 +        if(c < 0) break;
  39.125 +        s[i] = (char)c;
  39.126 +    }
  39.127 +    s[n] = '\0';
  39.128 +  exit:
  39.129 +    err = IOStream_error(io);
  39.130 +    if(c < 0 && !err) err = -EIO;
  39.131 +    if(err){
  39.132 +        objfree(val);
  39.133 +        val = ONONE;
  39.134 +    }
  39.135 +    *x = val;
  39.136 +    return err;
  39.137 +}
  39.138 +
  39.139 +int pack_cons(IOStream *io, Sxpr x){
  39.140 +    int err = 0;
  39.141 +    err = pack_sxpr(io, CAR(x));
  39.142 +    if(err) goto exit;
  39.143 +    err = pack_sxpr(io, CDR(x));
  39.144 +  exit:
  39.145 +    return err;
  39.146 +}
  39.147 +
  39.148 +int unpack_cons(IOStream *io, Sxpr *x){
  39.149 +    int err = 0;
  39.150 +    Sxpr u = ONONE, v = ONONE, val = ONONE;
  39.151 +    err = unpack_sxpr(io, &u);
  39.152 +    if(err) goto exit;
  39.153 +    err = unpack_sxpr(io, &v);
  39.154 +    if(err) goto exit;
  39.155 +    val = cons_new(u, v);
  39.156 +    if(NOMEMP(val)){
  39.157 +        err = -ENOMEM;
  39.158 +    }
  39.159 +  exit:
  39.160 +    if(err){
  39.161 +        objfree(u);
  39.162 +        objfree(v);
  39.163 +        val = ONONE;
  39.164 +    }        
  39.165 +    *x = val;
  39.166 +    return err;
  39.167 +}
  39.168 +
  39.169 +int pack_sxpr(IOStream *io, Sxpr x){
  39.170 +    int err = 0;
  39.171 +    unsigned short type = get_type(x);
  39.172 +    err = pack_ushort(io, type);
  39.173 +    if(err) goto exit;
  39.174 +    switch(type){
  39.175 +    case T_NULL:
  39.176 +        break;
  39.177 +    case T_NONE:
  39.178 +        break;
  39.179 +        break;
  39.180 +    case T_BOOL:
  39.181 +        err = pack_bool(io, get_ul(x));
  39.182 +        break;
  39.183 +    case T_CONS:
  39.184 +        err = pack_cons(io, x);
  39.185 +        break;
  39.186 +    case T_ATOM:
  39.187 +        err = pack_string(io, OBJ_ATOM(x)->name);
  39.188 +        break;
  39.189 +    case T_STRING:
  39.190 +        err = pack_string(io, x);
  39.191 +        break;
  39.192 +    case T_UINT:
  39.193 +        err = pack_uint(io, get_ul(x));
  39.194 +        break;
  39.195 +    default:
  39.196 +        err = -EINVAL;
  39.197 +        IOStream_print(iostderr, "%s> invalid type %d\n", __FUNCTION__, type);
  39.198 +        break;
  39.199 +    }
  39.200 +  exit:
  39.201 +    return err;
  39.202 +}
  39.203 +
  39.204 +int unpack_sxpr(IOStream *io, Sxpr *x){
  39.205 +    int err = 0;
  39.206 +    unsigned short type;
  39.207 +    unsigned int u;
  39.208 +    Sxpr val = ONONE, y;
  39.209 +
  39.210 +    err = unpack_ushort(io, &type);
  39.211 +    if(err) goto exit;
  39.212 +    switch(type){
  39.213 +    case T_NULL:
  39.214 +        val = ONULL;
  39.215 +        break;
  39.216 +    case T_NONE:
  39.217 +        val = ONONE;
  39.218 +        break;
  39.219 +    case T_CONS:
  39.220 +        err = unpack_cons(io, &val);
  39.221 +        break;
  39.222 +    case T_BOOL:
  39.223 +        err = unpack_bool(io, &u);
  39.224 +        if(err) goto exit;
  39.225 +        val = (u ? OTRUE : OFALSE);
  39.226 +        break;
  39.227 +    case T_ATOM:
  39.228 +        err = unpack_string(io, &y);
  39.229 +        if(err) goto exit;
  39.230 +        val = intern(string_string(y));
  39.231 +        objfree(y);
  39.232 +        break;
  39.233 +    case T_STRING:
  39.234 +        err = unpack_string(io, &val);
  39.235 +        break;
  39.236 +    case T_UINT:
  39.237 +        err = unpack_uint(io, &u);
  39.238 +        if(err) goto exit;
  39.239 +        val = OBJI(type, u);
  39.240 +        break;
  39.241 +    default:
  39.242 +        err = -EINVAL;
  39.243 +        IOStream_print(iostderr, "%s> invalid type %d\n", __FUNCTION__, type);
  39.244 +        break;
  39.245 +    }
  39.246 +  exit:
  39.247 +    *x = (err ? ONONE : val);
  39.248 +    return err;
  39.249 +}
    40.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.2 +++ b/tools/lib/xdr.h	Mon Jun 28 15:03:15 2004 +0000
    40.3 @@ -0,0 +1,14 @@
    40.4 +/* $Id: xdr.h,v 1.2 2003/09/29 13:40:00 mjw Exp $ */
    40.5 +#ifndef _SP_XDR_H_
    40.6 +#define _SP_XDR_H_
    40.7 +#include "iostream.h"
    40.8 +#include "sxpr.h"
    40.9 +int pack_uint(IOStream *out, unsigned int x);
   40.10 +int unpack_uint(IOStream *in, unsigned int *x);
   40.11 +int pack_string(IOStream *out, Sxpr x);
   40.12 +int unpack_string(IOStream *in, Sxpr *x);
   40.13 +int pack_cons(IOStream *out, Sxpr x);
   40.14 +int unpack_cons(IOStream *in, Sxpr *x);
   40.15 +int pack_sxpr(IOStream *out, Sxpr x);
   40.16 +int unpack_sxpr(IOStream *in, Sxpr *x);
   40.17 +#endif /* _SP_XDR_H_ */
    41.1 --- a/tools/xc/lib/Makefile	Mon Jun 28 08:17:15 2004 +0000
    41.2 +++ b/tools/xc/lib/Makefile	Mon Jun 28 15:03:15 2004 +0000
    41.3 @@ -4,13 +4,71 @@ MINOR    = 0
    41.4  SONAME   = libxc.so.$(MAJOR)
    41.5  
    41.6  CC       = gcc
    41.7 -CFLAGS   = -c -Werror -O3 -fno-strict-aliasing
    41.8 -CFLAGS  += -I../../../xen/include/hypervisor-ifs
    41.9 -CFLAGS  += -I../../xu/lib
   41.10 -CFLAGS  += -I../../../linux-xen-sparse/include
   41.11 +
   41.12 +XEN_ROOT = ../../..
   41.13 +
   41.14 +vpath %.h      $(XEN_ROOT)/xen/include/hypervisor-ifs
   41.15 +INCLUDES += -I $(XEN_ROOT)/xen/include/hypervisor-ifs
   41.16 +
   41.17 +vpath %.h      $(XEN_ROOT)/tools/xu/lib
   41.18 +INCLUDES += -I $(XEN_ROOT)/tools/xu/lib
   41.19 +
   41.20 +vpath %h       $(XEN_ROOT)/linux-xen-sparse/include
   41.21 +INCLUDES += -I $(XEN_ROOT)/linux-xen-sparse/include
   41.22 +
   41.23 +vpath %c       $(XEN_ROOT)/tools/lib
   41.24 +INCLUDES += -I $(XEN_ROOT)/tools/lib
   41.25  
   41.26 -HDRS     = $(wildcard *.h)
   41.27 -OBJS     = $(patsubst %.c,%.o,$(wildcard *.c))
   41.28 +LIB_SRCS :=
   41.29 +LIB_SRCS += allocate.c
   41.30 +#LIB_SRCS += enum.c
   41.31 +LIB_SRCS += file_stream.c
   41.32 +LIB_SRCS += gzip_stream.c
   41.33 +#LIB_SRCS += hash_table.c
   41.34 +LIB_SRCS += iostream.c
   41.35 +#LIB_SRCS += kernel_stream.c
   41.36 +#LIB_SRCS += lexis.c
   41.37 +#LIB_SRCS += lzi_stream.c
   41.38 +#LIB_SRCS += lzo_stream.c
   41.39 +#LIB_SRCS += marshal.c
   41.40 +#LIB_SRCS += socket_stream.c
   41.41 +#LIB_SRCS += string_stream.c
   41.42 +#LIB_SRCS += sxpr.c
   41.43 +#LIB_SRCS += sxpr_parser.c
   41.44 +LIB_SRCS += sys_net.c
   41.45 +LIB_SRCS += sys_string.c
   41.46 +#LIB_SRCS += xdr.c
   41.47 +
   41.48 +SRCS     :=
   41.49 +SRCS     += xc_atropos.c
   41.50 +SRCS     += xc_bvtsched.c
   41.51 +SRCS     += xc_domain.c
   41.52 +SRCS     += xc_evtchn.c
   41.53 +SRCS     += xc_io.c
   41.54 +SRCS     += xc_linux_build.c
   41.55 +SRCS     += xc_linux_restore.c
   41.56 +SRCS     += xc_linux_save.c
   41.57 +SRCS     += xc_misc.c
   41.58 +SRCS     += xc_netbsd_build.c
   41.59 +SRCS     += xc_physdev.c
   41.60 +SRCS     += xc_private.c
   41.61 +SRCS     += $(LIB_SRCS)
   41.62 +
   41.63 +#CFLAGS  += -I../../../xen/include/hypervisor-ifs
   41.64 +#CFLAGS  += -I../../xu/lib
   41.65 +#CFLAGS  += -I../../../linux-xen-sparse/include
   41.66 +
   41.67 +CFLAGS   += -Wall
   41.68 +CFLAGS   += -Werror
   41.69 +CFLAGS   += -g
   41.70 +CFLAGS   += -O3
   41.71 +CFLAGS   += -fno-strict-aliasing
   41.72 +CFLAGS   += $(INCLUDES)
   41.73 +# Get gcc to generate the dependencies for us.
   41.74 +CFLAGS   += -Wp,-MD,.$(@F).d
   41.75 +DEPS     = .*.d
   41.76 +
   41.77 +OBJS     = $(patsubst %.c,%.o,$(SRCS))
   41.78  
   41.79  LIB      = libxc.so libxc.so.$(MAJOR) libxc.so.$(MAJOR).$(MINOR)
   41.80  
   41.81 @@ -32,6 +90,8 @@ install: all
   41.82  
   41.83  clean:
   41.84  	$(RM) *.a *.so *.o *.rpm $(LIB)
   41.85 +	$(RM) *~
   41.86 +	$(RM) $(DEPS)
   41.87  
   41.88  rpm: all
   41.89  	rm -rf staging
   41.90 @@ -49,5 +109,8 @@ libxc.so.$(MAJOR):
   41.91  libxc.so.$(MAJOR).$(MINOR): $(OBJS)
   41.92  	$(CC) -Wl,-soname -Wl,$(SONAME) -shared -o $@ $^ -lz
   41.93  
   41.94 -%.o: %.c $(HDRS) Makefile
   41.95 -	$(CC) $(CFLAGS) -o $@ $<
   41.96 +%.o: %.c Makefile
   41.97 +
   41.98 +#	$(CC) $(CFLAGS) -o $@ $<
   41.99 +
  41.100 +-include $(DEPS)
    42.1 --- a/tools/xc/lib/xc.h	Mon Jun 28 08:17:15 2004 +0000
    42.2 +++ b/tools/xc/lib/xc.h	Mon Jun 28 15:03:15 2004 +0000
    42.3 @@ -68,18 +68,10 @@ int xc_shadow_control(int xc_handle,
    42.4  #define XCFLAGS_LIVE    2
    42.5  #define XCFLAGS_DEBUG   4
    42.6  
    42.7 -int xc_linux_save(int xc_handle,
    42.8 -                  u32 domid, 
    42.9 -                  unsigned int flags,
   42.10 -		  int (*writerfn)(void *, const void *, size_t),
   42.11 -		  void *writerst );
   42.12 +struct XcIOContext;
   42.13 +int xc_linux_save(int xc_handle, struct XcIOContext *ioctxt);
   42.14  
   42.15 -int xc_linux_restore(int xc_handle,
   42.16 -                     u32 domid,
   42.17 -                     unsigned int flags,		     
   42.18 -		     int (*readerfn)(void *, void *, size_t),
   42.19 -		     void *readerst,
   42.20 -                     u32 *pdomid);
   42.21 +int xc_linux_restore(int xc_handle, struct XcIOContext *ioctxt);
   42.22  
   42.23  int xc_linux_build(int xc_handle,
   42.24                     u32 domid,
    43.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    43.2 +++ b/tools/xc/lib/xc_io.c	Mon Jun 28 15:03:15 2004 +0000
    43.3 @@ -0,0 +1,27 @@
    43.4 +#include "xc_io.h"
    43.5 +
    43.6 +void xcio_error(XcIOContext *ctxt, const char *msg, ...){
    43.7 +  va_list args;
    43.8 +
    43.9 +  va_start(args, msg);
   43.10 +  IOStream_vprint(ctxt->info, msg, args);
   43.11 +  va_end(args);
   43.12 +}
   43.13 +
   43.14 +void xcio_info(XcIOContext *ctxt, const char *msg, ...){
   43.15 +  va_list args;
   43.16 +
   43.17 +  if(!(ctxt->flags & XCFLAGS_VERBOSE)) return;
   43.18 +  va_start(args, msg);
   43.19 +  IOStream_vprint(ctxt->info, msg, args);
   43.20 +  va_end(args);
   43.21 +}
   43.22 +
   43.23 +void xcio_debug(XcIOContext *ctxt, const char *msg, ...){
   43.24 +  va_list args;
   43.25 +
   43.26 +  if(!(ctxt->flags & XCFLAGS_DEBUG)) return;
   43.27 +  va_start(args, msg);
   43.28 +  IOStream_vprint(ctxt->info, msg, args);
   43.29 +  va_end(args);
   43.30 +}
    44.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    44.2 +++ b/tools/xc/lib/xc_io.h	Mon Jun 28 15:03:15 2004 +0000
    44.3 @@ -0,0 +1,44 @@
    44.4 +#ifndef __XC_XC_IO_H__
    44.5 +#define __XC_XC_IO_H__
    44.6 +
    44.7 +#include "xc_private.h"
    44.8 +#include <iostream.h>
    44.9 +
   44.10 +typedef struct XcIOContext {
   44.11 +    u32 domain;
   44.12 +    unsigned flags;
   44.13 +    IOStream *io;
   44.14 +    IOStream *info;
   44.15 +    IOStream *err;
   44.16 +    char *vmconfig;
   44.17 +    int vmconfig_n;
   44.18 +} XcIOContext;
   44.19 +
   44.20 +static inline int xcio_read(XcIOContext *ctxt, void *buf, int n){
   44.21 +    int rc;
   44.22 +
   44.23 +    rc = IOStream_read(ctxt->io, buf, n);
   44.24 +    return (rc == n ? 0 : rc);
   44.25 +}
   44.26 +
   44.27 +static inline int xcio_write(XcIOContext *ctxt, void *buf, int n){
   44.28 +    int rc;
   44.29 +
   44.30 +    rc = IOStream_write(ctxt->io, buf, n);
   44.31 +    return (rc == n ? 0 : rc);
   44.32 +}
   44.33 +
   44.34 +static inline int xcio_flush(XcIOContext *ctxt){
   44.35 +    return IOStream_flush(ctxt->io);
   44.36 +}
   44.37 +
   44.38 +extern void xcio_error(XcIOContext *ctxt, const char *msg, ...);
   44.39 +extern void xcio_info(XcIOContext *ctxt, const char *msg, ...);
   44.40 +
   44.41 +#define xcio_perror(_ctxt, _msg...) \
   44.42 +xcio_error(_ctxt, "(errno %d %s)" _msg, errno, strerror(errno), ## _msg)
   44.43 +
   44.44 +#endif /* ! __XC_XC_IO_H__ */
   44.45 +
   44.46 +
   44.47 +
    45.1 --- a/tools/xc/lib/xc_linux_restore.c	Mon Jun 28 08:17:15 2004 +0000
    45.2 +++ b/tools/xc/lib/xc_linux_restore.c	Mon Jun 28 15:03:15 2004 +0000
    45.3 @@ -8,7 +8,6 @@
    45.4  
    45.5  #include "xc_private.h"
    45.6  #include <asm-xen/suspend.h>
    45.7 -#include <zlib.h>
    45.8  
    45.9  #define MAX_BATCH_SIZE 1024
   45.10  
   45.11 @@ -21,14 +20,6 @@
   45.12  #endif
   45.13  
   45.14  
   45.15 -/* This may allow us to create a 'quiet' command-line option, if necessary. */
   45.16 -#define verbose_printf(_f, _a...) \
   45.17 -    do {                          \
   45.18 -        if ( !verbose ) break;    \
   45.19 -        printf( _f , ## _a );     \
   45.20 -        fflush(stdout);           \
   45.21 -    } while ( 0 )
   45.22 -
   45.23  static int get_pfn_list(int xc_handle,
   45.24                          u32 domain_id, 
   45.25                          unsigned long *pfn_buf, 
   45.26 @@ -54,19 +45,44 @@ static int get_pfn_list(int xc_handle,
   45.27      return (ret < 0) ? -1 : op.u.getmemlist.num_pfns;
   45.28  }
   45.29  
   45.30 +/** Read the vmconfig string from the state input.
   45.31 + * It is stored as a 4-byte count 'n' followed by n bytes.
   45.32 + * The config data is stored in a new string in 'ioctxt->vmconfig',
   45.33 + * and is null-terminated. The count is stored in 'ioctxt->vmconfig_n'.
   45.34 + *
   45.35 + * @param ioctxt i/o context
   45.36 + * @return 0 on success, non-zero on error.
   45.37 + */
   45.38 +static int read_vmconfig(XcIOContext *ioctxt){
   45.39 +    int err = -1;
   45.40 +    if(xcio_read(ioctxt, &ioctxt->vmconfig_n, sizeof(ioctxt->vmconfig_n))){
   45.41 +        goto exit;
   45.42 +    }
   45.43 +    ioctxt->vmconfig = malloc(ioctxt->vmconfig_n + 1);
   45.44 +    if(!ioctxt->vmconfig) goto exit;
   45.45 +    if(xcio_read(ioctxt, ioctxt->vmconfig, ioctxt->vmconfig_n)){
   45.46 +        goto exit;
   45.47 +    }
   45.48 +    ioctxt->vmconfig[ioctxt->vmconfig_n] = '\0';
   45.49 +    err = 0;
   45.50 +  exit:
   45.51 +    if(err){
   45.52 +        if(ioctxt->vmconfig){
   45.53 +            free(ioctxt->vmconfig);
   45.54 +        }
   45.55 +        ioctxt->vmconfig = NULL;
   45.56 +        ioctxt->vmconfig_n = 0;
   45.57 +    }
   45.58 +    return err;
   45.59 +}
   45.60  
   45.61 -int xc_linux_restore(int xc_handle,
   45.62 -                     u32 dom,
   45.63 -                     unsigned int flags,
   45.64 -                     int (*readerfn)(void *, void *, size_t),
   45.65 -                     void *readerst,
   45.66 -                     u32 *pdomid)
   45.67 +int xc_linux_restore(int xc_handle, XcIOContext *ioctxt)
   45.68  {
   45.69      dom0_op_t op;
   45.70 -    int rc = 1, i, j, n, k;
   45.71 +    int rc = 1, i, n, k;
   45.72      unsigned long mfn, pfn, xpfn;
   45.73      unsigned int prev_pc, this_pc;
   45.74 -    int verbose = flags & XCFLAGS_VERBOSE;
   45.75 +    u32 dom = ioctxt->domain;
   45.76      int verify = 0; 
   45.77  
   45.78      /* Number of page frames in use by this Linux session. */
   45.79 @@ -115,8 +131,7 @@ int xc_linux_restore(int xc_handle,
   45.80      /* used by debug verify code */
   45.81      unsigned long buf[PAGE_SIZE/sizeof(unsigned long)];
   45.82  
   45.83 -    if ( mlock(&ctxt, sizeof(ctxt) ) )
   45.84 -    {   
   45.85 +    if ( mlock(&ctxt, sizeof(ctxt) ) ) {   
   45.86          /* needed for when we do the build dom0 op, 
   45.87             but might as well do early */
   45.88          PERROR("Unable to mlock ctxt");
   45.89 @@ -124,35 +139,36 @@ int xc_linux_restore(int xc_handle,
   45.90      }
   45.91  
   45.92      /* Start writing out the saved-domain record. */
   45.93 -    if ( (*readerfn)(readerst, signature, 16) ||
   45.94 -         (memcmp(signature, "LinuxGuestRecord", 16) != 0) )
   45.95 -    {
   45.96 -        ERROR("Unrecognised state format -- no signature found");
   45.97 +    if ( xcio_read(ioctxt, signature, 16) ||
   45.98 +         (memcmp(signature, "LinuxGuestRecord", 16) != 0) ) {
   45.99 +        xcio_error(ioctxt, "Unrecognised state format -- no signature found");
  45.100          goto out;
  45.101      }
  45.102  
  45.103 -    if ( (*readerfn)(readerst, name,                  sizeof(name)) ||
  45.104 -         (*readerfn)(readerst, &nr_pfns,              sizeof(unsigned long)) ||
  45.105 -         (*readerfn)(readerst, pfn_to_mfn_frame_list, PAGE_SIZE) )
  45.106 -    {
  45.107 -        ERROR("Error when reading from state file");
  45.108 +    if ( xcio_read(ioctxt, name,                  sizeof(name)) ||
  45.109 +         xcio_read(ioctxt, &nr_pfns,              sizeof(unsigned long)) ||
  45.110 +         xcio_read(ioctxt, pfn_to_mfn_frame_list, PAGE_SIZE) ) {
  45.111 +        xcio_error(ioctxt, "Error reading header");
  45.112          goto out;
  45.113      }
  45.114  
  45.115 -    for ( i = 0; i < MAX_DOMAIN_NAME; i++ )
  45.116 -    {
  45.117 +    if(read_vmconfig(ioctxt)){
  45.118 +        xcio_error(ioctxt, "Error writing vmconfig");
  45.119 +        goto out;
  45.120 +    }
  45.121 +
  45.122 +    for ( i = 0; i < MAX_DOMAIN_NAME; i++ ) {
  45.123          if ( name[i] == '\0' ) break;
  45.124          if ( name[i] & 0x80 )
  45.125          {
  45.126 -            ERROR("Random characters in domain name");
  45.127 +            xcio_error(ioctxt, "Random characters in domain name");
  45.128              goto out;
  45.129          }
  45.130      }
  45.131      name[MAX_DOMAIN_NAME-1] = '\0';
  45.132  
  45.133 -    if ( nr_pfns > 1024*1024 )
  45.134 -    {
  45.135 -        ERROR("Invalid state file -- pfn count out of range");
  45.136 +    if ( nr_pfns > 1024*1024 ) {
  45.137 +        xcio_error(ioctxt, "Invalid state file -- pfn count out of range");
  45.138          goto out;
  45.139      }
  45.140  
  45.141 @@ -162,22 +178,19 @@ int xc_linux_restore(int xc_handle,
  45.142      region_mfn       = calloc(1, 4 * MAX_BATCH_SIZE);    
  45.143  
  45.144      if ( (pfn_to_mfn_table == NULL) || (pfn_type == NULL) || 
  45.145 -         (region_mfn == NULL) )
  45.146 -    {
  45.147 +         (region_mfn == NULL) ) {
  45.148          errno = ENOMEM;
  45.149          goto out;
  45.150      }
  45.151      
  45.152 -    if ( mlock(region_mfn, 4 * MAX_BATCH_SIZE ) )
  45.153 -    {
  45.154 -        ERROR("Could not mlock region_mfn");
  45.155 +    if ( mlock(region_mfn, 4 * MAX_BATCH_SIZE ) ) {
  45.156 +        xcio_error(ioctxt, "Could not mlock region_mfn");
  45.157          goto out;
  45.158      }
  45.159  
  45.160      /* Set the domain's name to that from the restore file */
  45.161 -    if ( xc_domain_setname( xc_handle, dom, name ) )
  45.162 -    {
  45.163 -        ERROR("Could not set domain name");
  45.164 +    if ( xc_domain_setname( xc_handle, dom, name ) ) {
  45.165 +        xcio_error(ioctxt, "Could not set domain name");
  45.166          goto out;
  45.167      }
  45.168  
  45.169 @@ -187,7 +200,7 @@ int xc_linux_restore(int xc_handle,
  45.170      if ( xc_domain_setinitialmem(xc_handle, dom, 
  45.171                                   nr_pfns * (PAGE_SIZE / 1024)) )
  45.172      {
  45.173 -        ERROR("Could not set domain initial memory");
  45.174 +        xcio_error(ioctxt, "Could not set domain initial memory");
  45.175          goto out;
  45.176      }
  45.177  
  45.178 @@ -195,9 +208,8 @@ int xc_linux_restore(int xc_handle,
  45.179      op.cmd = DOM0_GETDOMAININFO;
  45.180      op.u.getdomaininfo.domain = (domid_t)dom;
  45.181      op.u.getdomaininfo.ctxt = NULL;
  45.182 -    if ( do_dom0_op(xc_handle, &op) < 0 )
  45.183 -    {
  45.184 -        ERROR("Could not get information on new domain");
  45.185 +    if ( do_dom0_op(xc_handle, &op) < 0 ) {
  45.186 +        xcio_error(ioctxt, "Could not get information on new domain");
  45.187          goto out;
  45.188      }
  45.189      shared_info_frame = op.u.getdomaininfo.shared_info_frame;
  45.190 @@ -208,19 +220,17 @@ int xc_linux_restore(int xc_handle,
  45.191  
  45.192  
  45.193      /* Build the pfn-to-mfn table. We choose MFN ordering returned by Xen. */
  45.194 -    if ( get_pfn_list(xc_handle, dom, pfn_to_mfn_table, nr_pfns) != nr_pfns )
  45.195 -    {
  45.196 -        ERROR("Did not read correct number of frame numbers for new dom");
  45.197 +    if ( get_pfn_list(xc_handle, dom, pfn_to_mfn_table, nr_pfns) != nr_pfns ) {
  45.198 +        xcio_error(ioctxt, "Did not read correct number of frame numbers for new dom");
  45.199          goto out;
  45.200      }
  45.201  
  45.202 -    if ( (mmu = init_mmu_updates(xc_handle, dom)) == NULL )
  45.203 -    {
  45.204 -        ERROR("Could not initialise for MMU updates");
  45.205 +    if ( (mmu = init_mmu_updates(xc_handle, dom)) == NULL ) {
  45.206 +        xcio_error(ioctxt, "Could not initialise for MMU updates");
  45.207          goto out;
  45.208      }
  45.209  
  45.210 -    verbose_printf("Reloading memory pages:   0%%");
  45.211 +    xcio_info(ioctxt, "Reloading memory pages:   0%%");
  45.212  
  45.213      /*
  45.214       * Now simply read each saved frame into its new machine frame.
  45.215 @@ -229,56 +239,45 @@ int xc_linux_restore(int xc_handle,
  45.216      prev_pc = 0;
  45.217  
  45.218      n=0;
  45.219 -    while(1)
  45.220 -    {
  45.221 +    while(1) {
  45.222          int j;
  45.223          unsigned long region_pfn_type[MAX_BATCH_SIZE];
  45.224  
  45.225          this_pc = (n * 100) / nr_pfns;
  45.226 -        if ( (this_pc - prev_pc) >= 5 )
  45.227 -        {
  45.228 -            verbose_printf("\b\b\b\b%3d%%", this_pc);
  45.229 +        if ( (this_pc - prev_pc) >= 5 ) {
  45.230 +            xcio_info(ioctxt, "\b\b\b\b%3d%%", this_pc);
  45.231              prev_pc = this_pc;
  45.232          }
  45.233  
  45.234 -        if ( (*readerfn)(readerst, &j, sizeof(int)) )
  45.235 -        {
  45.236 -            ERROR("Error when reading from state file");
  45.237 +        if ( xcio_read(ioctxt, &j, sizeof(int)) ) {
  45.238 +            xcio_error(ioctxt, "Error when reading from state file");
  45.239              goto out;
  45.240          }
  45.241  
  45.242          DPRINTF("batch %d\n",j);
  45.243   
  45.244 -        if ( j == -1 )
  45.245 -        {
  45.246 +        if ( j == -1 ) {
  45.247              verify = 1;
  45.248              printf("Entering page verify mode\n");
  45.249              continue;
  45.250          }
  45.251  
  45.252 -        if ( j == 0 ) 
  45.253 -            break;  /* our work here is done */
  45.254 +        if ( j == 0 ) break;  /* our work here is done */
  45.255  
  45.256 -        if( j > MAX_BATCH_SIZE )
  45.257 -        {
  45.258 -            ERROR("Max batch size exceeded. Giving up.");
  45.259 +        if( j > MAX_BATCH_SIZE ) {
  45.260 +            xcio_error(ioctxt, "Max batch size exceeded. Giving up.");
  45.261              goto out;
  45.262          }
  45.263   
  45.264 -        if ( (*readerfn)(readerst, region_pfn_type, j*sizeof(unsigned long)) )
  45.265 -        {
  45.266 -            ERROR("Error when reading from state file");
  45.267 +        if ( xcio_read(ioctxt, region_pfn_type, j*sizeof(unsigned long)) ) {
  45.268 +            xcio_error(ioctxt, "Error when reading from state file");
  45.269              goto out;
  45.270          }
  45.271  
  45.272 -        for(i=0;i<j;i++)
  45.273 -        {
  45.274 -            if ( (region_pfn_type[i] & LTAB_MASK) == XTAB)
  45.275 -            {
  45.276 +        for(i=0; i<j; i++) {
  45.277 +            if ( (region_pfn_type[i] & LTAB_MASK) == XTAB) {
  45.278                  region_mfn[i] = 0; /* we know map will fail, but don't care */
  45.279 -            }
  45.280 -            else
  45.281 -            {  
  45.282 +            } else {  
  45.283                  pfn = region_pfn_type[i] & ~LTAB_MASK;
  45.284                  region_mfn[i] = pfn_to_mfn_table[pfn];
  45.285              }          
  45.286 @@ -287,24 +286,20 @@ int xc_linux_restore(int xc_handle,
  45.287          if ( (region_base = mfn_mapper_map_batch( xc_handle, dom, 
  45.288                                                    PROT_WRITE,
  45.289                                                    region_mfn,
  45.290 -                                                  j )) == 0)
  45.291 -        {
  45.292 -            PERROR("map batch failed");
  45.293 +                                                  j )) == 0) {
  45.294 +            xcio_error(ioctxt, "map batch failed");
  45.295              goto out;
  45.296          }
  45.297  
  45.298 -        for(i=0;i<j;i++)
  45.299 -        {
  45.300 +        for(i=0;i<j;i++) {
  45.301              unsigned long *ppage;
  45.302  
  45.303              pfn = region_pfn_type[i] & ~LTAB_MASK;
  45.304  
  45.305 -            if ( (region_pfn_type[i] & LTAB_MASK) == XTAB)
  45.306 -                continue;
  45.307 +            if ( (region_pfn_type[i] & LTAB_MASK) == XTAB) continue;
  45.308  
  45.309 -            if (pfn>nr_pfns)
  45.310 -            {
  45.311 -                ERROR("pfn out of range");
  45.312 +            if (pfn>nr_pfns) {
  45.313 +                xcio_error(ioctxt, "pfn out of range");
  45.314                  goto out;
  45.315              }
  45.316  
  45.317 @@ -314,36 +309,32 @@ int xc_linux_restore(int xc_handle,
  45.318  
  45.319              mfn = pfn_to_mfn_table[pfn];
  45.320  
  45.321 -            if ( verify )
  45.322 +            if ( verify ) {
  45.323                  ppage = (unsigned long*) buf;  /* debug case */
  45.324 -            else
  45.325 +            } else {
  45.326                  ppage = (unsigned long*) (region_base + i*PAGE_SIZE);
  45.327 +            }
  45.328  
  45.329 -            if ( (*readerfn)(readerst, ppage, PAGE_SIZE) )
  45.330 -            {
  45.331 -                ERROR("Error when reading from state file");
  45.332 +            if ( xcio_read(ioctxt, ppage, PAGE_SIZE) ) {
  45.333 +                xcio_error(ioctxt, "Error when reading from state file");
  45.334                  goto out;
  45.335              }
  45.336  
  45.337 -            switch( region_pfn_type[i] )
  45.338 -            {
  45.339 +            switch( region_pfn_type[i] ) {
  45.340              case 0:
  45.341                  break;
  45.342  
  45.343              case L1TAB:
  45.344              {
  45.345 -                for ( k = 0; k < 1024; k++ )
  45.346 -                {
  45.347 -                    if ( ppage[k] & _PAGE_PRESENT )
  45.348 -                    {
  45.349 +                for ( k = 0; k < 1024; k++ ) {
  45.350 +                    if ( ppage[k] & _PAGE_PRESENT ) {
  45.351                          xpfn = ppage[k] >> PAGE_SHIFT;
  45.352  
  45.353 -                        if ( xpfn >= nr_pfns )
  45.354 -                        {
  45.355 -                            ERROR("Frame number in type %d page table is "
  45.356 -                                  "out of range. i=%d k=%d pfn=0x%x "
  45.357 -                                  "nr_pfns=%d", region_pfn_type[i]>>28, i, 
  45.358 -                                  k, xpfn,nr_pfns);
  45.359 +                        if ( xpfn >= nr_pfns ) {
  45.360 +                            xcio_error(ioctxt, "Frame number in type %lu page table is "
  45.361 +                                  "out of range. i=%d k=%d pfn=0x%lx "
  45.362 +                                  "nr_pfns=%lu", region_pfn_type[i]>>28, i, 
  45.363 +                                  k, xpfn, nr_pfns);
  45.364                              goto out;
  45.365                          }
  45.366  
  45.367 @@ -359,16 +350,13 @@ int xc_linux_restore(int xc_handle,
  45.368              {
  45.369                  for ( k = 0; 
  45.370                        k < (HYPERVISOR_VIRT_START>>L2_PAGETABLE_SHIFT); 
  45.371 -                      k++ )
  45.372 -                {
  45.373 -                    if ( ppage[k] & _PAGE_PRESENT )
  45.374 -                    {
  45.375 +                      k++ ) {
  45.376 +                    if ( ppage[k] & _PAGE_PRESENT ) {
  45.377                          xpfn = ppage[k] >> PAGE_SHIFT;
  45.378  
  45.379 -                        if ( xpfn >= nr_pfns )
  45.380 -                        {
  45.381 -                            ERROR("Frame number in type %d page table is "
  45.382 -                                  "out of range. i=%d k=%d pfn=%d nr_pfns=%d",
  45.383 +                        if ( xpfn >= nr_pfns ) {
  45.384 +                            xcio_error(ioctxt, "Frame number in type %lu page table is "
  45.385 +                                  "out of range. i=%d k=%d pfn=%lu nr_pfns=%lu",
  45.386                                    region_pfn_type[i]>>28, i, k, xpfn, nr_pfns);
  45.387  
  45.388                              goto out;
  45.389 @@ -383,24 +371,21 @@ int xc_linux_restore(int xc_handle,
  45.390              break;
  45.391  
  45.392              default:
  45.393 -                ERROR("Bogus page type %x page table is out of range."
  45.394 -                      " i=%d nr_pfns=%d", region_pfn_type[i], i, nr_pfns);
  45.395 +                xcio_error(ioctxt, "Bogus page type %lx page table is out of range."
  45.396 +                      " i=%d nr_pfns=%lu", region_pfn_type[i], i, nr_pfns);
  45.397                  goto out;
  45.398  
  45.399              } /* end of page type switch statement */
  45.400  
  45.401 -            if ( verify )
  45.402 -            {
  45.403 +            if ( verify ) {
  45.404                  int res = memcmp(buf, (region_base + i*PAGE_SIZE), PAGE_SIZE );
  45.405 -                if (res)
  45.406 -                {
  45.407 +                if (res) {
  45.408                      int v;
  45.409 -                    printf("************** pfn=%x type=%x gotcs=%08lx "
  45.410 +                    printf("************** pfn=%lx type=%lx gotcs=%08lx "
  45.411                             "actualcs=%08lx\n", pfn, pfn_type[pfn], 
  45.412                             csum_page(region_base + i*PAGE_SIZE), 
  45.413                             csum_page(buf));
  45.414 -                    for ( v = 0; v < 4; v++ )
  45.415 -                    {
  45.416 +                    for ( v = 0; v < 4; v++ ) {
  45.417                          unsigned long *p = (unsigned long *)
  45.418                              (region_base + i*PAGE_SIZE);
  45.419                          if ( buf[v] != p[v] )
  45.420 @@ -411,8 +396,7 @@ int xc_linux_restore(int xc_handle,
  45.421              }
  45.422  
  45.423              if ( add_mmu_update(xc_handle, mmu,
  45.424 -                                (mfn<<PAGE_SHIFT) | MMU_MACHPHYS_UPDATE, pfn) )
  45.425 -            {
  45.426 +                                (mfn<<PAGE_SHIFT) | MMU_MACHPHYS_UPDATE, pfn) ) {
  45.427                  printf("machpys mfn=%ld pfn=%ld\n",mfn,pfn);
  45.428                  goto out;
  45.429              }
  45.430 @@ -431,44 +415,36 @@ int xc_linux_restore(int xc_handle,
  45.431       * Pin page tables. Do this after writing to them as otherwise Xen
  45.432       * will barf when doing the type-checking.
  45.433       */
  45.434 -    for ( i = 0; i < nr_pfns; i++ )
  45.435 -    {
  45.436 -        if ( pfn_type[i] == L1TAB )
  45.437 -        {
  45.438 +    for ( i = 0; i < nr_pfns; i++ ) {
  45.439 +        if ( pfn_type[i] == L1TAB ) {
  45.440              if ( add_mmu_update(xc_handle, mmu,
  45.441                                  (pfn_to_mfn_table[i]<<PAGE_SHIFT) | 
  45.442                                  MMU_EXTENDED_COMMAND,
  45.443 -                                MMUEXT_PIN_L1_TABLE) )
  45.444 -            {
  45.445 +                                MMUEXT_PIN_L1_TABLE) ) {
  45.446                  printf("ERR pin L1 pfn=%lx mfn=%lx\n",
  45.447 -                       i, pfn_to_mfn_table[i]);
  45.448 +                       (unsigned long)i, pfn_to_mfn_table[i]);
  45.449                  goto out;
  45.450              }
  45.451 -        }
  45.452 -        else if ( pfn_type[i] == L2TAB )
  45.453 -        {
  45.454 +        } else if ( pfn_type[i] == L2TAB ) {
  45.455              if ( add_mmu_update(xc_handle, mmu,
  45.456                                  (pfn_to_mfn_table[i]<<PAGE_SHIFT) | 
  45.457                                  MMU_EXTENDED_COMMAND,
  45.458 -                                MMUEXT_PIN_L2_TABLE) )
  45.459 -            {
  45.460 +                                MMUEXT_PIN_L2_TABLE) ) {
  45.461                  printf("ERR pin L2 pfn=%lx mfn=%lx\n",
  45.462 -                       i, pfn_to_mfn_table[i]);
  45.463 +                       (unsigned long)i, pfn_to_mfn_table[i]);
  45.464                  goto out;
  45.465              }
  45.466          }
  45.467      }
  45.468  
  45.469 -    if ( finish_mmu_updates(xc_handle, mmu) )
  45.470 -        goto out;
  45.471 +    if ( finish_mmu_updates(xc_handle, mmu) ) goto out;
  45.472  
  45.473 -    verbose_printf("\b\b\b\b100%%\nMemory reloaded.\n");
  45.474 +    xcio_info(ioctxt, "\b\b\b\b100%%\nMemory reloaded.\n");
  45.475  
  45.476  
  45.477 -    if ( (*readerfn)(readerst, &ctxt,                 sizeof(ctxt)) ||
  45.478 -         (*readerfn)(readerst, shared_info,           PAGE_SIZE) )
  45.479 -    {
  45.480 -        ERROR("Error when reading from state file");
  45.481 +    if ( xcio_read(ioctxt, &ctxt,                 sizeof(ctxt)) ||
  45.482 +         xcio_read(ioctxt, shared_info,           PAGE_SIZE) ) {
  45.483 +        xcio_error(ioctxt, "Error when reading from state file");
  45.484          goto out;
  45.485      }
  45.486  
  45.487 @@ -476,7 +452,7 @@ int xc_linux_restore(int xc_handle,
  45.488      pfn = ctxt.cpu_ctxt.esi;
  45.489      if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NOTAB) )
  45.490      {
  45.491 -        ERROR("Suspend record frame number is bad");
  45.492 +        xcio_error(ioctxt, "Suspend record frame number is bad");
  45.493          goto out;
  45.494      }
  45.495      ctxt.cpu_ctxt.esi = mfn = pfn_to_mfn_table[pfn];
  45.496 @@ -487,17 +463,14 @@ int xc_linux_restore(int xc_handle,
  45.497      unmap_pfn(pm_handle, p_srec);
  45.498  
  45.499      /* Uncanonicalise each GDT frame number. */
  45.500 -    if ( ctxt.gdt_ents > 8192 )
  45.501 -    {
  45.502 -        ERROR("GDT entry count out of range");
  45.503 +    if ( ctxt.gdt_ents > 8192 ) {
  45.504 +        xcio_error(ioctxt, "GDT entry count out of range");
  45.505          goto out;
  45.506      }
  45.507 -    for ( i = 0; i < ctxt.gdt_ents; i += 512 )
  45.508 -    {
  45.509 +    for ( i = 0; i < ctxt.gdt_ents; i += 512 ) {
  45.510          pfn = ctxt.gdt_frames[i];
  45.511 -        if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NOTAB) )
  45.512 -        {
  45.513 -            ERROR("GDT frame number is bad");
  45.514 +        if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NOTAB) ) {
  45.515 +            xcio_error(ioctxt, "GDT frame number is bad");
  45.516              goto out;
  45.517          }
  45.518          ctxt.gdt_frames[i] = pfn_to_mfn_table[pfn];
  45.519 @@ -505,11 +478,10 @@ int xc_linux_restore(int xc_handle,
  45.520  
  45.521      /* Uncanonicalise the page table base pointer. */
  45.522      pfn = ctxt.pt_base >> PAGE_SHIFT;
  45.523 -    if ( (pfn >= nr_pfns) || (pfn_type[pfn] != L2TAB) )
  45.524 -    {
  45.525 -        printf("PT base is bad. pfn=%d nr=%d type=%08lx %08lx\n",
  45.526 -               pfn, nr_pfns, pfn_type[pfn], L2TAB);
  45.527 -        ERROR("PT base is bad.");
  45.528 +    if ( (pfn >= nr_pfns) || (pfn_type[pfn] != L2TAB) ) {
  45.529 +        printf("PT base is bad. pfn=%lu nr=%lu type=%08lx %08lx\n",
  45.530 +               pfn, nr_pfns, pfn_type[pfn], (unsigned long)L2TAB);
  45.531 +        xcio_error(ioctxt, "PT base is bad.");
  45.532          goto out;
  45.533      }
  45.534      ctxt.pt_base = pfn_to_mfn_table[pfn] << PAGE_SHIFT;
  45.535 @@ -527,14 +499,12 @@ int xc_linux_restore(int xc_handle,
  45.536  
  45.537  
  45.538      /* Uncanonicalise the pfn-to-mfn table frame-number list. */
  45.539 -    for ( i = 0; i < (nr_pfns+1023)/1024; i++ )
  45.540 -    {
  45.541 +    for ( i = 0; i < (nr_pfns+1023)/1024; i++ ) {
  45.542          unsigned long pfn, mfn;
  45.543  
  45.544          pfn = pfn_to_mfn_frame_list[i];
  45.545 -        if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NOTAB) )
  45.546 -        {
  45.547 -            ERROR("PFN-to-MFN frame number is bad");
  45.548 +        if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NOTAB) ) {
  45.549 +            xcio_error(ioctxt, "PFN-to-MFN frame number is bad");
  45.550              goto out;
  45.551          }
  45.552          mfn = pfn_to_mfn_table[pfn];
  45.553 @@ -545,9 +515,8 @@ int xc_linux_restore(int xc_handle,
  45.554            mfn_mapper_map_batch(xc_handle, dom, 
  45.555                                 PROT_WRITE,
  45.556                                 pfn_to_mfn_frame_list,
  45.557 -                               (nr_pfns+1023)/1024 )) == 0 )
  45.558 -    {
  45.559 -        ERROR("Couldn't map pfn_to_mfn table");
  45.560 +                               (nr_pfns+1023)/1024 )) == 0 ) {
  45.561 +        xcio_error(ioctxt, "Couldn't map pfn_to_mfn table");
  45.562          goto out;
  45.563      }
  45.564  
  45.565 @@ -569,24 +538,26 @@ int xc_linux_restore(int xc_handle,
  45.566       *  9. debugregs are checked by Xen.
  45.567       *  10. callback code selectors need checking.
  45.568       */
  45.569 -    for ( i = 0; i < 256; i++ )
  45.570 -    {
  45.571 +    for ( i = 0; i < 256; i++ ) {
  45.572          ctxt.trap_ctxt[i].vector = i;
  45.573          if ( (ctxt.trap_ctxt[i].cs & 3) == 0 )
  45.574              ctxt.trap_ctxt[i].cs = FLAT_GUESTOS_CS;
  45.575      }
  45.576 -    if ( (ctxt.guestos_ss & 3) == 0 )
  45.577 +    if ( (ctxt.guestos_ss & 3) == 0 ){
  45.578          ctxt.guestos_ss = FLAT_GUESTOS_DS;
  45.579 -    if ( (ctxt.event_callback_cs & 3) == 0 )
  45.580 +    }
  45.581 +    if ( (ctxt.event_callback_cs & 3) == 0 ){
  45.582          ctxt.event_callback_cs = FLAT_GUESTOS_CS;
  45.583 -    if ( (ctxt.failsafe_callback_cs & 3) == 0 )
  45.584 +    }
  45.585 +    if ( (ctxt.failsafe_callback_cs & 3) == 0 ){
  45.586          ctxt.failsafe_callback_cs = FLAT_GUESTOS_CS;
  45.587 +    }
  45.588      if ( ((ctxt.ldt_base & (PAGE_SIZE - 1)) != 0) ||
  45.589           (ctxt.ldt_ents > 8192) ||
  45.590           (ctxt.ldt_base > HYPERVISOR_VIRT_START) ||
  45.591           ((ctxt.ldt_base + ctxt.ldt_ents*8) > HYPERVISOR_VIRT_START) )
  45.592      {
  45.593 -        ERROR("Bad LDT base or size");
  45.594 +        xcio_error(ioctxt, "Bad LDT base or size");
  45.595          goto out;
  45.596      }
  45.597     
  45.598 @@ -597,34 +568,33 @@ int xc_linux_restore(int xc_handle,
  45.599  
  45.600      /* don't start the domain as we have console etc to set up */
  45.601    
  45.602 -    if( rc == 0 )
  45.603 -    {
  45.604 +    if( rc == 0 ) {
  45.605          /* Success: print the domain id. */
  45.606 -        verbose_printf("DOM=%u\n", dom);
  45.607 +        xcio_info(ioctxt, "DOM=%lu\n", dom);
  45.608          return 0;
  45.609      }
  45.610  
  45.611  
  45.612   out:
  45.613 -    if ( (rc != 0) && (dom != 0) )
  45.614 +    if ( (rc != 0) && (dom != 0) ){
  45.615          xc_domain_destroy(xc_handle, dom);
  45.616 -
  45.617 -    if ( mmu != NULL )
  45.618 +    }
  45.619 +    if ( mmu != NULL ){
  45.620          free(mmu);
  45.621 -
  45.622 -    if ( pm_handle >= 0 )
  45.623 +    }
  45.624 +    if ( pm_handle >= 0 ){
  45.625          (void)close_pfn_mapper(pm_handle);
  45.626 +    }
  45.627 +    if ( pfn_to_mfn_table != NULL ){
  45.628 +        free(pfn_to_mfn_table);
  45.629 +    }
  45.630 +    if ( pfn_type != NULL ){
  45.631 +        free(pfn_type);
  45.632 +    }
  45.633  
  45.634 -    if ( pfn_to_mfn_table != NULL )
  45.635 -        free(pfn_to_mfn_table);
  45.636 -    if ( pfn_type != NULL )
  45.637 -        free(pfn_type);
  45.638 -
  45.639 -
  45.640 -    if ( rc == 0 )
  45.641 -        *pdomid = dom;
  45.642 -
  45.643 +    if ( rc == 0 ){
  45.644 +        ioctxt->domain = dom;
  45.645 +    }
  45.646      DPRINTF("Restore exit with rc=%d\n",rc);
  45.647 -
  45.648      return rc;
  45.649  }
    46.1 --- a/tools/xc/lib/xc_linux_save.c	Mon Jun 28 08:17:15 2004 +0000
    46.2 +++ b/tools/xc/lib/xc_linux_save.c	Mon Jun 28 15:03:15 2004 +0000
    46.3 @@ -6,6 +6,7 @@
    46.4   * Copyright (c) 2003, K A Fraser.
    46.5   */
    46.6  
    46.7 +#include <sys/time.h>
    46.8  #include "xc_private.h"
    46.9  #include <asm-xen/suspend.h>
   46.10  
   46.11 @@ -26,16 +27,6 @@
   46.12  #define DDPRINTF(_f, _a...) ((void)0)
   46.13  #endif
   46.14  
   46.15 -
   46.16 -
   46.17 -/* This may allow us to create a 'quiet' command-line option, if necessary. */
   46.18 -#define verbose_printf(_f, _a...) \
   46.19 -    do {                          \
   46.20 -        if ( !verbose ) break;    \
   46.21 -        printf( _f , ## _a );     \
   46.22 -        fflush(stdout);           \
   46.23 -    } while ( 0 )
   46.24 -
   46.25  /*
   46.26   * Returns TRUE if the given machine frame number has a unique mapping
   46.27   * in the guest's pseudophysical map.
   46.28 @@ -197,20 +188,30 @@ static int track_cpu_usage( int xc_handl
   46.29      return 0;
   46.30  }
   46.31  
   46.32 +/** Write the vmconfig string.
   46.33 + * It is stored as a 4-byte count 'n' followed by n bytes.
   46.34 + *
   46.35 + * @param ioctxt i/o context
   46.36 + * @return 0 on success, non-zero on error.
   46.37 + */
   46.38 +static int write_vmconfig(XcIOContext *ioctxt){
   46.39 +    int err = -1;
   46.40 +    if(xcio_write(ioctxt, &ioctxt->vmconfig_n, sizeof(ioctxt->vmconfig_n))) goto exit;
   46.41 +    if(xcio_write(ioctxt, ioctxt->vmconfig, ioctxt->vmconfig_n)) goto exit;
   46.42 +    err = 0;
   46.43 +  exit:
   46.44 +    return err;
   46.45 +}
   46.46  
   46.47 -int xc_linux_save(int xc_handle,
   46.48 -                  u32 domid, 
   46.49 -                  unsigned int flags,
   46.50 -                  int (*writerfn)(void *, const void *, size_t),
   46.51 -                  void *writerst )
   46.52 +int xc_linux_save(int xc_handle, XcIOContext *ioctxt)
   46.53  {
   46.54      dom0_op_t op;
   46.55      int rc = 1, i, j, k, last_iter, iter = 0;
   46.56      unsigned long mfn;
   46.57 -    int verbose = flags & XCFLAGS_VERBOSE;
   46.58 -    int live = flags & XCFLAGS_LIVE;
   46.59 -    int debug = flags & XCFLAGS_DEBUG;
   46.60 -    int sent_last_iter, sent_this_iter, skip_this_iter;
   46.61 +    u32 domid = ioctxt->domain;
   46.62 +    int live = (ioctxt->flags & XCFLAGS_LIVE);
   46.63 +    int debug = (ioctxt->flags & XCFLAGS_DEBUG);
   46.64 +    int sent_last_iter, skip_this_iter;
   46.65      unsigned long dirtied_this_iter, faults_this_iter;
   46.66  
   46.67      /* Important tuning parameters */
   46.68 @@ -246,7 +247,7 @@ int xc_linux_save(int xc_handle,
   46.69      unsigned long *live_shinfo;
   46.70  
   46.71      /* base of the region in which domain memory is mapped */
   46.72 -    unsigned char *region_base;
   46.73 +    unsigned char *region_base = NULL;
   46.74  
   46.75      /* A temporary mapping, and a copy, of the guest's suspend record. */
   46.76      suspend_record_t *p_srec;
   46.77 @@ -266,16 +267,14 @@ int xc_linux_save(int xc_handle,
   46.78      int needed_to_fix = 0;
   46.79      int total_sent    = 0;
   46.80      
   46.81 -    if ( mlock(&ctxt, sizeof(ctxt) ) )
   46.82 -    {
   46.83 -        PERROR("Unable to mlock ctxt");
   46.84 +    if (mlock(&ctxt, sizeof(ctxt))) {
   46.85 +        xcio_perror(ioctxt, "Unable to mlock ctxt");
   46.86          return 1;
   46.87      }
   46.88  
   46.89      /* Ensure that the domain exists, and that it is stopped. */
   46.90 -    if ( xc_domain_pause(xc_handle, domid) )
   46.91 -    {
   46.92 -        PERROR("Could not pause domain");
   46.93 +    if ( xc_domain_pause(xc_handle, domid) ){
   46.94 +        xcio_perror(ioctxt, "Could not pause domain");
   46.95          goto out;
   46.96      }
   46.97  
   46.98 @@ -283,9 +282,8 @@ int xc_linux_save(int xc_handle,
   46.99      shared_info_frame = op.u.getdomaininfo.shared_info_frame;
  46.100  
  46.101      /* A cheesy test to see whether the domain contains valid state. */
  46.102 -    if ( ctxt.pt_base == 0 )
  46.103 -    {
  46.104 -        ERROR("Domain is not in a valid Linux guest OS state");
  46.105 +    if ( ctxt.pt_base == 0 ){
  46.106 +        xcio_error(ioctxt, "Domain is not in a valid Linux guest OS state");
  46.107          goto out;
  46.108      }
  46.109  
  46.110 @@ -293,20 +291,17 @@ int xc_linux_save(int xc_handle,
  46.111         domid for this to succeed. */
  46.112      p_srec = mfn_mapper_map_single(xc_handle, domid,
  46.113                                     sizeof(*p_srec), PROT_READ, 
  46.114 -                                   ctxt.cpu_ctxt.esi );
  46.115 -
  46.116 -    if (!p_srec)
  46.117 -    {
  46.118 -        ERROR("Couldn't map state record");
  46.119 +                                   ctxt.cpu_ctxt.esi);
  46.120 +    if (!p_srec){
  46.121 +        xcio_error(ioctxt, "Couldn't map state record");
  46.122          goto out;
  46.123      }
  46.124  
  46.125      nr_pfns = p_srec->nr_pfns;
  46.126  
  46.127      /* cheesy sanity check */
  46.128 -    if ( nr_pfns > 1024*1024 )
  46.129 -    {
  46.130 -        ERROR("Invalid state record -- pfn count out of range");
  46.131 +    if ( nr_pfns > 1024*1024 ){
  46.132 +        xcio_error(ioctxt, "Invalid state record -- pfn count out of range");
  46.133          goto out;
  46.134      }
  46.135  
  46.136 @@ -316,9 +311,8 @@ int xc_linux_save(int xc_handle,
  46.137                                PAGE_SIZE, PROT_READ, 
  46.138                                p_srec->pfn_to_mfn_frame_list );
  46.139  
  46.140 -    if (!live_pfn_to_mfn_frame_list)
  46.141 -    {
  46.142 -        ERROR("Couldn't map pfn_to_mfn_frame_list");
  46.143 +    if (!live_pfn_to_mfn_frame_list){
  46.144 +        xcio_error(ioctxt, "Couldn't map pfn_to_mfn_frame_list");
  46.145          goto out;
  46.146      }
  46.147  
  46.148 @@ -345,24 +339,21 @@ int xc_linux_save(int xc_handle,
  46.149         (its not clear why it would want to change them, and we'll be OK
  46.150         from a safety POV anyhow. */
  46.151  
  46.152 -    live_pfn_to_mfn_table = mfn_mapper_map_batch( xc_handle, domid, 
  46.153 -                                                  PROT_READ,
  46.154 -                                                  live_pfn_to_mfn_frame_list,
  46.155 -                                                  (nr_pfns+1023)/1024 );  
  46.156 -    if( !live_pfn_to_mfn_table )
  46.157 -    {
  46.158 -        PERROR("Couldn't map pfn_to_mfn table");
  46.159 +    live_pfn_to_mfn_table = mfn_mapper_map_batch(xc_handle, domid, 
  46.160 +                                                 PROT_READ,
  46.161 +                                                 live_pfn_to_mfn_frame_list,
  46.162 +                                                 (nr_pfns+1023)/1024 );  
  46.163 +    if( !live_pfn_to_mfn_table ){
  46.164 +        xcio_perror(ioctxt, "Couldn't map pfn_to_mfn table");
  46.165          goto out;
  46.166      }
  46.167  
  46.168  
  46.169      /* Canonicalise the pfn-to-mfn table frame-number list. */
  46.170      memcpy( pfn_to_mfn_frame_list, live_pfn_to_mfn_frame_list, PAGE_SIZE );
  46.171 -    for ( i = 0; i < nr_pfns; i += 1024 )
  46.172 -    {
  46.173 -        if ( !translate_mfn_to_pfn(&pfn_to_mfn_frame_list[i/1024]) )
  46.174 -        {
  46.175 -            ERROR("Frame # in pfn-to-mfn frame list is not in pseudophys");
  46.176 +    for ( i = 0; i < nr_pfns; i += 1024 ){
  46.177 +        if ( !translate_mfn_to_pfn(&pfn_to_mfn_frame_list[i/1024]) ){
  46.178 +            xcio_error(ioctxt, "Frame # in pfn-to-mfn frame list is not in pseudophys");
  46.179              goto out;
  46.180          }
  46.181      }
  46.182 @@ -370,27 +361,24 @@ int xc_linux_save(int xc_handle,
  46.183      /* At this point, we can start the domain again if we're doing a
  46.184         live suspend */
  46.185  
  46.186 -    if( live )
  46.187 -    { 
  46.188 +    if( live ){ 
  46.189          if ( xc_shadow_control( xc_handle, domid, 
  46.190                                  DOM0_SHADOW_CONTROL_OP_ENABLE_LOGDIRTY,
  46.191 -                                NULL, 0, NULL, NULL ) < 0 )
  46.192 -        {
  46.193 -            ERROR("Couldn't enable shadow mode");
  46.194 +                                NULL, 0, NULL, NULL ) < 0 ){
  46.195 +            xcio_error(ioctxt, "Couldn't enable shadow mode");
  46.196              goto out;
  46.197          }
  46.198  
  46.199 -        if ( xc_domain_unpause(xc_handle, domid) < 0 )
  46.200 -        {
  46.201 -            ERROR("Couldn't unpause domain");
  46.202 +        if ( xc_domain_unpause(xc_handle, domid) < 0 ){
  46.203 +            xcio_error(ioctxt, "Couldn't unpause domain");
  46.204              goto out;
  46.205          }
  46.206  
  46.207          last_iter = 0;
  46.208          sent_last_iter = 1<<20; /* 4GB's worth of pages */
  46.209 +    } else{
  46.210 +        last_iter = 1;
  46.211      }
  46.212 -    else
  46.213 -        last_iter = 1;
  46.214  
  46.215  
  46.216      /* Setup to_send bitmap */
  46.217 @@ -401,25 +389,22 @@ int xc_linux_save(int xc_handle,
  46.218          to_fix  = calloc( 1, sz );
  46.219          to_skip = malloc( sz );
  46.220  
  46.221 -        if (!to_send || !to_fix || !to_skip)
  46.222 -        {
  46.223 -            ERROR("Couldn't allocate to_send array");
  46.224 +        if (!to_send || !to_fix || !to_skip){
  46.225 +            xcio_error(ioctxt, "Couldn't allocate to_send array");
  46.226              goto out;
  46.227          }
  46.228  
  46.229          memset( to_send, 0xff, sz );
  46.230  
  46.231 -        if ( mlock( to_send, sz ) )
  46.232 -        {
  46.233 -            PERROR("Unable to mlock to_send");
  46.234 +        if ( mlock( to_send, sz ) ){
  46.235 +            xcio_perror(ioctxt, "Unable to mlock to_send");
  46.236              return 1;
  46.237          }
  46.238  
  46.239          /* (to fix is local only) */
  46.240  
  46.241 -        if ( mlock( to_skip, sz ) )
  46.242 -        {
  46.243 -            PERROR("Unable to mlock to_skip");
  46.244 +        if ( mlock( to_skip, sz ) ){
  46.245 +            xcio_perror(ioctxt, "Unable to mlock to_skip");
  46.246              return 1;
  46.247          }
  46.248  
  46.249 @@ -429,21 +414,19 @@ int xc_linux_save(int xc_handle,
  46.250         15->4 16->4 17->5 */
  46.251      for( i=nr_pfns-1, order_nr=0; i ; i>>=1, order_nr++ );
  46.252  
  46.253 -    printf("nr_pfns=%d order_nr=%d\n",nr_pfns, order_nr);
  46.254 +    printf("nr_pfns=%lu order_nr=%d\n",nr_pfns, order_nr);
  46.255  
  46.256      /* We want zeroed memory so use calloc rather than malloc. */
  46.257      pfn_type = calloc(BATCH_SIZE, sizeof(unsigned long));
  46.258      pfn_batch = calloc(BATCH_SIZE, sizeof(unsigned long));
  46.259  
  46.260 -    if ( (pfn_type == NULL) || (pfn_batch == NULL) )
  46.261 -    {
  46.262 +    if ( (pfn_type == NULL) || (pfn_batch == NULL) ){
  46.263          errno = ENOMEM;
  46.264          goto out;
  46.265      }
  46.266  
  46.267 -    if ( mlock( pfn_type, BATCH_SIZE * sizeof(unsigned long) ) )
  46.268 -    {
  46.269 -        ERROR("Unable to mlock");
  46.270 +    if ( mlock( pfn_type, BATCH_SIZE * sizeof(unsigned long) ) ){
  46.271 +        xcio_error(ioctxt, "Unable to mlock");
  46.272          goto out;
  46.273      }
  46.274  
  46.275 @@ -452,8 +435,7 @@ int xc_linux_save(int xc_handle,
  46.276       * Quick belt and braces sanity check.
  46.277       */
  46.278  #if DEBUG
  46.279 -    for ( i = 0; i < nr_pfns; i++ )
  46.280 -    {
  46.281 +    for ( i = 0; i < nr_pfns; i++ ){
  46.282          mfn = live_pfn_to_mfn_table[i];
  46.283  
  46.284          if( (live_mfn_to_pfn_table[mfn] != i) && (mfn != 0x80000004) )
  46.285 @@ -467,29 +449,30 @@ int xc_linux_save(int xc_handle,
  46.286                                          PAGE_SIZE, PROT_READ,
  46.287                                          shared_info_frame);
  46.288  
  46.289 -    if (!live_shinfo)
  46.290 -    {
  46.291 -        ERROR("Couldn't map live_shinfo");
  46.292 +    if (!live_shinfo){
  46.293 +        xcio_error(ioctxt, "Couldn't map live_shinfo");
  46.294          goto out;
  46.295      }
  46.296  
  46.297      /* Start writing out the saved-domain record. */
  46.298  
  46.299 -    if ( (*writerfn)(writerst, "LinuxGuestRecord",    16) ||
  46.300 -         (*writerfn)(writerst, name,                  sizeof(name)) ||
  46.301 -         (*writerfn)(writerst, &nr_pfns,              sizeof(unsigned long)) ||
  46.302 -         (*writerfn)(writerst, pfn_to_mfn_frame_list, PAGE_SIZE) )
  46.303 -    {
  46.304 -        ERROR("Error when writing to state file (1)");
  46.305 +    if ( xcio_write(ioctxt, "LinuxGuestRecord",    16) ||
  46.306 +         xcio_write(ioctxt, name,                  sizeof(name)) ||
  46.307 +         xcio_write(ioctxt, &nr_pfns,              sizeof(unsigned long)) ||
  46.308 +         xcio_write(ioctxt, pfn_to_mfn_frame_list, PAGE_SIZE) ){
  46.309 +        xcio_error(ioctxt, "Error writing header");
  46.310 +        goto out;
  46.311 +    }
  46.312 +    if(write_vmconfig(ioctxt)){
  46.313 +        xcio_error(ioctxt, "Error writing vmconfig");
  46.314          goto out;
  46.315      }
  46.316  
  46.317 -    track_cpu_usage( xc_handle, domid, 0, 0, 0, 0 );
  46.318 +    track_cpu_usage(xc_handle, domid, 0, 0, 0, 0 );
  46.319  
  46.320      /* Now write out each data page, canonicalising page tables as we go... */
  46.321      
  46.322 -    while(1)
  46.323 -    {
  46.324 +    while(1){
  46.325          unsigned int prev_pc, sent_this_iter, N, batch;
  46.326  
  46.327          iter++;
  46.328 @@ -498,15 +481,13 @@ int xc_linux_save(int xc_handle,
  46.329          prev_pc = 0;
  46.330          N=0;
  46.331  
  46.332 -        verbose_printf("Saving memory pages: iter %d   0%%", iter);
  46.333 +        xcio_info(ioctxt, "Saving memory pages: iter %d   0%%", iter);
  46.334  
  46.335 -        while( N < nr_pfns )
  46.336 -        {
  46.337 +        while( N < nr_pfns ){
  46.338              unsigned int this_pc = (N * 100) / nr_pfns;
  46.339  
  46.340 -            if ( (this_pc - prev_pc) >= 5 )
  46.341 -            {
  46.342 -                verbose_printf("\b\b\b\b%3d%%", this_pc);
  46.343 +            if ( (this_pc - prev_pc) >= 5 ){
  46.344 +                xcio_info(ioctxt, "\b\b\b\b%3d%%", this_pc);
  46.345                  prev_pc = this_pc;
  46.346              }
  46.347  
  46.348 @@ -516,9 +497,8 @@ int xc_linux_save(int xc_handle,
  46.349              if ( !last_iter && 
  46.350                   xc_shadow_control(xc_handle, domid, 
  46.351                                     DOM0_SHADOW_CONTROL_OP_PEEK,
  46.352 -                                   to_skip, nr_pfns, NULL, NULL) != nr_pfns ) 
  46.353 -            {
  46.354 -                ERROR("Error peeking shadow bitmap");
  46.355 +                                   to_skip, nr_pfns, NULL, NULL) != nr_pfns ){
  46.356 +                xcio_error(ioctxt, "Error peeking shadow bitmap");
  46.357                  goto out;
  46.358              }
  46.359       
  46.360 @@ -526,25 +506,26 @@ int xc_linux_save(int xc_handle,
  46.361              /* load pfn_type[] with the mfn of all the pages we're doing in
  46.362                 this batch. */
  46.363  
  46.364 -            for( batch = 0; batch < BATCH_SIZE && N < nr_pfns ; N++ )
  46.365 -            {
  46.366 +            for( batch = 0; batch < BATCH_SIZE && N < nr_pfns ; N++ ){
  46.367                  int n = permute(N, nr_pfns, order_nr );
  46.368  
  46.369                  if(0 && debug)
  46.370                      fprintf(stderr,"%d pfn= %08lx mfn= %08lx %d   "
  46.371                              "[mfn]= %08lx\n",
  46.372 -                            iter, n, live_pfn_to_mfn_table[n],
  46.373 +                            iter, (unsigned long)n, live_pfn_to_mfn_table[n],
  46.374                              test_bit(n,to_send),
  46.375                              live_mfn_to_pfn_table[
  46.376                                  live_pfn_to_mfn_table[n]&0xFFFFF]);
  46.377  
  46.378 -                if (!last_iter && test_bit(n, to_send) && test_bit(n, to_skip))
  46.379 +                if (!last_iter && test_bit(n, to_send) && test_bit(n, to_skip)){
  46.380                      skip_this_iter++; /* stats keeping */
  46.381 +                }
  46.382  
  46.383                  if (! ( (test_bit(n, to_send) && !test_bit(n, to_skip)) ||
  46.384                          (test_bit(n, to_send) && last_iter) ||
  46.385 -                        (test_bit(n, to_fix)  && last_iter) )   )
  46.386 +                        (test_bit(n, to_fix)  && last_iter) )   ){
  46.387                      continue;
  46.388 +                }
  46.389  
  46.390                  /* we get here if:
  46.391                     1. page is marked to_send & hasn't already been re-dirtied
  46.392 @@ -555,8 +536,7 @@ int xc_linux_save(int xc_handle,
  46.393                  pfn_batch[batch] = n;
  46.394                  pfn_type[batch] = live_pfn_to_mfn_table[n];
  46.395  
  46.396 -                if( pfn_type[batch] == 0x80000004 )
  46.397 -                {
  46.398 +                if( pfn_type[batch] == 0x80000004 ){
  46.399                      /* not currently in pusedo-physical map -- set bit
  46.400                         in to_fix that we must send this page in last_iter
  46.401                         unless its sent sooner anyhow */
  46.402 @@ -570,8 +550,7 @@ int xc_linux_save(int xc_handle,
  46.403                  }
  46.404  
  46.405                  if ( last_iter && test_bit(n, to_fix) && 
  46.406 -                     !test_bit(n, to_send) )
  46.407 -                {
  46.408 +                     !test_bit(n, to_send) ){
  46.409                      needed_to_fix++;
  46.410                      DPRINTF("Fix! iter %d, pfn %lx. mfn %lx\n",
  46.411                              iter,n,pfn_type[batch]);
  46.412 @@ -584,33 +563,30 @@ int xc_linux_save(int xc_handle,
  46.413       
  46.414              DDPRINTF("batch %d:%d (n=%d)\n",iter,batch,n);
  46.415  
  46.416 -            if ( batch == 0 ) 
  46.417 +            if ( batch == 0 ){
  46.418                  goto skip; /* very unlikely */
  46.419 +            }
  46.420        
  46.421              if ( (region_base = mfn_mapper_map_batch(xc_handle, domid, 
  46.422                                                       PROT_READ,
  46.423                                                       pfn_type,
  46.424 -                                                     batch)) == 0 )
  46.425 -            {
  46.426 -                PERROR("map batch failed");
  46.427 +                                                     batch)) == 0 ){
  46.428 +                xcio_perror(ioctxt, "map batch failed");
  46.429                  goto out;
  46.430              }
  46.431       
  46.432 -            if ( get_pfn_type_batch(xc_handle, domid, batch, pfn_type) )
  46.433 -            {
  46.434 -                ERROR("get_pfn_type_batch failed");
  46.435 +            if ( get_pfn_type_batch(xc_handle, domid, batch, pfn_type) ){
  46.436 +                xcio_error(ioctxt, "get_pfn_type_batch failed");
  46.437                  goto out;
  46.438              }
  46.439       
  46.440 -            for ( j = 0; j < batch; j++ )
  46.441 -            {
  46.442 -                if ( (pfn_type[j] & LTAB_MASK) == XTAB )
  46.443 -                {
  46.444 +            for ( j = 0; j < batch; j++ ){
  46.445 +                if ( (pfn_type[j] & LTAB_MASK) == XTAB ){
  46.446                      DDPRINTF("type fail: page %i mfn %08lx\n",j,pfn_type[j]);
  46.447                      continue;
  46.448                  }
  46.449    
  46.450 -                if ( 0 && debug )
  46.451 +                if ( 0 && debug ){
  46.452                      fprintf(stderr,"%d pfn= %08lx mfn= %08lx "
  46.453                              "[mfn]= %08lx sum= %08lx\n",
  46.454                              iter, 
  46.455 @@ -619,6 +595,7 @@ int xc_linux_save(int xc_handle,
  46.456                              live_mfn_to_pfn_table[pfn_type[j]&(~LTAB_MASK)],
  46.457                              csum_page(region_base + (PAGE_SIZE*j))
  46.458                          );
  46.459 +                }
  46.460  
  46.461                  /* canonicalise mfn->pfn */
  46.462                  pfn_type[j] = (pfn_type[j] & LTAB_MASK) |
  46.463 @@ -626,32 +603,27 @@ int xc_linux_save(int xc_handle,
  46.464              }
  46.465  
  46.466       
  46.467 -            if ( (*writerfn)(writerst, &batch, sizeof(int) ) )
  46.468 -            {
  46.469 -                ERROR("Error when writing to state file (2)");
  46.470 +            if ( xcio_write(ioctxt, &batch, sizeof(int) ) ){
  46.471 +                xcio_error(ioctxt, "Error when writing to state file (2)");
  46.472                  goto out;
  46.473              }
  46.474  
  46.475 -            if ( (*writerfn)(writerst, pfn_type, sizeof(unsigned long)*j ) )
  46.476 -            {
  46.477 -                ERROR("Error when writing to state file (3)");
  46.478 +            if ( xcio_write(ioctxt, pfn_type, sizeof(unsigned long)*j ) ){
  46.479 +                xcio_error(ioctxt, "Error when writing to state file (3)");
  46.480                  goto out;
  46.481              }
  46.482       
  46.483              /* entering this loop, pfn_type is now in pfns (Not mfns) */
  46.484 -            for( j = 0; j < batch; j++ )
  46.485 -            {
  46.486 +            for( j = 0; j < batch; j++ ){
  46.487                  /* write out pages in batch */
  46.488    
  46.489 -                if( (pfn_type[j] & LTAB_MASK) == XTAB)
  46.490 -                {
  46.491 +                if( (pfn_type[j] & LTAB_MASK) == XTAB){
  46.492                      DDPRINTF("SKIP BOGUS page %i mfn %08lx\n",j,pfn_type[j]);
  46.493                      continue;
  46.494                  }
  46.495    
  46.496                  if ( ((pfn_type[j] & LTAB_MASK) == L1TAB) || 
  46.497 -                     ((pfn_type[j] & LTAB_MASK) == L2TAB) )
  46.498 -                {
  46.499 +                     ((pfn_type[j] & LTAB_MASK) == L2TAB) ){
  46.500        
  46.501                      memcpy(page, region_base + (PAGE_SIZE*j), PAGE_SIZE);
  46.502        
  46.503 @@ -659,8 +631,7 @@ int xc_linux_save(int xc_handle,
  46.504                            k < (((pfn_type[j] & LTAB_MASK) == L2TAB) ? 
  46.505                                 (HYPERVISOR_VIRT_START >> L2_PAGETABLE_SHIFT) : 
  46.506                                 1024); 
  46.507 -                          k++ )
  46.508 -                    {
  46.509 +                          k++ ){
  46.510                          unsigned long pfn;
  46.511  
  46.512                          if ( !(page[k] & _PAGE_PRESENT) ) continue;
  46.513 @@ -683,20 +654,16 @@ int xc_linux_save(int xc_handle,
  46.514                          page[k] |= pfn << PAGE_SHIFT;
  46.515                      } /* end of page table rewrite for loop */
  46.516        
  46.517 -                    if ( (*writerfn)(writerst, page, PAGE_SIZE) )
  46.518 -                    {
  46.519 -                        ERROR("Error when writing to state file (4)");
  46.520 +                    if ( xcio_write(ioctxt, page, PAGE_SIZE) ){
  46.521 +                        xcio_error(ioctxt, "Error when writing to state file (4)");
  46.522                          goto out;
  46.523                      }
  46.524        
  46.525 -                }  /* end of it's a PT page */
  46.526 -                else
  46.527 -                {  /* normal page */
  46.528 +                }  /* end of it's a PT page */ else {  /* normal page */
  46.529  
  46.530 -                    if ( (*writerfn)(writerst, region_base + (PAGE_SIZE*j), 
  46.531 -                                     PAGE_SIZE) )
  46.532 -                    {
  46.533 -                        ERROR("Error when writing to state file (5)");
  46.534 +                    if ( xcio_write(ioctxt, region_base + (PAGE_SIZE*j), 
  46.535 +                                     PAGE_SIZE) ){
  46.536 +                        xcio_error(ioctxt, "Error when writing to state file (5)");
  46.537                          goto out;
  46.538                      }
  46.539                  }
  46.540 @@ -712,40 +679,35 @@ int xc_linux_save(int xc_handle,
  46.541  
  46.542          total_sent += sent_this_iter;
  46.543  
  46.544 -        verbose_printf("\r %d: sent %d, skipped %d, ", 
  46.545 +        xcio_info(ioctxt, "\r %d: sent %d, skipped %d, ", 
  46.546                         iter, sent_this_iter, skip_this_iter );
  46.547  
  46.548 -        if ( last_iter )
  46.549 -        {
  46.550 +        if ( last_iter ){
  46.551              track_cpu_usage( xc_handle, domid, 0, sent_this_iter, 0, 1);
  46.552 -
  46.553 -            verbose_printf("Total pages sent= %d (%.2fx)\n", 
  46.554 +            xcio_info(ioctxt, "Total pages sent= %d (%.2fx)\n", 
  46.555                             total_sent, ((float)total_sent)/nr_pfns );
  46.556 -            verbose_printf("(of which %d were fixups)\n", needed_to_fix  );
  46.557 +            xcio_info(ioctxt, "(of which %d were fixups)\n", needed_to_fix  );
  46.558          }       
  46.559  
  46.560 -        if ( debug && last_iter )
  46.561 -        {
  46.562 +        if (last_iter && debug){
  46.563              int minusone = -1;
  46.564              memset( to_send, 0xff, nr_pfns/8 );
  46.565              debug = 0;
  46.566              printf("Entering debug resend-all mode\n");
  46.567      
  46.568              /* send "-1" to put receiver into debug mode */
  46.569 -            if ( (*writerfn)(writerst, &minusone, sizeof(int)) )
  46.570 +            if ( xcio_write(ioctxt, &minusone, sizeof(int)) )
  46.571              {
  46.572 -                ERROR("Error when writing to state file (6)");
  46.573 +                xcio_error(ioctxt, "Error when writing to state file (6)");
  46.574                  goto out;
  46.575              }
  46.576  
  46.577              continue;
  46.578          }
  46.579  
  46.580 -        if ( last_iter )
  46.581 -            break;
  46.582 +        if ( last_iter ) break;
  46.583  
  46.584 -        if ( live )
  46.585 -        {
  46.586 +        if ( live ) {
  46.587              if ( (iter >= max_iters) || 
  46.588                   (sent_this_iter+skip_this_iter < 50) || 
  46.589                   (total_sent > nr_pfns*max_factor) )
  46.590 @@ -761,7 +723,7 @@ int xc_linux_save(int xc_handle,
  46.591                                      to_send, nr_pfns, &faults_this_iter,
  46.592                                      &dirtied_this_iter) != nr_pfns ) 
  46.593              {
  46.594 -                ERROR("Error flushing shadow PT");
  46.595 +                xcio_error(ioctxt, "Error flushing shadow PT");
  46.596                  goto out;
  46.597              }
  46.598  
  46.599 @@ -781,9 +743,9 @@ int xc_linux_save(int xc_handle,
  46.600      rc = 0;
  46.601      
  46.602      /* Zero terminate */
  46.603 -    if ( (*writerfn)(writerst, &rc, sizeof(int)) )
  46.604 +    if ( xcio_write(ioctxt, &rc, sizeof(int)) )
  46.605      {
  46.606 -        ERROR("Error when writing to state file (6)");
  46.607 +        xcio_error(ioctxt, "Error when writing to state file (6)");
  46.608          goto out;
  46.609      }
  46.610  
  46.611 @@ -794,50 +756,42 @@ int xc_linux_save(int xc_handle,
  46.612      if ( (do_dom0_op(xc_handle, &op) < 0) || 
  46.613           ((u32)op.u.getdomaininfo.domain != domid) )
  46.614      {
  46.615 -        PERROR("Could not get info on domain");
  46.616 +        xcio_perror(ioctxt, "Could not get info on domain");
  46.617          goto out;
  46.618      }
  46.619  
  46.620      /* Canonicalise the suspend-record frame number. */
  46.621 -    if ( !translate_mfn_to_pfn(&ctxt.cpu_ctxt.esi) )
  46.622 -    {
  46.623 -        ERROR("State record is not in range of pseudophys map");
  46.624 +    if ( !translate_mfn_to_pfn(&ctxt.cpu_ctxt.esi) ){
  46.625 +        xcio_error(ioctxt, "State record is not in range of pseudophys map");
  46.626          goto out;
  46.627      }
  46.628  
  46.629      /* Canonicalise each GDT frame number. */
  46.630 -    for ( i = 0; i < ctxt.gdt_ents; i += 512 )
  46.631 -    {
  46.632 -        if ( !translate_mfn_to_pfn(&ctxt.gdt_frames[i]) )
  46.633 -        {
  46.634 -            ERROR("GDT frame is not in range of pseudophys map");
  46.635 +    for ( i = 0; i < ctxt.gdt_ents; i += 512 ) {
  46.636 +        if ( !translate_mfn_to_pfn(&ctxt.gdt_frames[i]) ) {
  46.637 +            xcio_error(ioctxt, "GDT frame is not in range of pseudophys map");
  46.638              goto out;
  46.639          }
  46.640      }
  46.641  
  46.642      /* Canonicalise the page table base pointer. */
  46.643 -    if ( !MFN_IS_IN_PSEUDOPHYS_MAP(ctxt.pt_base >> PAGE_SHIFT) )
  46.644 -    {
  46.645 -        ERROR("PT base is not in range of pseudophys map");
  46.646 +    if ( !MFN_IS_IN_PSEUDOPHYS_MAP(ctxt.pt_base >> PAGE_SHIFT) ) {
  46.647 +        xcio_error(ioctxt, "PT base is not in range of pseudophys map");
  46.648          goto out;
  46.649      }
  46.650      ctxt.pt_base = live_mfn_to_pfn_table[ctxt.pt_base >> PAGE_SHIFT] << 
  46.651          PAGE_SHIFT;
  46.652  
  46.653 -    if ( (*writerfn)(writerst, &ctxt,       sizeof(ctxt)) ||
  46.654 -         (*writerfn)(writerst, live_shinfo, PAGE_SIZE) )
  46.655 -    {
  46.656 -        ERROR("Error when writing to state file (1)");
  46.657 +    if ( xcio_write(ioctxt, &ctxt,       sizeof(ctxt)) ||
  46.658 +         xcio_write(ioctxt, live_shinfo, PAGE_SIZE) ) {
  46.659 +        xcio_error(ioctxt, "Error when writing to state file (1)");
  46.660          goto out;
  46.661      }
  46.662      munmap(live_shinfo, PAGE_SIZE);
  46.663  
  46.664   out:
  46.665 -    if ( pfn_type != NULL )
  46.666 -        free(pfn_type);
  46.667 -
  46.668 +    if ( pfn_type != NULL ) free(pfn_type);
  46.669      DPRINTF("Save exit rc=%d\n",rc);
  46.670 -    
  46.671      return !!rc;
  46.672  
  46.673  }
    47.1 --- a/tools/xc/lib/xc_private.h	Mon Jun 28 08:17:15 2004 +0000
    47.2 +++ b/tools/xc/lib/xc_private.h	Mon Jun 28 15:03:15 2004 +0000
    47.3 @@ -136,6 +136,8 @@ int close_pfn_mapper(int pm_handle);
    47.4  void *map_pfn_writeable(int pm_handle, unsigned long pfn);
    47.5  void *map_pfn_readonly(int pm_handle, unsigned long pfn);
    47.6  void unmap_pfn(int pm_handle, void *vaddr);
    47.7 +int get_pfn_type_batch(int xc_handle, u32 dom, int num, unsigned long *arr);
    47.8 +unsigned long csum_page (void * page);
    47.9  
   47.10  /*
   47.11   * MMU updates.
   47.12 @@ -202,4 +204,5 @@ void * mfn_mapper_queue_entry(mfn_mapper
   47.13  
   47.14  long long  xc_domain_get_cpu_usage( int xc_handle, domid_t domid );
   47.15  
   47.16 +#include "xc_io.h"
   47.17  #endif /* __XC_PRIVATE_H__ */
    48.1 --- a/tools/xc/py/Xc.c	Mon Jun 28 08:17:15 2004 +0000
    48.2 +++ b/tools/xc/py/Xc.c	Mon Jun 28 15:03:15 2004 +0000
    48.3 @@ -14,6 +14,8 @@
    48.4  #include <sys/socket.h>
    48.5  #include <netdb.h>
    48.6  #include <arpa/inet.h>
    48.7 +#include "xc_private.h"
    48.8 +#include "gzip_stream.h"
    48.9  
   48.10  /* Needed for Python versions earlier than 2.3. */
   48.11  #ifndef PyMODINIT_FUNC
   48.12 @@ -189,115 +191,31 @@ static PyObject *pyxc_domain_getinfo(PyO
   48.13      return list;
   48.14  }
   48.15  
   48.16 -static PyObject *tcp_save(XcObject *xc, u32 dom, char *url, unsigned flags){
   48.17 -#define max_namelen 64
   48.18 -    char server[max_namelen];
   48.19 -    char *port_s;
   48.20 -    int port=777;
   48.21 -    int sd = -1;
   48.22 -    struct hostent *h;
   48.23 -    struct sockaddr_in s;
   48.24 -    int sockbufsize;
   48.25 +static int file_save(XcObject *xc, XcIOContext *ctxt, char *state_file){
   48.26      int rc = -1;
   48.27 -    
   48.28 -    int writerfn(void *fd, const void *buf, size_t count) {
   48.29 -        int tot = 0, rc;
   48.30 -        do {
   48.31 -            rc = write( (int) fd, ((char*)buf)+tot, count-tot );
   48.32 -            if ( rc < 0 ) { perror("WRITE"); return rc; };
   48.33 -            tot += rc;
   48.34 -        }
   48.35 -        while ( tot < count );
   48.36 -        return 0;
   48.37 -    }
   48.38 -    
   48.39 -    strncpy( server, url+strlen("tcp://"), max_namelen);
   48.40 -    server[max_namelen-1]='\0';
   48.41 -    if ( (port_s = strchr(server,':')) != NULL ) {
   48.42 -        *port_s = '\0';
   48.43 -        port = atoi(port_s+1);
   48.44 -    }
   48.45 -    printf("X server=%s port=%d\n",server,port);
   48.46 -    h = gethostbyname(server);
   48.47 -    sd = socket(AF_INET, SOCK_STREAM,0);
   48.48 -    if (sd < 0) goto serr;
   48.49 -    s.sin_family = AF_INET;
   48.50 -    bcopy ( h->h_addr, &(s.sin_addr.s_addr), h->h_length);
   48.51 -    s.sin_port = htons(port);
   48.52 -    if ( connect(sd, (struct sockaddr *) &s, sizeof(s)) ) goto serr;
   48.53 -    sockbufsize=128*1024;
   48.54 -    if ( setsockopt(sd, SOL_SOCKET, SO_SNDBUF, &sockbufsize, sizeof sockbufsize) < 0 ) goto serr;
   48.55 -
   48.56 -    if ( xc_linux_save(xc->xc_handle, dom, flags, writerfn, (void*)sd) == 0 ) {
   48.57 -        if ( read( sd, &rc, sizeof(int) ) != sizeof(int) ) goto serr;
   48.58 -  
   48.59 -        if ( rc == 0 ) {
   48.60 -                printf("Migration succesful -- destroy local copy\n");
   48.61 -                xc_domain_destroy(xc->xc_handle, dom);
   48.62 -                close(sd);
   48.63 -                Py_INCREF(zero);
   48.64 -                return zero;
   48.65 -        } else {
   48.66 -            errno = rc;
   48.67 -        }
   48.68 -    }
   48.69 +    int fd = -1;
   48.70 +    int open_flags = (O_CREAT | O_EXCL | O_WRONLY);
   48.71 +    int open_mode = 0644;
   48.72  
   48.73 -  serr:
   48.74 -    printf("Migration failed -- restart local copy\n");
   48.75 -    xc_domain_unpause(xc->xc_handle, dom);
   48.76 -    PyErr_SetFromErrno(xc_error);
   48.77 -    if ( sd >= 0 ) close(sd);
   48.78 -    return NULL;
   48.79 -
   48.80 -}
   48.81 -
   48.82 -static PyObject *file_save(XcObject *xc, u32 dom, char *state_file, unsigned flags){
   48.83 -        int fd = -1;
   48.84 -        gzFile gfd = NULL;
   48.85 -
   48.86 -        int writerfn(void *fd, const void *buf, size_t count) {
   48.87 -            int rc;
   48.88 -            while ( ((rc = gzwrite( (gzFile*)fd, (void*)buf, count)) == -1) && 
   48.89 -                    (errno = EINTR) )
   48.90 -                continue;
   48.91 -            return ! (rc == count);
   48.92 -        }
   48.93 -
   48.94 -        if (strncmp(state_file,"file:",strlen("file:")) == 0){
   48.95 -            state_file += strlen("file:");
   48.96 -        }
   48.97 -
   48.98 -        if ( (fd = open(state_file, O_CREAT|O_EXCL|O_WRONLY, 0644)) == -1 ) {
   48.99 -            perror("Could not open file for writing");
  48.100 -            goto err;
  48.101 -        }
  48.102 -        /*
  48.103 -         * Compression rate 1: we want speed over compression. 
  48.104 -         * We're mainly going for those zero pages, after all.
  48.105 -         */
  48.106 -        if ( (gfd = gzdopen(fd, "wb1")) == NULL ) {
  48.107 -            perror("Could not allocate compression state for state file");
  48.108 -            close(fd);
  48.109 -            goto err;
  48.110 -        }
  48.111 -        if ( xc_linux_save(xc->xc_handle, dom, flags, writerfn, gfd) == 0 ) {
  48.112 -            /* kill domain. We don't want to do this for checkpointing, but
  48.113 -               if we don't do it here I think people will hurt themselves
  48.114 -               by accident... */
  48.115 -            xc_domain_destroy(xc->xc_handle, dom);
  48.116 -            gzclose(gfd);
  48.117 -            close(fd);
  48.118 -
  48.119 -            Py_INCREF(zero);
  48.120 -            return zero;
  48.121 -        }
  48.122 -
  48.123 -    err:
  48.124 -        PyErr_SetFromErrno(xc_error);
  48.125 -        if ( gfd != NULL ) gzclose(gfd);
  48.126 -        if ( fd >= 0 ) close(fd);
  48.127 -        unlink(state_file);
  48.128 -        return NULL;
  48.129 +    fd = open(state_file, open_flags, open_mode);
  48.130 +    if(fd < 0){
  48.131 +        xcio_perror(ctxt, "Could not open file for writing");
  48.132 +        goto exit;
  48.133 +    }
  48.134 +    /* Compression rate 1: we want speed over compression. 
  48.135 +     * We're mainly going for those zero pages, after all.
  48.136 +     */
  48.137 +    ctxt->io = gzip_stream_fdopen(fd, "wb1");
  48.138 +    if(!ctxt->io){
  48.139 +        xcio_perror(ctxt, "Could not allocate compression state");
  48.140 +        goto exit;
  48.141 +    }
  48.142 +    rc = xc_linux_save(xc->xc_handle, ctxt);
  48.143 +  exit:
  48.144 +    if(ctxt->io) IOStream_close(ctxt->io);
  48.145 +    if(fd >= 0) close(fd);
  48.146 +    unlink(state_file);
  48.147 +    return rc;
  48.148  }
  48.149  
  48.150  static PyObject *pyxc_linux_save(PyObject *self,
  48.151 @@ -306,195 +224,92 @@ static PyObject *pyxc_linux_save(PyObjec
  48.152  {
  48.153      XcObject *xc = (XcObject *)self;
  48.154  
  48.155 -    u32   dom;
  48.156 +    u32 dom;
  48.157      char *state_file;
  48.158 -    int   progress = 1, live = -1, debug = 0;
  48.159 +    int progress = 1, debug = 0;
  48.160      unsigned int flags = 0;
  48.161      PyObject *val = NULL;
  48.162 -
  48.163 -    static char *kwd_list[] = { "dom", "state_file", "progress", 
  48.164 -                                "live", "debug", NULL };
  48.165 +    int rc = -1;
  48.166 +    XcIOContext ioctxt = { .info = iostdout, .err = iostderr };
  48.167  
  48.168 -    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "is|iii", kwd_list, 
  48.169 -                                      &dom, &state_file, &progress, 
  48.170 -                                      &live, &debug) )
  48.171 -        goto exit;
  48.172 +    static char *kwd_list[] = { "dom", "state_file", "vmconfig", "progress", "debug", NULL };
  48.173  
  48.174 -    if (progress)  flags |= XCFLAGS_VERBOSE;
  48.175 -    if (live == 1) flags |= XCFLAGS_LIVE;
  48.176 -    if (debug)     flags |= XCFLAGS_DEBUG;
  48.177 -
  48.178 -    if ( strncmp(state_file,"tcp:", strlen("tcp:")) == 0 ) {
  48.179 -        /* default to live for tcp */
  48.180 -        if (live == -1) flags |= XCFLAGS_LIVE;
  48.181 -        val = tcp_save(xc, dom, state_file, flags);
  48.182 -    } else {
  48.183 -        val = file_save(xc, dom, state_file, flags);
  48.184 +    if (!PyArg_ParseTupleAndKeywords(args, kwds, "is|siii", kwd_list, 
  48.185 +                                     &ioctxt.domain,
  48.186 +                                     &state_file,
  48.187 +                                     &ioctxt.vmconfig,
  48.188 +                                     &progress, 
  48.189 +                                     &debug)){
  48.190 +        goto exit;
  48.191      }
  48.192 +    ioctxt.vmconfig_n = (ioctxt.vmconfig ? strlen(ioctxt.vmconfig) : 0);
  48.193 +    if (progress)  ioctxt.flags |= XCFLAGS_VERBOSE;
  48.194 +    if (debug)     ioctxt.flags |= XCFLAGS_DEBUG;
  48.195 +    if(!state_file || state_file[0] == '\0') goto exit;
  48.196 +    rc = file_save(xc, &ioctxt, state_file);
  48.197 +    if(rc){
  48.198 +        PyErr_SetFromErrno(xc_error);
  48.199 +        goto exit;
  48.200 +    } 
  48.201 +    //xc_domain_destroy(xc->xc_handle, dom);
  48.202 +    Py_INCREF(zero);
  48.203 +    val = zero;
  48.204    exit:
  48.205      return val;
  48.206  }
  48.207  
  48.208 +
  48.209 +static int file_restore(XcObject *xc, XcIOContext *ioctxt, char *state_file){
  48.210 +    int rc = -1;
  48.211 +
  48.212 +    ioctxt->io = gzip_stream_fopen(state_file, "rb");
  48.213 +    if (!ioctxt->io) {
  48.214 +        xcio_perror(ioctxt, "Could not open file for reading");
  48.215 +        goto exit;
  48.216 +    }
  48.217 +
  48.218 +    rc = xc_linux_restore(xc->xc_handle, ioctxt);
  48.219 +  exit:
  48.220 +    if(ioctxt->io) IOStream_close(ioctxt->io);
  48.221 +    return rc;
  48.222 +}
  48.223 +
  48.224  static PyObject *pyxc_linux_restore(PyObject *self,
  48.225                                      PyObject *args,
  48.226                                      PyObject *kwds)
  48.227  {
  48.228      XcObject *xc = (XcObject *)self;
  48.229 -
  48.230 -    char        *state_file;
  48.231 -    int          progress = 1;
  48.232 -    u32          dom;
  48.233 -    unsigned int flags = 0;
  48.234 -
  48.235 -    static char *kwd_list[] = { "dom", "state_file", "progress", NULL };
  48.236 -
  48.237 -    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "is|i", kwd_list, 
  48.238 -                                      &dom, &state_file, &progress) )
  48.239 -        return NULL;
  48.240 -
  48.241 -    if ( progress )
  48.242 -        flags |= XCFLAGS_VERBOSE;
  48.243 -
  48.244 -    if ( strncmp(state_file,"tcp:", strlen("tcp:")) == 0 )
  48.245 -    {
  48.246 -#define max_namelen 64
  48.247 -        char server[max_namelen];
  48.248 -        char *port_s;
  48.249 -        int port=777;
  48.250 -        int ld = -1, sd = -1;
  48.251 -        struct hostent *h;
  48.252 -        struct sockaddr_in s, d, p;
  48.253 -        socklen_t dlen, plen;
  48.254 -        int sockbufsize;
  48.255 -        int on = 1, rc = -1;
  48.256 +    char *state_file;
  48.257 +    int progress = 1, debug = 0;
  48.258 +    u32 dom;
  48.259 +    PyObject *val = NULL;
  48.260 +    XcIOContext ioctxt = { .info = iostdout, .err = iostderr };
  48.261 +    int rc =-1;
  48.262  
  48.263 -        int readerfn(void *fd, void *buf, size_t count)
  48.264 -        {
  48.265 -            int rc, tot = 0;
  48.266 -            do { 
  48.267 -                rc = read( (int) fd, ((char*)buf)+tot, count-tot ); 
  48.268 -                if ( rc < 0 ) { perror("READ"); return rc; }
  48.269 -                if ( rc == 0 ) { printf("read: need %d, tot=%d got zero\n",
  48.270 -                                        count-tot, tot); return -1; }
  48.271 -                tot += rc;
  48.272 -            } 
  48.273 -            while ( tot < count );
  48.274 -            return 0;
  48.275 -        }
  48.276 -
  48.277 -        strncpy( server, state_file+strlen("tcp://"), max_namelen);
  48.278 -        server[max_namelen-1]='\0';
  48.279 -        if ( (port_s = strchr(server,':')) != NULL )
  48.280 -        {
  48.281 -            *port_s = '\0';
  48.282 -            port = atoi(port_s+1);
  48.283 -        }
  48.284 -
  48.285 -        printf("X server=%s port=%d\n",server,port);
  48.286 - 
  48.287 -        h = gethostbyname(server);
  48.288 -        ld = socket (AF_INET,SOCK_STREAM,0);
  48.289 -        if ( ld < 0 ) goto serr;
  48.290 -        s.sin_family = AF_INET;
  48.291 -        s.sin_addr.s_addr = htonl(INADDR_ANY);
  48.292 -        s.sin_port = htons(port);
  48.293 -
  48.294 -        if ( setsockopt(ld, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0 )
  48.295 -            goto serr;
  48.296 -
  48.297 -        if ( bind(ld, (struct sockaddr *) &s, sizeof(s)) ) 
  48.298 -            goto serr;
  48.299 -
  48.300 -        if ( listen(ld, 1) )
  48.301 -            goto serr;
  48.302 -
  48.303 -        dlen=sizeof(struct sockaddr);
  48.304 -        if ( (sd = accept(ld, (struct sockaddr *) &d, &dlen )) < 0 )
  48.305 -            goto serr;
  48.306 -
  48.307 -        plen = sizeof(p);
  48.308 -        if ( getpeername(sd, (struct sockaddr_in *) &p, 
  48.309 -                         &plen) < 0 )
  48.310 -            goto serr;
  48.311 +    static char *kwd_list[] = { "state_file", "progress", "debug", NULL };
  48.312  
  48.313 -        printf("Accepted connection from %s\n", inet_ntoa(p.sin_addr));
  48.314 - 
  48.315 -        sockbufsize=128*1024;
  48.316 -        if ( setsockopt(sd, SOL_SOCKET, SO_SNDBUF, &sockbufsize, 
  48.317 -                        sizeof sockbufsize) < 0 ) 
  48.318 -            goto serr;
  48.319 -
  48.320 -        rc = xc_linux_restore(xc->xc_handle, dom, flags, 
  48.321 -                              readerfn, (void*)sd, &dom);
  48.322 -
  48.323 -        write( sd, &rc, sizeof(int) ); 
  48.324 -
  48.325 -        if (rc == 0)
  48.326 -        {
  48.327 -            close(sd);
  48.328 -            Py_INCREF(zero);
  48.329 -            return zero;
  48.330 -        }
  48.331 -        errno = rc;
  48.332 -
  48.333 -    serr:
  48.334 -        PyErr_SetFromErrno(xc_error);
  48.335 -        if ( ld >= 0 ) close(ld);
  48.336 -        if ( sd >= 0 ) close(sd);
  48.337 -        return NULL;
  48.338 -    }    
  48.339 -    else
  48.340 -    {
  48.341 -        int fd = -1;
  48.342 -        gzFile gfd = NULL;
  48.343 +    if (!PyArg_ParseTupleAndKeywords(args, kwds, "is|ii", kwd_list, 
  48.344 +                                     &ioctxt.domain,
  48.345 +                                     &state_file,
  48.346 +                                     &progress,
  48.347 +                                     &debug)){
  48.348 +        goto exit;
  48.349 +    }
  48.350 +    if (progress) ioctxt.flags |= XCFLAGS_VERBOSE;
  48.351 +    if (debug)    ioctxt.flags |= XCFLAGS_DEBUG;
  48.352  
  48.353 -        int readerfn(void *fd, void *buf, size_t count)
  48.354 -        {
  48.355 -            int rc;
  48.356 -            while ( ((rc = gzread( (gzFile*)fd, (void*)buf, count)) == -1) && 
  48.357 -                    (errno = EINTR) )
  48.358 -                continue;
  48.359 -            return ! (rc == count);
  48.360 -        }
  48.361 -
  48.362 -        if ( strncmp(state_file,"file:",strlen("file:")) == 0 )
  48.363 -            state_file += strlen("file:");
  48.364 -
  48.365 -        if ( (fd = open(state_file, O_RDONLY)) == -1 )
  48.366 -        {
  48.367 -            perror("Could not open file for writing");
  48.368 -            goto err;
  48.369 -        }
  48.370 -
  48.371 -        /*
  48.372 -         * Compression rate 1: we want speed over compression. 
  48.373 -         * We're mainly going for those zero pages, after all.
  48.374 -         */
  48.375 -        if ( (gfd = gzdopen(fd, "rb")) == NULL )
  48.376 -        {
  48.377 -            perror("Could not allocate compression state for state file");
  48.378 -            close(fd);
  48.379 -            goto err;
  48.380 -        }
  48.381 -
  48.382 -
  48.383 -        if ( xc_linux_restore(xc->xc_handle, dom, flags, 
  48.384 -                              readerfn, gfd, &dom) == 0 )
  48.385 -        {
  48.386 -            gzclose(gfd);
  48.387 -            close(fd);
  48.388 -
  48.389 -            Py_INCREF(zero);
  48.390 -            return zero;
  48.391 -        }
  48.392 -
  48.393 -    err:
  48.394 +    if(!state_file || state_file[0] == '\0') goto exit;
  48.395 +    rc = file_restore(xc, &ioctxt, state_file);
  48.396 +    if(rc){
  48.397          PyErr_SetFromErrno(xc_error);
  48.398 -        if ( gfd != NULL ) gzclose(gfd);
  48.399 -        if ( fd >= 0 ) close(fd);
  48.400 -        return NULL;
  48.401 +        goto exit;
  48.402      }
  48.403 -
  48.404 +    val = Py_BuildValue("{s:i,s:s}",
  48.405 +                        "dom", ioctxt.domain,
  48.406 +                        "vmconfig", ioctxt.vmconfig);
  48.407 +    //? free(ioctxt.vmconfig);
  48.408 +  exit:
  48.409 +    return val;
  48.410  }
  48.411  
  48.412  static PyObject *pyxc_linux_build(PyObject *self,
    49.1 --- a/tools/xc/py/setup.py	Mon Jun 28 08:17:15 2004 +0000
    49.2 +++ b/tools/xc/py/setup.py	Mon Jun 28 15:03:15 2004 +0000
    49.3 @@ -3,12 +3,17 @@ from distutils.core import setup, Extens
    49.4  
    49.5  module = Extension("xc",
    49.6                     extra_compile_args   = ["-fno-strict-aliasing"],
    49.7 -                   include_dirs         = ["../lib"],
    49.8 -                   library_dirs         = ["../lib"],
    49.9 +                   include_dirs         = ["../lib",
   49.10 +                                           "../../../xen/include/hypervisor-ifs",
   49.11 +                                           "../../../linux-xen-sparse/include",
   49.12 +                                           "../../xu/lib",
   49.13 +                                           "../../lib" ],
   49.14 +                   library_dirs         = ["../lib",
   49.15 +                                           "../../lib" ],
   49.16                     libraries            = ["xc"],
   49.17                     sources              = ["Xc.c"])
   49.18  
   49.19  setup(name = "xc",
   49.20 -      version = "1.0",
   49.21 +      version = "2.0",
   49.22        ext_package = "xen.ext",
   49.23        ext_modules = [module])
    50.1 --- a/tools/xen/lib/xend/XendDomain.py	Mon Jun 28 08:17:15 2004 +0000
    50.2 +++ b/tools/xen/lib/xend/XendDomain.py	Mon Jun 28 15:03:15 2004 +0000
    50.3 @@ -235,7 +235,7 @@ class XendDomain:
    50.4      def domain_get(self, id):
    50.5          id = str(id)
    50.6          self.refresh_domain(id)
    50.7 -        return self.domain[id]
    50.8 +        return self.domain.get(id)
    50.9      
   50.10      def domain_unpause(self, id):
   50.11          """(Re)start domain running.
   50.12 @@ -278,22 +278,26 @@ class XendDomain:
   50.13          """
   50.14          # Need a cancel too?
   50.15          pass
   50.16 -    
   50.17 +
   50.18      def domain_save(self, id, dst, progress=0):
   50.19          """Save domain state to file, destroy domain.
   50.20          """
   50.21          dom = int(id)
   50.22 +        dominfo = self.domain_get(id)
   50.23 +        if not dominfo:
   50.24 +            return -1
   50.25 +        vmconfig = sxp.to_string(dominfo.sxpr())
   50.26          self.domain_pause(id)
   50.27          eserver.inject('xend.domain.save', id)
   50.28 -        rc = xc.linux_save(dom=dom, state_file=dst, progress=progress)
   50.29 +        rc = xc.linux_save(dom=dom, state_file=dst, vmconfig=vmconfig, progress=progress)
   50.30          if rc == 0:
   50.31              self.domain_destroy(id)
   50.32          return rc
   50.33      
   50.34 -    def domain_restore(self, src, config, progress=0):
   50.35 +    def domain_restore(self, src, progress=0):
   50.36          """Restore domain from file.
   50.37          """
   50.38 -        dominfo = XendDomainInfo.dom_restore(dom, config)
   50.39 +        dominfo = XendDomainInfo.vm_restore(src, progress=progress)
   50.40          self._add_domain(dominfo.id, dominfo)
   50.41          return dominfo
   50.42      
    51.1 --- a/tools/xen/lib/xend/XendDomainInfo.py	Mon Jun 28 08:17:15 2004 +0000
    51.2 +++ b/tools/xen/lib/xend/XendDomainInfo.py	Mon Jun 28 15:03:15 2004 +0000
    51.3 @@ -272,22 +272,23 @@ def vm_recreate(config, info):
    51.4          d.callback(vm)
    51.5      return d
    51.6  
    51.7 -def vm_restore(src, config, progress=0):
    51.8 +def vm_restore(src, progress=0):
    51.9      """Restore a VM from a disk image.
   51.10  
   51.11      src      saved state to restore
   51.12 -    config   configuration
   51.13      progress progress reporting flag
   51.14      returns  deferred
   51.15      raises   VmError for invalid configuration
   51.16      """
   51.17      vm = XendDomainInfo()
   51.18 -    vm.config = config
   51.19 -    ostype = "linux" #todo set from config
   51.20 +    ostype = "linux" #todo Set from somewhere (store in the src?).
   51.21      restorefn = getattr(xc, "%s_restore" % ostype)
   51.22 -    dom = restorefn(state_file=src, progress=progress)
   51.23 +    d = restorefn(state_file=src, progress=progress)
   51.24 +    dom = int(d['dom'])
   51.25      if dom < 0:
   51.26          raise VMError('restore failed')
   51.27 +    vmconfig = sxp.from_string(d['vmconfig'])
   51.28 +    vm.config = sxp.child_value(vmconfig, 'config')
   51.29      deferred = vm.dom_configure(dom)
   51.30      def vifs_cb(val, vm):
   51.31          vif_up(vm.ipaddrs)
   51.32 @@ -855,9 +856,7 @@ def vm_field_vfr(vm, config, val, index)
   51.33          if not ip:
   51.34              raise VmError('vfr: missing ip address')
   51.35          ipaddrs.append(ip);
   51.36 -        #Don't do this in new i/o model.
   51.37 -        #print 'vm_field_vfr> add rule', 'dom=', vm.dom, 'vif=', vif, 'ip=', ip
   51.38 -        #xenctl.ip.setup_vfr_rules_for_vif(vm.dom, vif, ip)
   51.39 +        # todo: Configure the ipaddrs.
   51.40      vm.ipaddrs = ipaddrs
   51.41  
   51.42  def vnet_bridge(vnet, vmac, dom, idx):
    52.1 --- a/tools/xen/lib/xend/server/SrvDomain.py	Mon Jun 28 08:17:15 2004 +0000
    52.2 +++ b/tools/xen/lib/xend/server/SrvDomain.py	Mon Jun 28 15:03:15 2004 +0000
    52.3 @@ -44,13 +44,6 @@ class SrvDomain(SrvDir):
    52.4          val = fn(req.args, {'dom': self.dom.id})
    52.5          return val
    52.6  
    52.7 -    def op_restore(self, op, req):
    52.8 -        fn = FormFn(self.xd.domain_restore,
    52.9 -                    [['dom', 'int'],
   52.10 -                     ['file', 'str']])
   52.11 -        val = fn(req.args, {'dom': self.dom.id})
   52.12 -        return val
   52.13 -        
   52.14      def op_migrate(self, op, req):
   52.15          fn = FormFn(self.xd.domain_migrate,
   52.16                      [['dom', 'int'],
    53.1 --- a/tools/xen/lib/xend/server/SrvDomainDir.py	Mon Jun 28 08:17:15 2004 +0000
    53.2 +++ b/tools/xen/lib/xend/server/SrvDomainDir.py	Mon Jun 28 15:03:15 2004 +0000
    53.3 @@ -7,6 +7,7 @@ from twisted.web import error
    53.4  
    53.5  from xen.xend import sxp
    53.6  from xen.xend import XendDomain
    53.7 +from xen.xend.Args import FormFn
    53.8  
    53.9  from SrvDir import SrvDir
   53.10  from SrvDomain import SrvDomain
   53.11 @@ -88,6 +89,12 @@ class SrvDomainDir(SrvDir):
   53.12              out.close()
   53.13              return val
   53.14  
   53.15 +    def op_restore(self, op, req):
   53.16 +        fn = FormFn(self.xd.domain_restore,
   53.17 +                    [['file', 'str']])
   53.18 +        val = fn(req.args)
   53.19 +        return val
   53.20 +        
   53.21      def render_POST(self, req):
   53.22          return self.perform(req)
   53.23  
   53.24 @@ -129,3 +136,9 @@ class SrvDomainDir(SrvDir):
   53.25          req.write('<button type="submit" name="op" value="create">Create Domain</button>')
   53.26          req.write('Config <input type="file" name="config"><br>')
   53.27          req.write('</form>')
   53.28 +        req.write('<form method="post" action="%s" enctype="multipart/form-data">'
   53.29 +                  % req.prePathURL())
   53.30 +        req.write('<button type="submit" name="op" value="create">Restore Domain</button>')
   53.31 +        req.write('State <input type="string" name="state"><br>')
   53.32 +        req.write('</form>')
   53.33 +        
    54.1 --- a/tools/xen/lib/xend/sxp.py	Mon Jun 28 08:17:15 2004 +0000
    54.2 +++ b/tools/xen/lib/xend/sxp.py	Mon Jun 28 15:03:15 2004 +0000
    54.3 @@ -16,6 +16,7 @@ import sys
    54.4  import types
    54.5  import errno
    54.6  import string
    54.7 +from StringIO import StringIO
    54.8  
    54.9  __all__ = [
   54.10      "mime_type", 
   54.11 @@ -521,6 +522,28 @@ def elements(sxpr, ctxt=None):
   54.12                  yield v
   54.13          i += 1
   54.14  
   54.15 +def to_string(sxpr):
   54.16 +    """Convert an sxpr to a string.
   54.17 +
   54.18 +    sxpr sxpr
   54.19 +    returns string
   54.20 +    """
   54.21 +    io = StringIO()
   54.22 +    sxp.show(sxpr, io)
   54.23 +    io.seek(0)
   54.24 +    val = io.getvalue()
   54.25 +    io.close()
   54.26 +    return val
   54.27 +
   54.28 +def from_string(str):
   54.29 +    """Create an sxpr by parsing a string.
   54.30 +
   54.31 +    str string
   54.32 +    returns sxpr
   54.33 +    """
   54.34 +    io = StringIO(str)
   54.35 +    return parse(io)
   54.36 +
   54.37  def parse(io):
   54.38      """Completely parse all input from 'io'.
   54.39  
    55.1 --- a/tools/xen/xend	Mon Jun 28 08:17:15 2004 +0000
    55.2 +++ b/tools/xen/xend	Mon Jun 28 15:03:15 2004 +0000
    55.3 @@ -13,8 +13,8 @@
    55.4  
    55.5     xend stop
    55.6  
    55.7 -   Unfortunately restarting it upsets the channel to dom0 and
    55.8 -   domain management stops working - needs a reboot to fix.
    55.9 +   The daemon should reconnect to device control interfaces
   55.10 +   and recover its state when restarted.
   55.11  """
   55.12  import os
   55.13  import sys