os/ossrv/genericopenlibs/liboil/src/liboilfunction.c
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/ossrv/genericopenlibs/liboil/src/liboilfunction.c	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,606 @@
     1.4 +/*
     1.5 + * LIBOIL - Library of Optimized Inner Loops
     1.6 + * Copyright (c) 2003,2004 David A. Schleef <ds@schleef.org>
     1.7 + * All rights reserved.
     1.8 + *
     1.9 + * Redistribution and use in source and binary forms, with or without
    1.10 + * modification, are permitted provided that the following conditions
    1.11 + * are met:
    1.12 + * 1. Redistributions of source code must retain the above copyright
    1.13 + *    notice, this list of conditions and the following disclaimer.
    1.14 + * 2. Redistributions in binary form must reproduce the above copyright
    1.15 + *    notice, this list of conditions and the following disclaimer in the
    1.16 + *    documentation and/or other materials provided with the distribution.
    1.17 + * 
    1.18 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
    1.19 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    1.20 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    1.21 + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
    1.22 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    1.23 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    1.24 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    1.25 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    1.26 + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
    1.27 + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    1.28 + * POSSIBILITY OF SUCH DAMAGE.
    1.29 + */
    1.30 +//Portions Copyright (c)  2008-2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. 
    1.31 +
    1.32 +#ifdef HAVE_CONFIG_H
    1.33 +#include "config.h"
    1.34 +#endif
    1.35 +#include <liboil/liboildebug.h>
    1.36 +#include <liboil/liboilcpu.h>
    1.37 +#include <liboil/liboilfault.h>
    1.38 +#include <liboil/liboiltest.h>
    1.39 +
    1.40 +#include <stdio.h>
    1.41 +#include <string.h>
    1.42 +#include <stdlib.h>
    1.43 +#include <time.h>
    1.44 +
    1.45 +/**
    1.46 + * SECTION:liboilclass-unstable
    1.47 + * @title:OilFunctionClass
    1.48 + * @short_description: Functions for manipulating function classes
    1.49 + *
    1.50 + * <para>
    1.51 + * Functions operate on arrays of data.  The arrays can be either source
    1.52 + * arrays (input only), destination arrays (output only), or in-place
    1.53 + * arrays (both input and output).
    1.54 + * </para>
    1.55 + *
    1.56 + * <para>
    1.57 + * The interpretation of a parameter can usually be determined from its
    1.58 + * name.  Parameters for arrays are of the form d1_1xn, where the first
    1.59 + * character represents the direction (source, destination, or in-place),
    1.60 + * the second represents the index for that particular direction, and
    1.61 + * the characters after the underscore indicate the size of the array.
    1.62 + * In this case, "1xn" represents an array that is 1 by N.  Note that
    1.63 + * the index and the size can both be omitted, giving a default of 1
    1.64 + * for the index and 1xn for the size.
    1.65 + * </para>
    1.66 + *
    1.67 + * <para>
    1.68 + * Parameters that represent strides are of the form "d1s".  The
    1.69 + * interpretation is similar to above, except that the s indicates
    1.70 + * a stride parameter.
    1.71 + * </para>
    1.72 + *
    1.73 + * <para>
    1.74 + * The exceptions to the above rule are "dest", "src", "dstr", "sstr", etc.
    1.75 + * These are aliases for "d1", "s1", "d1s", and "s1s", respectively.  This
    1.76 + * form is deprecated and will be removed in the 0.4 series.
    1.77 + * </para>
    1.78 + *
    1.79 + * <para>
    1.80 + * Two special parameters are "n" and "m", which determine the size of
    1.81 + * the arrays in other parameters.
    1.82 + * </para>
    1.83 + *
    1.84 + * <para>
    1.85 + * Data arrays are laid out such that rows are separated by the number
    1.86 + * of bytes given by the corresponding stride.  Elements in each row
    1.87 + * are contiguous.  If there is no stride parameter corresponding to an
    1.88 + * array, the rows of the array are contiguous.
    1.89 + * </para>
    1.90 + */
    1.91 +
    1.92 +/**
    1.93 + * SECTION:liboilimpl-unstable
    1.94 + * @title:OilFunctionImpl
    1.95 + * @short_description: Functions for manipulating function implementations.
    1.96 + */
    1.97 +
    1.98 +
    1.99 +#ifndef __SYMBIAN32__
   1.100 +extern OilFunctionClass *_oil_function_class_array[];
   1.101 +extern OilFunctionImpl *_oil_function_impl_array[];
   1.102 +#else
   1.103 +extern OilFunctionClass** __oil_function_class_array(void);
   1.104 +extern OilFunctionImpl** __oil_function_impl_array(void);
   1.105 +#define _oil_function_class_array ((OilFunctionClass **)(__oil_function_class_array()))
   1.106 +#define _oil_function_impl_array ((OilFunctionImpl **)(__oil_function_impl_array()))
   1.107 +extern void init(void);
   1.108 +extern void init_impl(void);
   1.109 +#endif
   1.110 +
   1.111 +
   1.112 +static int _oil_n_function_impls;
   1.113 +static int _oil_n_function_classes;
   1.114 +
   1.115 +static void oil_init_pointers (void);
   1.116 +static void oil_init_structs (void);
   1.117 +
   1.118 +static char * xstrdup (const char *s);
   1.119 +
   1.120 +void _oil_cpu_init (void);
   1.121 +
   1.122 +/**
   1.123 + * SECTION:liboilinit
   1.124 + * @title: Intialization
   1.125 + * @short_description: Initialization functions
   1.126 + */
   1.127 +/**
   1.128 + * SECTION:liboilinit-unstable
   1.129 + * @title: Intialization
   1.130 + * @short_description: Initialization functions
   1.131 + */
   1.132 +/**
   1.133 + * oil_init:
   1.134 + *
   1.135 + * Initialize liboil.  This function must be called before any
   1.136 + * other liboil function is used.  oil_init() may be called multiple
   1.137 + * times.
   1.138 + *
   1.139 + * Since: 0.3.0
   1.140 + */
   1.141 +static int _oil_inited = 0;
   1.142 +
   1.143 +#ifdef __SYMBIAN32__
   1.144 +EXPORT_C
   1.145 +#endif
   1.146 +void
   1.147 +oil_init (void)
   1.148 +{
   1.149 +
   1.150 +  if (_oil_inited) return;
   1.151 +  _oil_inited = 1;
   1.152 +
   1.153 +	#ifdef	__SYMBIAN32__
   1.154 +  init();
   1.155 +  init_impl();	
   1.156 +  #endif
   1.157 +  
   1.158 +  srand(time(NULL));
   1.159 +
   1.160 +  _oil_debug_init ();
   1.161 +  _oil_cpu_init ();
   1.162 +  oil_init_pointers ();
   1.163 +  oil_init_structs ();
   1.164 +
   1.165 +  oil_optimize_all ();
   1.166 +
   1.167 +  OIL_INFO ("oil_init() finished");
   1.168 +}
   1.169 +
   1.170 +/**
   1.171 + * oil_init_no_optimize:
   1.172 + *
   1.173 + * Initialize liboil similar to oil_init(), but do not run the
   1.174 + * profiling stage.  This function is mainly useful for internal
   1.175 + * programs.
   1.176 + */
   1.177 +#ifdef __SYMBIAN32__
   1.178 +EXPORT_C
   1.179 +#endif
   1.180 +void
   1.181 +oil_init_no_optimize (void)
   1.182 +{
   1.183 +  if (_oil_inited) return;
   1.184 +  _oil_inited = 1;
   1.185 +
   1.186 +  srand(time(NULL));
   1.187 +
   1.188 +  _oil_debug_init ();
   1.189 +  _oil_cpu_init ();
   1.190 +  oil_init_pointers ();
   1.191 +  oil_init_structs ();
   1.192 +}
   1.193 +
   1.194 +/**
   1.195 + * oil_optimize_all:
   1.196 + *
   1.197 + * Optimize all function classes.
   1.198 + */
   1.199 + #ifdef __SYMBIAN32__
   1.200 +EXPORT_C 
   1.201 +#endif
   1.202 +void
   1.203 +oil_optimize_all (void)
   1.204 +{
   1.205 +  OilFunctionClass *klass;
   1.206 +  int i;
   1.207 +
   1.208 +  oil_fault_check_enable ();
   1.209 +  for (i = 0; i < _oil_n_function_classes; i++) {
   1.210 +    klass = oil_class_get_by_index (i);
   1.211 +
   1.212 +    oil_class_optimize (klass);
   1.213 +  }
   1.214 +  OIL_INFO("%d classes, %d implementations, %d enabled",
   1.215 +      _oil_n_function_classes, _oil_n_function_impls, 0);
   1.216 +  oil_fault_check_disable ();
   1.217 +}
   1.218 +
   1.219 +/**
   1.220 + * oil_optimize:
   1.221 + * @class_name: a string
   1.222 + *
   1.223 + * Optimize the function class that has the name specified by @class_name.
   1.224 + */
   1.225 +#ifdef __SYMBIAN32__
   1.226 +EXPORT_C 
   1.227 +#endif
   1.228 +void
   1.229 +oil_optimize (const char *class_name)
   1.230 +{
   1.231 +  OilFunctionClass *klass;
   1.232 +
   1.233 +  klass = oil_class_get (class_name);
   1.234 +  if (klass == NULL) {
   1.235 +    OIL_ERROR ("could not find class %s", class_name);
   1.236 +    return;
   1.237 +  }
   1.238 +
   1.239 +  oil_class_optimize (klass);
   1.240 +}
   1.241 +
   1.242 +/**
   1.243 + * oil_class_get_n_classes:
   1.244 + *
   1.245 + * Returns the number of function classes.
   1.246 + *
   1.247 + * Returns: the number of function classes
   1.248 + */
   1.249 +#ifdef __SYMBIAN32__
   1.250 +EXPORT_C
   1.251 +#endif
   1.252 +int
   1.253 +oil_class_get_n_classes (void)
   1.254 +{
   1.255 +  return _oil_n_function_classes;
   1.256 +}
   1.257 +
   1.258 +/**
   1.259 + * oil_class_get_by_index:
   1.260 + * @i: index
   1.261 + *
   1.262 + * Returns a pointer to the function class with index @i.
   1.263 + *
   1.264 + * Returns: an @OilFunctionClass
   1.265 + */
   1.266 + 
   1.267 +#ifdef __SYMBIAN32__
   1.268 +EXPORT_C  
   1.269 +#endif
   1.270 +OilFunctionClass *
   1.271 +oil_class_get_by_index (int i)
   1.272 +{
   1.273 +  if (i<0 || i>=_oil_n_function_classes) return NULL;
   1.274 +
   1.275 +  return _oil_function_class_array[i];
   1.276 +}
   1.277 +
   1.278 +/**
   1.279 + * oil_impl_is_runnable:
   1.280 + * @impl: an @OilFunctionImpl
   1.281 + *
   1.282 + * Determines whether the function implementation given by @impl
   1.283 + * can be executed by the current CPU.
   1.284 + *
   1.285 + * Returns: 1 if the implementation can be executed, otherwise 0
   1.286 + */
   1.287 +#ifdef __SYMBIAN32__
   1.288 +EXPORT_C  
   1.289 +#endif 
   1.290 +int
   1.291 +oil_impl_is_runnable (OilFunctionImpl *impl)
   1.292 +{
   1.293 +  unsigned int oil_cpu_flags = oil_cpu_get_flags();
   1.294 +
   1.295 +  if ((impl->flags & OIL_CPU_FLAG_MASK) & (~oil_cpu_flags))
   1.296 +    return 0;
   1.297 +  return 1;
   1.298 +}
   1.299 +
   1.300 +//#ifdef __SYMBIAN32__
   1.301 +//EXPORT_C unsigned long _oil_cpu_flags()
   1.302 +	//{
   1.303 +	//return &oil_cpu_flags;
   1.304 +	//}
   1.305 +//#endif
   1.306 +
   1.307 +/**
   1.308 + * oil_impl_is_usable:
   1.309 + * @impl: an @OilFunctionImpl
   1.310 + *
   1.311 + * Determines whether the function implementation given by @impl
   1.312 + * is useful, that is, it can be executed on the current CPU and
   1.313 + * passes tests.
   1.314 + *
   1.315 + * Returns: 1 if the implementation can be used, otherwise 0
   1.316 + */
   1.317 +#ifdef __SYMBIAN32__
   1.318 +EXPORT_C  
   1.319 +#endif
   1.320 +int
   1.321 +oil_impl_is_usable (OilFunctionImpl *impl)
   1.322 +{
   1.323 +  unsigned int oil_cpu_flags = oil_cpu_get_flags();
   1.324 +
   1.325 +  if ((impl->flags & OIL_CPU_FLAG_MASK) & (~oil_cpu_flags))
   1.326 +    return 0;
   1.327 +  if (impl->flags & OIL_IMPL_FLAG_DISABLED)
   1.328 +    return 0;
   1.329 +  return 1;
   1.330 +}
   1.331 +
   1.332 +/**
   1.333 + * oil_impl_get_by_index:
   1.334 + * @i: index
   1.335 + *
   1.336 + * Returns a pointer to the function implementation with index @i.
   1.337 + *
   1.338 + * Returns: a pointer to a function implementation structure
   1.339 + */
   1.340 +#ifdef __SYMBIAN32__
   1.341 +EXPORT_C  
   1.342 +#endif 
   1.343 +OilFunctionImpl *
   1.344 +oil_impl_get_by_index (int i)
   1.345 +{
   1.346 +  if (i<0 || i>=_oil_n_function_impls) return NULL;
   1.347 +
   1.348 +  return _oil_function_impl_array[i];
   1.349 +}
   1.350 +
   1.351 +/**
   1.352 + * oil_class_get:
   1.353 + * @class_name: the name of the function class
   1.354 + *
   1.355 + * Returns a pointer to the function class that has the given class
   1.356 + * name.  If no such class is found, NULL is returned.
   1.357 + *
   1.358 + * Returns: a pointer to a function class
   1.359 + */
   1.360 +#ifdef __SYMBIAN32__
   1.361 +EXPORT_C  
   1.362 +#endif
   1.363 +OilFunctionClass *
   1.364 +oil_class_get (const char *class_name)
   1.365 +{
   1.366 +  OilFunctionClass *klass;
   1.367 +  int i;
   1.368 +
   1.369 +  for (i = 0; i < _oil_n_function_classes; i++) {
   1.370 +    klass = oil_class_get_by_index (i);
   1.371 +
   1.372 +    if (strcmp (klass->name, class_name) == 0)
   1.373 +      return klass;
   1.374 +  }
   1.375 +  return NULL;
   1.376 +}
   1.377 +
   1.378 +/**
   1.379 + * oil_class_choose_by_name:
   1.380 + * @klass: a function class
   1.381 + * @name: the name of an implementation
   1.382 + *
   1.383 + * Sets the chosen implementation for the given function class to
   1.384 + * the implementation with the given name.  If no implementation
   1.385 + * having the given name is found, the chosen implementation is
   1.386 + * not changed.
   1.387 + */
   1.388 + #ifdef __SYMBIAN32__
   1.389 +EXPORT_C 
   1.390 +#endif
   1.391 +void
   1.392 +oil_class_choose_by_name (OilFunctionClass * klass, const char *name)
   1.393 +{
   1.394 +  OilFunctionImpl *impl;
   1.395 +
   1.396 +  for(impl = klass->first_impl; impl; impl = impl->next) {
   1.397 +    if (impl->name && strcmp (impl->name, name) == 0) {
   1.398 +      klass->chosen_impl = impl;
   1.399 +      klass->func = impl->func;
   1.400 +      return;
   1.401 +    }
   1.402 +  }
   1.403 +}
   1.404 +
   1.405 +/**
   1.406 + * oil_class_optimize:
   1.407 + * @klass: a function class
   1.408 + *
   1.409 + * Tests and profiles each implementation for the given function
   1.410 + * class.  Testing compares the output of running each implementation
   1.411 + * on random input against the reference implementation for the
   1.412 + * same input.
   1.413 + */
   1.414 +#ifdef __SYMBIAN32__
   1.415 +EXPORT_C  
   1.416 +#endif
   1.417 +void
   1.418 +oil_class_optimize (OilFunctionClass * klass)
   1.419 +{
   1.420 +  OilFunctionImpl *impl;
   1.421 +  OilFunctionImpl *min_impl;
   1.422 +  OilTest *test;
   1.423 +  int ret;
   1.424 +
   1.425 +  OIL_DEBUG ("optimizing class %s", klass->name);
   1.426 +
   1.427 +  if (klass->reference_impl == NULL) {
   1.428 +    OIL_ERROR ("class %s has no reference implmentation", klass->name);
   1.429 +    return;
   1.430 +  }
   1.431 +  if (klass->first_impl == NULL) {
   1.432 +    OIL_ERROR ("class %s has no implmentations", klass->name);
   1.433 +    return;
   1.434 +  }
   1.435 +
   1.436 +  test = oil_test_new (klass);
   1.437 +  if (test == NULL) {
   1.438 +    OIL_ERROR ("failed to test function class %s", klass->name);
   1.439 +    return;
   1.440 +  }
   1.441 +
   1.442 +  min_impl = NULL;
   1.443 +  for (impl = klass->first_impl; impl; impl = impl->next) {
   1.444 +    OIL_LOG ("testing impl %s", impl->name);
   1.445 +    if (!oil_impl_is_runnable (impl))
   1.446 +      continue;
   1.447 +
   1.448 +    ret = oil_test_check_impl (test, impl);
   1.449 +    if (ret) {
   1.450 +      impl->profile_ave = test->profile_ave;
   1.451 +      impl->profile_std = test->profile_std;
   1.452 +      OIL_LOG ("impl %s ave=%g std=%g", impl->name, impl->profile_ave,
   1.453 +          impl->profile_std);
   1.454 +      if (min_impl == NULL) {
   1.455 +        min_impl = impl;
   1.456 +      } else {
   1.457 +        if (impl->profile_ave < min_impl->profile_ave) {
   1.458 +          min_impl = impl;
   1.459 +        }
   1.460 +      }
   1.461 +    } else {
   1.462 +      OIL_WARNING("disabling implementation %s", impl->name);
   1.463 +      impl->profile_ave = test->profile_ave;
   1.464 +      impl->profile_std = test->profile_std;
   1.465 +      impl->flags |= OIL_IMPL_FLAG_DISABLED;
   1.466 +    }
   1.467 +  }
   1.468 +  if (min_impl == NULL) {
   1.469 +    OIL_ERROR ("failed to find optimal implementation for class %s",
   1.470 +        klass->name);
   1.471 +    return;
   1.472 +  }
   1.473 +
   1.474 +  OIL_DEBUG("choosing implementation %s", min_impl->name);
   1.475 +  klass->chosen_impl = min_impl;
   1.476 +  klass->func = min_impl->func;
   1.477 +
   1.478 +  oil_test_free (test);
   1.479 +}
   1.480 +
   1.481 +static void
   1.482 +oil_init_pointers (void)
   1.483 +{
   1.484 +  int i;
   1.485 +
   1.486 +  for(i=0;_oil_function_class_array[i];i++) {
   1.487 +    _oil_n_function_classes++;
   1.488 +  }
   1.489 +
   1.490 +  for(i=0;_oil_function_impl_array[i];i++) {
   1.491 +    _oil_n_function_impls++;
   1.492 +  }
   1.493 +
   1.494 +}
   1.495 +
   1.496 +static void
   1.497 +oil_init_structs (void)
   1.498 +{
   1.499 +  int i;
   1.500 +  OilFunctionImpl *impl;
   1.501 +
   1.502 +  for (i = 0; i < _oil_n_function_impls; i++) {
   1.503 +    impl = oil_impl_get_by_index (i);
   1.504 +    OIL_LOG ("registering impl %p (%s)", impl,
   1.505 +          (impl->name != NULL) ? impl->name : "NULL");
   1.506 +    if (impl->klass == NULL) {
   1.507 +      OIL_ERROR ("impl->klass is NULL for impl %p (%s)", impl,
   1.508 +          (impl->name != NULL) ? impl->name : "NULL");
   1.509 +      continue;
   1.510 +    }
   1.511 +    impl->next = impl->klass->first_impl;
   1.512 +    impl->klass->first_impl = impl;
   1.513 +    if (impl->flags & OIL_IMPL_FLAG_REF) {
   1.514 +      impl->klass->reference_impl = impl;
   1.515 +      impl->klass->chosen_impl = impl;
   1.516 +      impl->klass->func = impl->func;
   1.517 +    }
   1.518 +  }
   1.519 +}
   1.520 +
   1.521 +/**
   1.522 + * oil_class_register_impl_by_name:
   1.523 + * @klass_name: the name of the class
   1.524 + * @impl: an implementation
   1.525 + *
   1.526 + * Adds @impl to the list of implementations associated with
   1.527 + * the function class given by @klass_name.
   1.528 + */
   1.529 + #ifdef __SYMBIAN32__
   1.530 +EXPORT_C
   1.531 +#endif
   1.532 +void
   1.533 +oil_class_register_impl_by_name (const char *klass_name, OilFunctionImpl *impl)
   1.534 +{
   1.535 +  OilFunctionClass *klass;
   1.536 +
   1.537 +  klass = oil_class_get (klass_name);
   1.538 +  if (klass == NULL) return;
   1.539 +
   1.540 +  oil_class_register_impl (klass, impl);
   1.541 +}
   1.542 +
   1.543 +/**
   1.544 + * oil_class_register_impl:
   1.545 + * @klass: the class
   1.546 + * @impl: an implementation
   1.547 + *
   1.548 + * Adds @impl to the list of implementations associated with
   1.549 + * the function class given by @klass.
   1.550 + */
   1.551 + #ifdef __SYMBIAN32__
   1.552 +EXPORT_C
   1.553 +#endif
   1.554 +void
   1.555 +oil_class_register_impl (OilFunctionClass *klass, OilFunctionImpl *impl)
   1.556 +{
   1.557 +  impl->klass = klass;
   1.558 +  impl->next = impl->klass->first_impl;
   1.559 +  klass->first_impl = impl;
   1.560 +  if (impl->flags & OIL_IMPL_FLAG_REF) {
   1.561 +    impl->klass->reference_impl = impl;
   1.562 +    impl->klass->chosen_impl = impl;
   1.563 +    impl->klass->func = impl->func;
   1.564 +  }
   1.565 +}
   1.566 +
   1.567 +/**
   1.568 + * oil_class_register_impl_full:
   1.569 + * @klass: the class
   1.570 + * @func: the function
   1.571 + * @name: name of the function
   1.572 + * @flags: CPU flags
   1.573 + *
   1.574 + * Adds @func to the list of implementations associated with
   1.575 + * the function class given by @klass.
   1.576 + */
   1.577 + #ifdef __SYMBIAN32__
   1.578 +EXPORT_C  
   1.579 +#endif
   1.580 +void
   1.581 +oil_class_register_impl_full (OilFunctionClass *klass,
   1.582 +    void (*func)(void), const char *name, unsigned int flags)
   1.583 +{
   1.584 +  OilFunctionImpl *impl;
   1.585 +
   1.586 +  impl = malloc(sizeof(OilFunctionImpl));
   1.587 +  memset (impl, 0, sizeof(OilFunctionImpl));
   1.588 +
   1.589 +  impl->func = (void*)func;
   1.590 +  impl->flags = flags;
   1.591 +  impl->name = xstrdup(name);
   1.592 +
   1.593 +  oil_class_register_impl(klass,impl);
   1.594 +}
   1.595 +
   1.596 +static char *
   1.597 +xstrdup (const char *s)
   1.598 +{
   1.599 +  int n = strlen(s);
   1.600 +  char *t;
   1.601 +
   1.602 +  n = strlen(s);
   1.603 +  t = malloc(n + 1);
   1.604 +  memcpy (t, s, n);
   1.605 +  t[n] = 0;
   1.606 +
   1.607 +  return t;
   1.608 +}
   1.609 +