Home | History | Annotate | Line # | Download | only in intl
      1  1.1  christos /*	$NetBSD: relocatable.c,v 1.1.1.1 2016/01/14 00:11:28 christos Exp $	*/
      2  1.1  christos 
      3  1.1  christos /* Provide relocatable packages.
      4  1.1  christos    Copyright (C) 2003 Free Software Foundation, Inc.
      5  1.1  christos    Written by Bruno Haible <bruno (at) clisp.org>, 2003.
      6  1.1  christos 
      7  1.1  christos    This program is free software; you can redistribute it and/or modify it
      8  1.1  christos    under the terms of the GNU Library General Public License as published
      9  1.1  christos    by the Free Software Foundation; either version 2, or (at your option)
     10  1.1  christos    any later version.
     11  1.1  christos 
     12  1.1  christos    This program is distributed in the hope that it will be useful,
     13  1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15  1.1  christos    Library General Public License for more details.
     16  1.1  christos 
     17  1.1  christos    You should have received a copy of the GNU Library General Public
     18  1.1  christos    License along with this program; if not, write to the Free Software
     19  1.1  christos    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
     20  1.1  christos    USA.  */
     21  1.1  christos 
     22  1.1  christos 
     23  1.1  christos /* Tell glibc's <stdio.h> to provide a prototype for getline().
     24  1.1  christos    This must come before <config.h> because <config.h> may include
     25  1.1  christos    <features.h>, and once <features.h> has been included, it's too late.  */
     26  1.1  christos #ifndef _GNU_SOURCE
     27  1.1  christos # define _GNU_SOURCE	1
     28  1.1  christos #endif
     29  1.1  christos 
     30  1.1  christos #ifdef HAVE_CONFIG_H
     31  1.1  christos # include "config.h"
     32  1.1  christos #endif
     33  1.1  christos 
     34  1.1  christos /* Specification.  */
     35  1.1  christos #include "relocatable.h"
     36  1.1  christos 
     37  1.1  christos #if ENABLE_RELOCATABLE
     38  1.1  christos 
     39  1.1  christos #include <stddef.h>
     40  1.1  christos #include <stdio.h>
     41  1.1  christos #include <stdlib.h>
     42  1.1  christos #include <string.h>
     43  1.1  christos 
     44  1.1  christos #ifdef NO_XMALLOC
     45  1.1  christos # define xmalloc malloc
     46  1.1  christos #else
     47  1.1  christos # include "xalloc.h"
     48  1.1  christos #endif
     49  1.1  christos 
     50  1.1  christos #if defined _WIN32 || defined __WIN32__
     51  1.1  christos # define WIN32_LEAN_AND_MEAN
     52  1.1  christos # include <windows.h>
     53  1.1  christos #endif
     54  1.1  christos 
     55  1.1  christos #if DEPENDS_ON_LIBCHARSET
     56  1.1  christos # include <libcharset.h>
     57  1.1  christos #endif
     58  1.1  christos #if DEPENDS_ON_LIBICONV && HAVE_ICONV
     59  1.1  christos # include <iconv.h>
     60  1.1  christos #endif
     61  1.1  christos #if DEPENDS_ON_LIBINTL && ENABLE_NLS
     62  1.1  christos # include <libintl.h>
     63  1.1  christos #endif
     64  1.1  christos 
     65  1.1  christos /* Faked cheap 'bool'.  */
     66  1.1  christos #undef bool
     67  1.1  christos #undef false
     68  1.1  christos #undef true
     69  1.1  christos #define bool int
     70  1.1  christos #define false 0
     71  1.1  christos #define true 1
     72  1.1  christos 
     73  1.1  christos /* Pathname support.
     74  1.1  christos    ISSLASH(C)           tests whether C is a directory separator character.
     75  1.1  christos    IS_PATH_WITH_DIR(P)  tests whether P contains a directory specification.
     76  1.1  christos  */
     77  1.1  christos #if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
     78  1.1  christos   /* Win32, OS/2, DOS */
     79  1.1  christos # define ISSLASH(C) ((C) == '/' || (C) == '\\')
     80  1.1  christos # define HAS_DEVICE(P) \
     81  1.1  christos     ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
     82  1.1  christos      && (P)[1] == ':')
     83  1.1  christos # define IS_PATH_WITH_DIR(P) \
     84  1.1  christos     (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
     85  1.1  christos # define FILESYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
     86  1.1  christos #else
     87  1.1  christos   /* Unix */
     88  1.1  christos # define ISSLASH(C) ((C) == '/')
     89  1.1  christos # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
     90  1.1  christos # define FILESYSTEM_PREFIX_LEN(P) 0
     91  1.1  christos #endif
     92  1.1  christos 
     93  1.1  christos /* Original installation prefix.  */
     94  1.1  christos static char *orig_prefix;
     95  1.1  christos static size_t orig_prefix_len;
     96  1.1  christos /* Current installation prefix.  */
     97  1.1  christos static char *curr_prefix;
     98  1.1  christos static size_t curr_prefix_len;
     99  1.1  christos /* These prefixes do not end in a slash.  Anything that will be concatenated
    100  1.1  christos    to them must start with a slash.  */
    101  1.1  christos 
    102  1.1  christos /* Sets the original and the current installation prefix of this module.
    103  1.1  christos    Relocation simply replaces a pathname starting with the original prefix
    104  1.1  christos    by the corresponding pathname with the current prefix instead.  Both
    105  1.1  christos    prefixes should be directory names without trailing slash (i.e. use ""
    106  1.1  christos    instead of "/").  */
    107  1.1  christos static void
    108  1.1  christos set_this_relocation_prefix (const char *orig_prefix_arg,
    109  1.1  christos 			    const char *curr_prefix_arg)
    110  1.1  christos {
    111  1.1  christos   if (orig_prefix_arg != NULL && curr_prefix_arg != NULL
    112  1.1  christos       /* Optimization: if orig_prefix and curr_prefix are equal, the
    113  1.1  christos 	 relocation is a nop.  */
    114  1.1  christos       && strcmp (orig_prefix_arg, curr_prefix_arg) != 0)
    115  1.1  christos     {
    116  1.1  christos       /* Duplicate the argument strings.  */
    117  1.1  christos       char *memory;
    118  1.1  christos 
    119  1.1  christos       orig_prefix_len = strlen (orig_prefix_arg);
    120  1.1  christos       curr_prefix_len = strlen (curr_prefix_arg);
    121  1.1  christos       memory = (char *) xmalloc (orig_prefix_len + 1 + curr_prefix_len + 1);
    122  1.1  christos #ifdef NO_XMALLOC
    123  1.1  christos       if (memory != NULL)
    124  1.1  christos #endif
    125  1.1  christos 	{
    126  1.1  christos 	  memcpy (memory, orig_prefix_arg, orig_prefix_len + 1);
    127  1.1  christos 	  orig_prefix = memory;
    128  1.1  christos 	  memory += orig_prefix_len + 1;
    129  1.1  christos 	  memcpy (memory, curr_prefix_arg, curr_prefix_len + 1);
    130  1.1  christos 	  curr_prefix = memory;
    131  1.1  christos 	  return;
    132  1.1  christos 	}
    133  1.1  christos     }
    134  1.1  christos   orig_prefix = NULL;
    135  1.1  christos   curr_prefix = NULL;
    136  1.1  christos   /* Don't worry about wasted memory here - this function is usually only
    137  1.1  christos      called once.  */
    138  1.1  christos }
    139  1.1  christos 
    140  1.1  christos /* Sets the original and the current installation prefix of the package.
    141  1.1  christos    Relocation simply replaces a pathname starting with the original prefix
    142  1.1  christos    by the corresponding pathname with the current prefix instead.  Both
    143  1.1  christos    prefixes should be directory names without trailing slash (i.e. use ""
    144  1.1  christos    instead of "/").  */
    145  1.1  christos void
    146  1.1  christos set_relocation_prefix (const char *orig_prefix_arg, const char *curr_prefix_arg)
    147  1.1  christos {
    148  1.1  christos   set_this_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
    149  1.1  christos 
    150  1.1  christos   /* Now notify all dependent libraries.  */
    151  1.1  christos #if DEPENDS_ON_LIBCHARSET
    152  1.1  christos   libcharset_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
    153  1.1  christos #endif
    154  1.1  christos #if DEPENDS_ON_LIBICONV && HAVE_ICONV && _LIBICONV_VERSION >= 0x0109
    155  1.1  christos   libiconv_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
    156  1.1  christos #endif
    157  1.1  christos #if DEPENDS_ON_LIBINTL && ENABLE_NLS && defined libintl_set_relocation_prefix
    158  1.1  christos   libintl_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
    159  1.1  christos #endif
    160  1.1  christos }
    161  1.1  christos 
    162  1.1  christos #if !defined IN_LIBRARY || (defined PIC && defined INSTALLDIR)
    163  1.1  christos 
    164  1.1  christos /* Convenience function:
    165  1.1  christos    Computes the current installation prefix, based on the original
    166  1.1  christos    installation prefix, the original installation directory of a particular
    167  1.1  christos    file, and the current pathname of this file.  Returns NULL upon failure.  */
    168  1.1  christos #ifdef IN_LIBRARY
    169  1.1  christos #define compute_curr_prefix local_compute_curr_prefix
    170  1.1  christos static
    171  1.1  christos #endif
    172  1.1  christos const char *
    173  1.1  christos compute_curr_prefix (const char *orig_installprefix,
    174  1.1  christos 		     const char *orig_installdir,
    175  1.1  christos 		     const char *curr_pathname)
    176  1.1  christos {
    177  1.1  christos   const char *curr_installdir;
    178  1.1  christos   const char *rel_installdir;
    179  1.1  christos 
    180  1.1  christos   if (curr_pathname == NULL)
    181  1.1  christos     return NULL;
    182  1.1  christos 
    183  1.1  christos   /* Determine the relative installation directory, relative to the prefix.
    184  1.1  christos      This is simply the difference between orig_installprefix and
    185  1.1  christos      orig_installdir.  */
    186  1.1  christos   if (strncmp (orig_installprefix, orig_installdir, strlen (orig_installprefix))
    187  1.1  christos       != 0)
    188  1.1  christos     /* Shouldn't happen - nothing should be installed outside $(prefix).  */
    189  1.1  christos     return NULL;
    190  1.1  christos   rel_installdir = orig_installdir + strlen (orig_installprefix);
    191  1.1  christos 
    192  1.1  christos   /* Determine the current installation directory.  */
    193  1.1  christos   {
    194  1.1  christos     const char *p_base = curr_pathname + FILESYSTEM_PREFIX_LEN (curr_pathname);
    195  1.1  christos     const char *p = curr_pathname + strlen (curr_pathname);
    196  1.1  christos     char *q;
    197  1.1  christos 
    198  1.1  christos     while (p > p_base)
    199  1.1  christos       {
    200  1.1  christos 	p--;
    201  1.1  christos 	if (ISSLASH (*p))
    202  1.1  christos 	  break;
    203  1.1  christos       }
    204  1.1  christos 
    205  1.1  christos     q = (char *) xmalloc (p - curr_pathname + 1);
    206  1.1  christos #ifdef NO_XMALLOC
    207  1.1  christos     if (q == NULL)
    208  1.1  christos       return NULL;
    209  1.1  christos #endif
    210  1.1  christos     memcpy (q, curr_pathname, p - curr_pathname);
    211  1.1  christos     q[p - curr_pathname] = '\0';
    212  1.1  christos     curr_installdir = q;
    213  1.1  christos   }
    214  1.1  christos 
    215  1.1  christos   /* Compute the current installation prefix by removing the trailing
    216  1.1  christos      rel_installdir from it.  */
    217  1.1  christos   {
    218  1.1  christos     const char *rp = rel_installdir + strlen (rel_installdir);
    219  1.1  christos     const char *cp = curr_installdir + strlen (curr_installdir);
    220  1.1  christos     const char *cp_base =
    221  1.1  christos       curr_installdir + FILESYSTEM_PREFIX_LEN (curr_installdir);
    222  1.1  christos 
    223  1.1  christos     while (rp > rel_installdir && cp > cp_base)
    224  1.1  christos       {
    225  1.1  christos 	bool same = false;
    226  1.1  christos 	const char *rpi = rp;
    227  1.1  christos 	const char *cpi = cp;
    228  1.1  christos 
    229  1.1  christos 	while (rpi > rel_installdir && cpi > cp_base)
    230  1.1  christos 	  {
    231  1.1  christos 	    rpi--;
    232  1.1  christos 	    cpi--;
    233  1.1  christos 	    if (ISSLASH (*rpi) || ISSLASH (*cpi))
    234  1.1  christos 	      {
    235  1.1  christos 		if (ISSLASH (*rpi) && ISSLASH (*cpi))
    236  1.1  christos 		  same = true;
    237  1.1  christos 		break;
    238  1.1  christos 	      }
    239  1.1  christos #if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
    240  1.1  christos 	    /* Win32, OS/2, DOS - case insignificant filesystem */
    241  1.1  christos 	    if ((*rpi >= 'a' && *rpi <= 'z' ? *rpi - 'a' + 'A' : *rpi)
    242  1.1  christos 		!= (*cpi >= 'a' && *cpi <= 'z' ? *cpi - 'a' + 'A' : *cpi))
    243  1.1  christos 	      break;
    244  1.1  christos #else
    245  1.1  christos 	    if (*rpi != *cpi)
    246  1.1  christos 	      break;
    247  1.1  christos #endif
    248  1.1  christos 	  }
    249  1.1  christos 	if (!same)
    250  1.1  christos 	  break;
    251  1.1  christos 	/* The last pathname component was the same.  opi and cpi now point
    252  1.1  christos 	   to the slash before it.  */
    253  1.1  christos 	rp = rpi;
    254  1.1  christos 	cp = cpi;
    255  1.1  christos       }
    256  1.1  christos 
    257  1.1  christos     if (rp > rel_installdir)
    258  1.1  christos       /* Unexpected: The curr_installdir does not end with rel_installdir.  */
    259  1.1  christos       return NULL;
    260  1.1  christos 
    261  1.1  christos     {
    262  1.1  christos       size_t curr_prefix_len = cp - curr_installdir;
    263  1.1  christos       char *curr_prefix;
    264  1.1  christos 
    265  1.1  christos       curr_prefix = (char *) xmalloc (curr_prefix_len + 1);
    266  1.1  christos #ifdef NO_XMALLOC
    267  1.1  christos       if (curr_prefix == NULL)
    268  1.1  christos 	return NULL;
    269  1.1  christos #endif
    270  1.1  christos       memcpy (curr_prefix, curr_installdir, curr_prefix_len);
    271  1.1  christos       curr_prefix[curr_prefix_len] = '\0';
    272  1.1  christos 
    273  1.1  christos       return curr_prefix;
    274  1.1  christos     }
    275  1.1  christos   }
    276  1.1  christos }
    277  1.1  christos 
    278  1.1  christos #endif /* !IN_LIBRARY || PIC */
    279  1.1  christos 
    280  1.1  christos #if defined PIC && defined INSTALLDIR
    281  1.1  christos 
    282  1.1  christos /* Full pathname of shared library, or NULL.  */
    283  1.1  christos static char *shared_library_fullname;
    284  1.1  christos 
    285  1.1  christos #if defined _WIN32 || defined __WIN32__
    286  1.1  christos 
    287  1.1  christos /* Determine the full pathname of the shared library when it is loaded.  */
    288  1.1  christos 
    289  1.1  christos BOOL WINAPI
    290  1.1  christos DllMain (HINSTANCE module_handle, DWORD event, LPVOID reserved)
    291  1.1  christos {
    292  1.1  christos   (void) reserved;
    293  1.1  christos 
    294  1.1  christos   if (event == DLL_PROCESS_ATTACH)
    295  1.1  christos     {
    296  1.1  christos       /* The DLL is being loaded into an application's address range.  */
    297  1.1  christos       static char location[MAX_PATH];
    298  1.1  christos 
    299  1.1  christos       if (!GetModuleFileName (module_handle, location, sizeof (location)))
    300  1.1  christos 	/* Shouldn't happen.  */
    301  1.1  christos 	return FALSE;
    302  1.1  christos 
    303  1.1  christos       if (!IS_PATH_WITH_DIR (location))
    304  1.1  christos 	/* Shouldn't happen.  */
    305  1.1  christos 	return FALSE;
    306  1.1  christos 
    307  1.1  christos       shared_library_fullname = strdup (location);
    308  1.1  christos     }
    309  1.1  christos 
    310  1.1  christos   return TRUE;
    311  1.1  christos }
    312  1.1  christos 
    313  1.1  christos #else /* Unix */
    314  1.1  christos 
    315  1.1  christos static void
    316  1.1  christos find_shared_library_fullname ()
    317  1.1  christos {
    318  1.1  christos #if defined __linux__ && __GLIBC__ >= 2
    319  1.1  christos   /* Linux has /proc/self/maps. glibc 2 has the getline() function.  */
    320  1.1  christos   FILE *fp;
    321  1.1  christos 
    322  1.1  christos   /* Open the current process' maps file.  It describes one VMA per line.  */
    323  1.1  christos   fp = fopen ("/proc/self/maps", "r");
    324  1.1  christos   if (fp)
    325  1.1  christos     {
    326  1.1  christos       unsigned long address = (unsigned long) &find_shared_library_fullname;
    327  1.1  christos       for (;;)
    328  1.1  christos 	{
    329  1.1  christos 	  unsigned long start, end;
    330  1.1  christos 	  int c;
    331  1.1  christos 
    332  1.1  christos 	  if (fscanf (fp, "%lx-%lx", &start, &end) != 2)
    333  1.1  christos 	    break;
    334  1.1  christos 	  if (address >= start && address <= end - 1)
    335  1.1  christos 	    {
    336  1.1  christos 	      /* Found it.  Now see if this line contains a filename.  */
    337  1.1  christos 	      while (c = getc (fp), c != EOF && c != '\n' && c != '/')
    338  1.1  christos 		continue;
    339  1.1  christos 	      if (c == '/')
    340  1.1  christos 		{
    341  1.1  christos 		  size_t size;
    342  1.1  christos 		  int len;
    343  1.1  christos 
    344  1.1  christos 		  ungetc (c, fp);
    345  1.1  christos 		  shared_library_fullname = NULL; size = 0;
    346  1.1  christos 		  len = getline (&shared_library_fullname, &size, fp);
    347  1.1  christos 		  if (len >= 0)
    348  1.1  christos 		    {
    349  1.1  christos 		      /* Success: filled shared_library_fullname.  */
    350  1.1  christos 		      if (len > 0 && shared_library_fullname[len - 1] == '\n')
    351  1.1  christos 			shared_library_fullname[len - 1] = '\0';
    352  1.1  christos 		    }
    353  1.1  christos 		}
    354  1.1  christos 	      break;
    355  1.1  christos 	    }
    356  1.1  christos 	  while (c = getc (fp), c != EOF && c != '\n')
    357  1.1  christos 	    continue;
    358  1.1  christos 	}
    359  1.1  christos       fclose (fp);
    360  1.1  christos     }
    361  1.1  christos #endif
    362  1.1  christos }
    363  1.1  christos 
    364  1.1  christos #endif /* WIN32 / Unix */
    365  1.1  christos 
    366  1.1  christos /* Return the full pathname of the current shared library.
    367  1.1  christos    Return NULL if unknown.
    368  1.1  christos    Guaranteed to work only on Linux and Woe32.  */
    369  1.1  christos static char *
    370  1.1  christos get_shared_library_fullname ()
    371  1.1  christos {
    372  1.1  christos #if !(defined _WIN32 || defined __WIN32__)
    373  1.1  christos   static bool tried_find_shared_library_fullname;
    374  1.1  christos   if (!tried_find_shared_library_fullname)
    375  1.1  christos     {
    376  1.1  christos       find_shared_library_fullname ();
    377  1.1  christos       tried_find_shared_library_fullname = true;
    378  1.1  christos     }
    379  1.1  christos #endif
    380  1.1  christos   return shared_library_fullname;
    381  1.1  christos }
    382  1.1  christos 
    383  1.1  christos #endif /* PIC */
    384  1.1  christos 
    385  1.1  christos /* Returns the pathname, relocated according to the current installation
    386  1.1  christos    directory.  */
    387  1.1  christos const char *
    388  1.1  christos relocate (const char *pathname)
    389  1.1  christos {
    390  1.1  christos #if defined PIC && defined INSTALLDIR
    391  1.1  christos   static int initialized;
    392  1.1  christos 
    393  1.1  christos   /* Initialization code for a shared library.  */
    394  1.1  christos   if (!initialized)
    395  1.1  christos     {
    396  1.1  christos       /* At this point, orig_prefix and curr_prefix likely have already been
    397  1.1  christos 	 set through the main program's set_program_name_and_installdir
    398  1.1  christos 	 function.  This is sufficient in the case that the library has
    399  1.1  christos 	 initially been installed in the same orig_prefix.  But we can do
    400  1.1  christos 	 better, to also cover the cases that 1. it has been installed
    401  1.1  christos 	 in a different prefix before being moved to orig_prefix and (later)
    402  1.1  christos 	 to curr_prefix, 2. unlike the program, it has not moved away from
    403  1.1  christos 	 orig_prefix.  */
    404  1.1  christos       const char *orig_installprefix = INSTALLPREFIX;
    405  1.1  christos       const char *orig_installdir = INSTALLDIR;
    406  1.1  christos       const char *curr_prefix_better;
    407  1.1  christos 
    408  1.1  christos       curr_prefix_better =
    409  1.1  christos 	compute_curr_prefix (orig_installprefix, orig_installdir,
    410  1.1  christos 			     get_shared_library_fullname ());
    411  1.1  christos       if (curr_prefix_better == NULL)
    412  1.1  christos 	curr_prefix_better = curr_prefix;
    413  1.1  christos 
    414  1.1  christos       set_relocation_prefix (orig_installprefix, curr_prefix_better);
    415  1.1  christos 
    416  1.1  christos       initialized = 1;
    417  1.1  christos     }
    418  1.1  christos #endif
    419  1.1  christos 
    420  1.1  christos   /* Note: It is not necessary to perform case insensitive comparison here,
    421  1.1  christos      even for DOS-like filesystems, because the pathname argument was
    422  1.1  christos      typically created from the same Makefile variable as orig_prefix came
    423  1.1  christos      from.  */
    424  1.1  christos   if (orig_prefix != NULL && curr_prefix != NULL
    425  1.1  christos       && strncmp (pathname, orig_prefix, orig_prefix_len) == 0)
    426  1.1  christos     {
    427  1.1  christos       if (pathname[orig_prefix_len] == '\0')
    428  1.1  christos 	/* pathname equals orig_prefix.  */
    429  1.1  christos 	return curr_prefix;
    430  1.1  christos       if (ISSLASH (pathname[orig_prefix_len]))
    431  1.1  christos 	{
    432  1.1  christos 	  /* pathname starts with orig_prefix.  */
    433  1.1  christos 	  const char *pathname_tail = &pathname[orig_prefix_len];
    434  1.1  christos 	  char *result =
    435  1.1  christos 	    (char *) xmalloc (curr_prefix_len + strlen (pathname_tail) + 1);
    436  1.1  christos 
    437  1.1  christos #ifdef NO_XMALLOC
    438  1.1  christos 	  if (result != NULL)
    439  1.1  christos #endif
    440  1.1  christos 	    {
    441  1.1  christos 	      memcpy (result, curr_prefix, curr_prefix_len);
    442  1.1  christos 	      strcpy (result + curr_prefix_len, pathname_tail);
    443  1.1  christos 	      return result;
    444  1.1  christos 	    }
    445  1.1  christos 	}
    446  1.1  christos     }
    447  1.1  christos   /* Nothing to relocate.  */
    448  1.1  christos   return pathname;
    449  1.1  christos }
    450  1.1  christos 
    451  1.1  christos #endif
    452