diff --git a/src/libraries/libmisc/ChangeLog b/src/libraries/libmisc/ChangeLog
new file mode 100644
index 0000000000000000000000000000000000000000..9f0ce4f5f06aa41c5e1baa0e812f37b6fff86067
--- /dev/null
+++ b/src/libraries/libmisc/ChangeLog
@@ -0,0 +1,27 @@
+Thu Dec 20 04:59:36 1990  Thomas Bellman  (bellman at lave)
+
+	* s-string.[ch]: s_strchr() och s_strrchr(): Lade till en
+	  parameter som anger var s|kningen ska b|rja.
+
+	* s-string.c: [ndrat fr}n if-satser f|r kontroll av parametrar
+	  till att anv{nda assert()-makrot.
+
+	* s-string.[ch]: Lade till s_strrchr().
+
+	* zmalloc.c: Fixat en del buggar d{r pekare till z_info-structen
+	  returnerades i st f pekare efter denna, samt lite annat.
+
+Sat Dec  8 03:05:51 1990  Thomas Bellman  (bellman at laila)
+
+	* [ndrade tillbaka s_strcpy().  Den ska sl{ppa loss minnet {ven om
+	  den f}r en EMPTY_STRING.
+
+Sat Dec  1 12:09:35 1990  Lars Willf|r  (willfor at nanny)
+
+	* [ndrade s_strcpy s} att den med s{kerhet fungerar {ven om
+	  source_string == EMPTY_STRING.
+
+Thu Aug  9 05:12:52 1990  Thomas Bellman  (bellman at laila)
+
+	* Biblioteket skapat ig}r.
+
diff --git a/src/libraries/libmisc/pom.c b/src/libraries/libmisc/pom.c
new file mode 100644
index 0000000000000000000000000000000000000000..41e8d4c7862ec3e84b598086ca9c69bad9f58f97
--- /dev/null
+++ b/src/libraries/libmisc/pom.c
@@ -0,0 +1,168 @@
+/*
+ *  pom.c  --  Calculate the Phase Of the Moon
+ *
+ *  Written by G|ran ]hlstr|m 1984-04-05, revision 5 1986-03-03
+ *
+ *  Modified by Thomas Bellman 1991-01-29
+ */
+
+#include <sys/types.h>
+#include <time.h>
+#include <math.h>
+#include <stdio.h>
+
+#include "pom.h"
+
+
+#define EXPORT
+
+
+#define RADS	(M_PI/180.0)
+
+static	char		* pmt[] = { "NM", "FQ", "FM", "LQ" };
+static	short		  ix;
+static	double		  m;		/* Sun's Mean Anomaly */
+static	double		  mp;		/* Moon's Mean Anomaly */
+static	double		  f;		/* Moon's Argument of Latitude	*/
+static	struct tm	  dt;
+
+
+/* New & Full Moon correction */
+static  double
+mcorr (double	t)
+
+{
+    double	  tmp;
+
+    tmp = (0.1734-3.93E-4*t) * sin(m) + 0.0021 * sin(2.0*m) - 0.4068 * sin(mp);
+    tmp += 0.0161 * sin(2.0*mp) - 0.0004 * sin(3.0*mp) + 0.0104 * sin(2.0*f);
+    tmp += 0.0004 * sin(2.0*f + m) - 0.0051 * sin(m+mp) - 0.0074 * sin(m-mp);
+    tmp -= 0.0004 * sin(2.0*f - m) + 0.0006 * sin(2.0*f + mp);
+    return  tmp += 0.0010 * sin(2.0*f - mp) + 0.0005 * sin(m + 2.0*mp);
+}
+
+
+
+/*  First & Last Quarter correction  */
+static  double
+qcorr (double	t)
+
+{
+    double	  tmp, tmp2;
+
+    tmp = (0.1721 - 0.0004*t) * sin(m) + 0.0021 * sin(2.0*m) - 0.628 * sin(mp);
+    tmp +=  0.0089 * sin(2.0*mp) - 0.0004 * sin(3.0*mp) + 0.0079 * sin(2.0*f);
+    tmp +=  0.0003 * sin(2.0*f + m) - 0.0119 * sin(m+mp) - 0.0047 * sin(m-mp);
+    tmp +=  0.0021 * sin(2.0*f - mp) - 0.0004 * sin(2.0*f - m);
+    tmp += -0.0006 * sin(2.0*f + mp) + 0.0003 * sin(m + 2.0*mp);
+    tmp +=  0.0004 * sin(m - 2.0*mp) - 0.0003 * sin(2.0*m + mp);
+    tmp2 = (0.0028 - 0.0004 * cos (m) + 0.0003 * cos (mp));
+    if (ix == 1)
+	tmp += tmp2;
+    else
+	tmp -= tmp2;
+
+    return  tmp;
+}
+
+
+
+/* When is nearest phase? */
+static  double
+pcon (void)
+
+{
+    double	  frc;
+    double	  year;
+    double	  k;
+    double	  t;
+    double	  tmp;
+    int		  leap;
+
+
+    year = (dt.tm_hour + ((dt.tm_min + (dt.tm_sec / 60.0)) / 60.0)) / 24.0;
+    year += dt.tm_yday;
+
+    /* Leap year? */
+    leap = dt.tm_year + 1900;
+    leap = (leap % 4 == 0  &&  (leap % 100 != 0  ||  leap % 400 == 0));
+
+    /* This year with decimals */
+    year = dt.tm_year + year / (365.0 + leap);
+
+    k = year * 12.3685;
+    k -= (frc = k - floor (k));
+
+    /* Determine nearest phase */
+    for ( ix = 0 ;  frc > ix * 0.25 + 0.125 ;  ix++ )
+	;
+    t = (k += ix * 0.25) / 1236.85;
+    tmp = 2415020.75933 + 29.53058868 * k
+	+ (1.178E-4 - 1.55E-7 * t) * pow (t, 2.0);
+    tmp += 3.3E-4 * sin (166.56*RADS + 132.87*RADS * t
+			 - 9.173E-3*RADS * pow(t, 2.0));
+    m = RADS * fmod (359.2242 + 29.10535608 * k
+		     - (3.47e-6*t + 3.33e-5) * pow (t, 2.0), 360.0);
+    mp = RADS * fmod (306.0253 + 385.81691806 * k
+		      + (1.236e-5*t + 0.0107306) * pow (t, 2.0), 360.0);
+    f = RADS * fmod (21.2964 + 390.67050646 * k
+		     - (2.39e-6*t + 1.6528e-3) * pow (t, 2.0), 360.0);
+    return  tmp += ((ix % 2 == 0) ? mcorr (t) : qcorr (t));
+}
+
+
+
+/* JD at this instant */
+static  double
+dcon (void)
+
+{
+    double	  a, b, d, m, y;
+
+
+    m = dt.tm_mon;
+    y = dt.tm_year + 1900.0;
+    d = dt.tm_mday + dt.tm_hour / 24.0 + dt.tm_min / 1440.0
+	+ dt.tm_sec / 86400.0;
+    if (m <= 2.0)
+    {
+	y -= 1.0;
+	m += 12.0;
+    }
+    a = floor (y/100.0);	/* Gregorian Calendar correction */
+    b = 2.0 - a + floor (a / 4.0);
+    return  (floor (365.25 * y) + floor (30.6001 * (m+1.0)) + d + 1720994.5 + b);
+}
+
+
+
+EXPORT  struct pom
+phase_of_the_moon (struct tm	* when)
+
+{
+    int		  p1, p2, p3, p4;
+    char	  sgn;
+    long	  ts;
+    double	  tmp;
+    struct pom	  result;
+
+
+    dt = *when;
+    dt.tm_mon++;
+    dt.tm_yday++;
+    tmp = pcon() - dcon();
+    sgn = (tmp > 0)  ?  '-'  :  '+';
+    tmp = fabs (tmp);
+    tmp -= (p1 = floor (tmp));
+    tmp = tmp * 24.0 - (p2 = floor (tmp * 24.0));
+    tmp = tmp * 60.0 - (p3 = floor (tmp * 60.0));
+    p4 = floor (tmp * 60.0);
+
+    result.quarter = ix % 4;
+    result.days    = (sgn == '+')  ?  p1  :  -p1;
+    result.hours   = (sgn == '+')  ?  p2  :  -p2;
+    result.minutes = (sgn == '+')  ?  p3  :  -p3;
+    result.seconds = (sgn == '+')  ?  p4  :  -p4;
+
+    return  result;
+}
diff --git a/src/libraries/libmisc/pom.h b/src/libraries/libmisc/pom.h
new file mode 100644
index 0000000000000000000000000000000000000000..f0f7c32d17f76a52befd8582ff0e19d56cfa8d98
--- /dev/null
+++ b/src/libraries/libmisc/pom.h
@@ -0,0 +1,34 @@
+/*
+ *  pom.h
+ *	Calculate the phase of the moon at any given time.
+ *
+ *
+ *  This file is in the public domain.  No rights reserved.
+ */
+
+
+#ifndef POM_H_INCLUDED__
+#define POM_H_INCLUDED__
+
+
+struct	pom {
+	enum { pom_NM, pom_FQ, pom_FM, pom_LQ }
+			  quarter;	/* Nearest quarter */
+	/* Time since nearest quarter.  All fields are negative if
+	 * nearest quarter is in the future.			*/
+	int		  days;
+	int		  hours;
+	int		  minutes;
+	int		  seconds;
+};
+
+
+/*
+ *  Calculate the phase of the moon at the time WHEN, which should be
+ *  the GMT time.
+ */
+extern  struct pom
+phase_of_the_moon (struct tm	* when);
+    
+
+#endif  /* POM_H_INCLUDED__ */
diff --git a/src/libraries/libmisc/s-collat-tabs.c b/src/libraries/libmisc/s-collat-tabs.c
new file mode 100644
index 0000000000000000000000000000000000000000..8d058b3c5e1552318d27c0d92226270777ce587f
--- /dev/null
+++ b/src/libraries/libmisc/s-collat-tabs.c
@@ -0,0 +1,108 @@
+/*
+ *  s-collat-tables.c  --  Collating tables used for the s_usr_strcmp()
+ *			   routine in s-string.[ch]
+ *
+ *
+ *  Copyright (C) 1990	Lysator Computer Club,
+ *			Linkoping University,  Sweden
+ *
+ *  Everyone is granted permission to copy, modify and redistribute
+ *  this code, provided the people they give it to can.
+ *
+ *
+ *  Author:	Thomas Bellman
+ *		Lysator Computer Club
+ *		Linkoping University
+ *		Sweden
+ *
+ *  email:	Bellman@Lysator.LiU.SE
+ */
+
+
+#include "s-collat-tables.h"
+
+
+/*
+ *  Collating tables:
+ *	swedish_collate_tab:	Swedish text.  "][\}{|" in the right
+ *				order.  Upper and lower case letters
+ *				are equal.
+ *	english_collate_tab:	English text.  Upper and lower case
+ *				letters are equal.
+ */
+
+
+
+char	swedish_collate_tab [ COLLAT_TAB_SIZE ] =
+    {
+	'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+	'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+	'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+	'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+	' ',	'!',	'"',	'#',	'$',	'%',	'&',	'\'',
+	'(',	')',	'*',	'+',	',',	'-',	'.',	'/',
+	'0',	'1',	'2',	'3',	'4',	'5',	'6',	'7',
+	'8',	'9',	':',	';',	'<',	'=',	'>',	'?',
+	'@',	'a',	'b',	'c',	'd',	'e',	'f',	'g',
+	'h',	'i',	'j',	'k',	'l',	'm',	'n',	'o',
+	'p',	'q',	'r',	's',	't',	'u',	'v',	'w',
+	'x',	'y',	'z',	'}',	'{',	'|',	'~',	'_',
+	'`',	'a',	'b',	'c',	'd',	'e',	'f',	'g',
+	'h',	'i',	'j',	'k',	'l',	'm',	'n',	'o',
+	'p',	'q',	'r',	's',	't',	'u',	'v',	'w',
+	'x',	'y',	'z',	'}',	'{',	'|',	'~',	'',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�'
+    };
+
+
+
+char	english_collate_tab [ COLLAT_TAB_SIZE ] =
+    {
+	'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+	'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+	'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+	'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+	' ',	'!',	'"',	'#',	'$',	'%',	'&',	'\'',
+	'(',	')',	'*',	'+',	',',	'-',	'.',	'/',
+	'0',	'1',	'2',	'3',	'4',	'5',	'6',	'7',
+	'8',	'9',	':',	';',	'<',	'=',	'>',	'?',
+	'@',	'a',	'b',	'c',	'd',	'e',	'f',	'g',
+	'h',	'i',	'j',	'k',	'l',	'm',	'n',	'o',
+	'p',	'q',	'r',	's',	't',	'u',	'v',	'w',
+	'x',	'y',	'z',	'[',	'\\',	']',	'~',	'_',
+	'`',	'a',	'b',	'c',	'd',	'e',	'f',	'g',
+	'h',	'i',	'j',	'k',	'l',	'm',	'n',	'o',
+	'p',	'q',	'r',	's',	't',	'u',	'v',	'w',
+	'x',	'y',	'z',	'{',	'|',	'}',	'~',	'',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�',
+	'�',	'�',	'�',	'�',	'�',	'�',	'�',	'�'
+    };
diff --git a/src/libraries/libmisc/s-collat-tabs.h b/src/libraries/libmisc/s-collat-tabs.h
new file mode 100644
index 0000000000000000000000000000000000000000..0c47985f8d2455a02085358be6993a30bb3da125
--- /dev/null
+++ b/src/libraries/libmisc/s-collat-tabs.h
@@ -0,0 +1,35 @@
+/*
+ *  s-collat-tables.h  --  Declarations for collating tables
+ *
+ *
+ *  Copyright (C) 1990	Lysator Computer Club,
+ *			Linkoping University,  Sweden
+ *
+ *  Everyone is granted permission to copy, modify and redistribute
+ *  this code, provided the people they give it to can.
+ *
+ *
+ *  Author:	Thomas Bellman
+ *		Lysator Computer Club
+ *		Linkoping University
+ *		Sweden
+ *
+ *  email:	Bellman@Lysator.LiU.SE
+ *
+ *
+ *  Any opinions expressed in this code are the author's PERSONAL opinions,
+ *  and does NOT, repeat NOT, represent any official standpoint of Lysator,
+ *  even if so stated.
+ */
+
+
+#include <limits.h>
+
+#define COLLAT_TAB_SIZE	   (UCHAR_MAX+1)
+
+
+extern  char	swedish_collate_tab [ COLLAT_TAB_SIZE ];
+extern  char	english_collate_tab [ COLLAT_TAB_SIZE ];
+#if 0
+extern	char	iso8859_1_collate_tab [ COLLAT_TAB_SIZE ];
+#endif
diff --git a/src/libraries/libmisc/s-string.c b/src/libraries/libmisc/s-string.c
new file mode 100644
index 0000000000000000000000000000000000000000..30cfbe723f2c6d37101547b5bfb683d05d904f6d
--- /dev/null
+++ b/src/libraries/libmisc/s-string.c
@@ -0,0 +1,881 @@
+/*
+ *  s-string.c  --  Routines for manipulating objects of type String.
+ *
+ *
+ *  Copyright (C) 1990	Lysator Computer Club,
+ *			Linkoping University,  Sweden
+ *
+ *  Everyone is granted permission to copy, modify and redistribute
+ *  this code, provided the people they give it to can.
+ *
+ *
+ *  Author:	Thomas Bellman
+ *		Lysator Computer Club
+ *		Linkoping University
+ *		Sweden
+ *
+ *  email:	Bellman@Lysator.LiU.SE
+ *
+ *
+ *  Any opinions expressed in this code are the author's PERSONAL opinions,
+ *  and does NOT, repeat NOT, represent any official standpoint of Lysator,
+ *  even if so stated.
+ */
+
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include <misc-types.h>
+#include "s-collat-tables.h"
+#include "s-string.h"
+
+
+#define	EXPORT			/* To emphasize objects that are exported */
+
+
+/*  The empty String  */
+EXPORT  const String	EMPTY_STRING	= EMPTY_STRING_i;
+
+
+static free_function	x_free		= NULL;
+static malloc_function	x_malloc	= NULL;
+static realloc_function	x_realloc	= NULL;
+
+
+
+/*
+ *  Functions to manipulate strings of type 'String'.
+ *  All these functions return a value of type Success, which is
+ *  an enum of OK an FAILURE (do NOT trust the order of these!).
+ *
+ *  All functions automatically allocates (and deallocates) any
+ *  necessary storage, using the storage management functions
+ *  defined by the s_set_storage_management() call.
+ */
+
+
+/*  Macro to reallocate new storage.  Works even if PTR is a
+ *  nil pointer.	*/
+#define REALLOC_0(ptr, size)	(((ptr) == NULL)		\
+					? MALLOC_0 (size)	\
+					: (*x_realloc) ((ptr), size))
+
+/*  Free storage.  Works even if PTR is a nil pointer.	*/
+#define FREE_0(ptr)		(((ptr) == NULL)		\
+					? ((void) 0)		\
+					: (*x_free) (ptr))
+
+#define MALLOC_0(size)		((*x_malloc) (size))
+
+
+/*
+ *  Set the functions to use for storage management.  These must
+ *  be call compatible with the normal functions malloc(),
+ *  realloc() and free().
+ */
+EXPORT  void
+s_set_storage_management (malloc_function	new_malloc,
+			  realloc_function	new_realloc,
+			  free_function		new_free)
+
+{
+    x_malloc = new_malloc;
+    x_realloc = new_realloc;
+    x_free = new_free;
+}
+
+
+
+/*
+ *  Create an object of type String from an ordinary C string.
+ */
+EXPORT  Success
+s_crea_str (String	* dest_string,
+	    const char	* c_string    )
+
+{
+    String_size		  length;
+    void		* temp_ptr;	/* To hold result from malloc/realloc
+					 * before actually using it.  */
+
+    length = strlen(c_string);
+
+    temp_ptr = MALLOC_0 (length);
+    if (temp_ptr == NULL)
+    {
+	return FAILURE;
+    }
+
+    FREE_0 (dest_string->string);
+    dest_string->string = temp_ptr;
+    
+    strncpy(dest_string->string, c_string, length);
+    dest_string->len = length;
+
+    return OK;
+}
+
+
+
+/*
+ *  Return a temporary String from a C string, i e return a struct
+ *  pointing to the actual C string.  Suitable for sending a 'String'
+ *  object as parameter to a function (IF that function does not modify
+ *  it's parameter.  Note that normally String variables should be set
+ *  by s_crea_str(), to deallocate the memory used by it.
+ */
+EXPORT  String
+s_fcrea_str (const char	  * c_string)
+
+{
+    String	temp;
+
+    /* Cast needed to make compiler not warn about assignment from
+     * const pointer to non-const pointer.  Sigh...		*/
+    temp.string = (char *) c_string;
+    temp.len = strlen(c_string);
+    return  temp;
+}
+
+
+
+/*
+ *  Free's the space used by a String object.  The object is
+ *  set to EMPTY_STRING.
+ */
+EXPORT  void
+s_clear (String   * str)
+{
+    FREE_0 (str->string);
+    *str = EMPTY_STRING;
+}
+
+
+
+/*
+ *  Copy SOURCE_STRING to DEST_STRING.  Old value of DEST_STRING is
+ *  retained if an error was encountered.  If 'foo' is a separate
+ *  String, then it is legal to do  's_strcpy(&foo, foo)'.
+ */
+EXPORT  Success
+s_strcpy (String	* dest_string,
+	  const String	  source_string)
+
+{
+    void		* temp_ptr;	/* To hold result from malloc/realloc
+					 * before actually using it.  */
+
+    if (s_strlen(source_string) == 0)
+    {
+	s_clear (dest_string);
+	return OK;
+    }
+
+    /* (Re-)allocate memory */
+    temp_ptr = REALLOC_0 (dest_string->string, s_strlen(source_string));
+    if (temp_ptr == NULL)
+	return FAILURE;
+    dest_string->string = temp_ptr;
+    
+    /* Copy the string */
+    memcpy (dest_string->string,
+	    source_string.string,
+	    s_strlen (source_string));
+    dest_string->len = s_strlen (source_string);
+
+    return OK;
+}
+
+
+
+/*
+ *  In String STR remove the characters starting with number FIRST
+ *  and ending with number LAST, inclusive.  If FIRST > LAST, then
+ *  no characters are removed.
+ */
+extern  Success
+s_strdel (String	* str,
+	  String_size	  first,
+	  String_size	  last )
+
+{
+    String_size		i;	/* Just an index in a loop */
+
+
+    assert (   first >= 0  &&  first <= s_strlen (*str)
+	    && last >= -1  &&  last < s_strlen (*str));
+
+    for ( i = last + 1 ;  i < s_strlen(*str) ;  i++ )
+	str->string [i-(last-first+1)] = str->string [i];
+
+    str->len -= last-first+1;
+
+    return  OK;
+}
+
+
+
+/*
+ *  Append SOURCE_STRING to the end of DEST_STRING.  DEST_STRING is not
+ *  changed if an error is encountered.
+ */
+EXPORT  Success
+s_strcat (String	* dest_string,
+	  const String	  source_string)
+
+{
+    void		* temp_ptr;	/* To hold result from malloc/realloc
+					 * before actually using it.  */
+
+    /* (Re-)alloc space for new string */
+    temp_ptr = REALLOC_0 (dest_string->string,
+			  dest_string->len + source_string.len);
+    if (temp_ptr == NULL)
+    {
+	return FAILURE;
+    }
+    dest_string->string = (char *)temp_ptr;
+
+    /* Append SOURCE_STRING to *DEST_STRING */
+    memcpy (dest_string->string + s_strlen (*dest_string),
+	    source_string.string,
+	    s_strlen (source_string));
+    dest_string->len += source_string.len;
+
+    return OK;
+}
+
+
+
+/*
+ *  Extract a substring from SOURCE_STRING, starting with char no
+ *  START_CHAR and ending with char no END_CHAR.  First character
+ *  is character no 0.  If END_CHAR < START_CHAR, then DEST_STRING
+ *  is set to 'EMPTY_STRING'.  If END_CHAR is equal to the macro
+ *  'END_OF_STRING', then the substring reaches to the last character
+ *  in SOURCE_STRING.
+ */
+EXPORT  Success
+s_substr (String	* dest_string,
+	  const String	  source_string,
+	  String_size	  start_char,
+	  String_size	  end_char)
+
+{
+    String_size		  sub_len;	/* Length of substring */
+    void		* temp_ptr;	/* To hold result from malloc/realloc
+					 * before really using it.  */
+
+    if (end_char == END_OF_STRING)
+	end_char = s_strlen(source_string)-1;
+
+    assert (    start_char >= 0  &&  end_char >= -1
+	    &&  start_char <= s_strlen (source_string)
+	    &&  end_char < s_strlen (source_string));
+
+    sub_len = end_char - start_char + 1;
+
+    /* Will the substring be empty? */
+    if (sub_len <= 0)
+    {
+	s_clear (dest_string);	/* Free and set to EMPTY_STRING */
+	return OK;
+    }
+
+    /* (Re-)allocate space for substring */
+    temp_ptr = REALLOC_0(dest_string->string, sub_len);
+    if (temp_ptr == NULL)
+    {
+	return FAILURE;
+    }
+    dest_string->string = (char *)temp_ptr;
+
+    /* Copy substring to DEST_STRING */
+    memcpy (dest_string->string,
+	    source_string.string + start_char,
+	    sub_len);
+    dest_string->len = sub_len;
+
+    return OK;
+}
+
+
+
+/*
+ *  Fast extraction of a substring.  Returns an object of type
+ *  String wich points into SOURCE_STRING.  Thus you should NEVER
+ *  modify the result of this function.  (Raw character modifying
+ *  is OK if you know what you are doing, but never use anything
+ *  that might call free or realloc on it.)  If END_CHAR is equal
+ *  to the macro 'END_OF_STRING', then the substring reaches to
+ *  the last character in SOURCE_STRING.
+ */
+EXPORT  String
+s_fsubstr (const String	  source_string,
+	   String_size	  start_char,
+	   String_size	  end_char	)
+
+{
+    String	sub_string;	/* Substring struct */
+
+
+    if (end_char == END_OF_STRING)
+	end_char = s_strlen(source_string)-1;
+
+    assert (    start_char >= 0  &&  end_char >= -1
+	    &&  start_char <= s_strlen (source_string)
+	    &&  end_char < s_strlen (source_string));
+
+    sub_string.len = end_char - start_char + 1;
+
+    /* Is the substring empty? */
+    if (sub_string.len < 1)
+    {
+	return EMPTY_STRING;
+    }
+
+    sub_string.string = source_string.string + start_char;
+
+    return sub_string;
+}
+
+
+
+/*
+ *  Returns -1 if ARG is negative, 0 if 0 and +1 if positive.
+ *  Used in the string comparison routines.
+ */
+static  int
+sign (int  arg)
+{
+    if (arg < 0)
+	return  -1;
+    else if (arg == 0)
+	return   0;
+    else
+	return  +1;
+}
+
+
+
+/*
+ *  Compares two strings.  Returns -1 if STR1 is lexically less
+ *  than STR2, +1 if STR1 is greater than STR2, and 0 if they are
+ *  equal.
+ */
+EXPORT  int
+s_strcmp (String   str1,
+	  String   str2)
+
+{
+    u_int		index;
+    String_size		shortest;	/* Length of the shortest string */
+    int			retval_based_on_lengths;
+
+
+    retval_based_on_lengths = sign(str1.len - str2.len);
+
+    if (str1.len < str2.len)
+	shortest = str1.len;
+    else
+	shortest = str2.len;
+
+    
+    /*  If they point to the same string, then we only have to
+     *  compare the lengths.	*/
+    if (str1.string == str2.string)
+	return  retval_based_on_lengths;
+
+
+    /* Find first diff:ing character (in [index]) */
+    index = 0;
+    while (  (index < shortest)
+	   && (str1.string[index] == str2.string[index]) )
+	index++;
+
+    /* If no diff:ing char, then the shortest is the "smallest" */
+    if (index >= shortest)
+	return  retval_based_on_lengths;
+    else  /* ...else check which character was the "smallest". */
+	return  sign(str1.string[index] - str2.string[index]);
+
+}
+
+
+
+/*
+ *  Makes INDEX (type char) positive.  Those that are negative,
+ *  result in a positive number above the other numbers.  This
+ *  works as if bitcopying a 2's complement nuber to an unsigned
+ *  number.
+ *
+ *  NOTE:  This code might need to be modified for some arhitectures.
+ */
+#define POS_INDEX(index)	((u_char)(index))
+
+/*
+ *  Compares two strings with user specified collation order.
+ *  Returns the same values as s_srcmp().
+ *  COLLAT_TAB is a table of collating values for every char.
+ */
+EXPORT  int
+s_usr_strcmp (String	 str1,
+	      String     str2,
+	      char     * collat_tab)
+
+{
+    u_int		index;
+    String_size		shortest;	/* Length of the shortest string */
+    int			retval_based_on_lengths;
+
+
+    retval_based_on_lengths = sign(str1.len - str2.len);
+
+    if (str1.len < str2.len)
+	shortest = str1.len;
+    else
+	shortest = str2.len;
+
+    
+    /*  If they point to the same string, then we only have to
+     *  compare the lengths.	*/
+    if (str1.string == str2.string)
+	return  retval_based_on_lengths;
+
+
+    /* Find first diff:ing character (in [index-1]) */
+    index = 0;
+    while (   (index < shortest)
+	   && ( collat_tab [ POS_INDEX( str1.string [index] )]
+	       == collat_tab [ POS_INDEX( str2.string [index] )]) )
+	index++;
+
+    
+    /* If no diff:ing char, then the shortest is the "smallest" */
+    if (index >= shortest)
+	return  retval_based_on_lengths;
+
+    /* ...else check which character was the "smallest". */
+    else
+	return  sign( collat_tab [ POS_INDEX( str1.string[index] )]
+		     - collat_tab [ POS_INDEX( str2.string[index] )] );
+
+}
+
+
+
+/*
+ *  Checks if STR1 is the exact beginning of STR2, e g if STR1
+ *  is "foobar" and STR2 is "foobarf" then the result is TRUE.
+ */
+EXPORT  Bool
+s_strhead (String	str1,
+	   String	str2)
+
+{
+    String_size		i;	/*  Index in comparison loop  */
+
+
+    /*  If STR1 is longer than STR2, then it can't be a head.	*/
+    if (s_strlen(str1) > s_strlen(str2))
+	return  FALSE;
+
+    /*  If they point to the same string, then STR1 is a head
+     *  of STR2.  (We have already compared the lengths.)	*/
+    if (str1.string == str2.string)
+	return  TRUE;
+
+    /*  Check character by character  */
+    for ( i = 0 ;  i < s_strlen(str1) ;  i++)
+	if (str1.string[i] != str2.string[i])
+	    return FALSE;	/* Diff. found, so not head. */
+
+    /*  No differences found  */
+    return  TRUE;
+}
+
+
+
+/*
+ *  Checks if STR1 is the exact beginning of STR2, but uses a
+ *  user specified collating sequence for comparison (as in
+ *  s_usr_strcmp()).
+ */
+EXPORT  Bool
+s_usr_strhead (String	str1,
+	       String	str2,
+	       char	collat_tab [ COLLAT_TAB_SIZE ])
+
+{
+    String_size		i;	/*  Index in comparison loop  */
+
+
+    /*  If STR1 is longer than STR2, then it can't be a head.	*/
+    if (s_strlen(str1) > s_strlen(str2))
+	return  FALSE;
+
+    /*  If they point to the same string, then STR1 is a head
+     *  of STR2.  (We have already compared the lengths.)	*/
+    if (str1.string == str2.string)
+	return  TRUE;
+
+    /*  Check character by character  */
+    for ( i = 0 ;  i < s_strlen(str1) ;  i++)
+    {
+	if (  collat_tab [ POS_INDEX( str1.string[i] )]
+	    != collat_tab [ POS_INDEX( str2.string[i] )] )
+	{
+	    return FALSE;	/* Diff. found, so not head. */
+	}
+    }
+    
+    /*  No differences found  */
+    return  TRUE;
+}
+
+
+
+
+/*
+ *  From STR strip all trailing characters that can be found
+ *  in STRIP_STRING.
+ */
+extern  String
+s_strip_trailing (String	  str,
+		  const String	  strip_string)
+
+{
+    while (  s_strlen (str) > 0
+	   && s_strchr (strip_string,
+			str.string[s_strlen(str) - 1], 0) != -1)
+	str.len--;
+    return  str;
+}
+
+
+
+
+/*
+ *  Returns the index of the first occurrence in the String STR
+ *  of the character CH, starting at position STAR_POS.  Returns
+ *  -1 if no occurrence.
+ */
+EXPORT  String_size
+s_strchr (const String	  str,
+	  char		  ch,
+	  String_size	  start_pos)
+
+{
+    char		* ptr;
+
+    assert (start_pos >= 0  &&  start_pos <= s_strlen (str));
+
+    ptr = memchr (str.string + start_pos, ch, s_strlen (str) - start_pos);
+    if (ptr == NULL)
+	return  -1;
+    else
+	return  ptr - str.string;
+}
+
+
+
+/*
+ *  Returns the index of the last occurrence in the String STR
+ *  of the character CH, starting at position START_POS.  Returns
+ *  -1 if no occurrence.
+ */
+EXPORT  String_size
+s_strrchr (const String	  str,
+	   char		  ch,
+	   String_size	  start_pos)
+
+{
+    String_size		index;
+
+    if (start_pos == END_OF_STRING)
+	start_pos = s_strlen (str) - 1;
+
+    assert (start_pos >= -1  &&  start_pos < s_strlen (str));
+
+    index = start_pos;
+    while (index >= 0  &&  str.string[index] != ch)
+	index--;
+
+    return  index;	/* This will be -1 if not found. */
+}
+
+
+
+
+/*
+ *  Return the index of the first occurrence in the String LOOK_IN
+ *  of any of the characters in the String SEARCH_FOR, or -1 if none.
+ */
+extern  String_size
+s_strpbrk (const String	  look_in,
+	   const String	  search_for)
+
+{
+    String_size		  i;
+
+    for ( i = 0 ;  i < s_strlen (look_in) ;  i++ )
+	if (s_strchr (search_for, look_in.string[i], 0) != -1)
+	    return  i;
+
+    return  -1;
+}
+
+
+
+
+/*
+ *  Find the first character in LOOK_IN that *is* present in
+ *  SEARCH_FOR, and return its index, or the length of LOOK_IN if
+ *  it contains only characters that are not present in SEARCH_FOR.
+ */
+extern  String_size
+s_strcspn (const String	  look_in,
+	   const String	  search_for)
+
+{
+    String_size		  i;
+
+    i = 0;
+    while (  i < s_strlen (look_in)
+	   && s_strchr (search_for, look_in.string[i], 0) == -1)
+	i++;
+    return  i;
+}
+
+
+
+
+/*
+ *  Find the first character in LOOK_IN that is *not* present in
+ *  SKIP_CHARS, and return its index, or the length of LOOK_IN if
+ *  it contains only characters that are present in SKIP_CHARS.
+ */
+extern  String_size
+s_strspn (const String	  look_in,
+	  const String	  skip_chars)
+
+{
+    String_size		  i;
+
+    i = 0;
+    while (  i < s_strlen (look_in)
+	   && s_strchr (skip_chars, look_in.string[i], 0) != -1)
+	i++;
+    return  i;
+}
+
+
+
+
+
+/*
+ *  Pick out the first token from SOURCE separated by one or more
+ *  of the characters in SEPARATORS, starting in position START_POS.
+ *
+ *  More specifically: start in position START_POS and skip over
+ *  separator characters (any of those present in SEPARATORS).
+ *  Extract the substring starting with the first non-separator,
+ *  and ending the character immediately before the first separator
+ *  following.  *start_pos will be the index of the first separator
+ *  character after the token.
+ *
+ *  Note that the return value actually points into SOURCE.  It
+ *  is not separately allocated.
+ */
+EXPORT  String
+s_strtok (const String	  source,
+	  String_size	* start_pos,
+	  const String	  separators)
+
+{
+    String_size		first_char;	/* First character in token */
+    String_size		end_char;	/* First character after token */
+
+
+    /* Check of parameters - we might save some time on this */
+    if (   (*start_pos >= s_strlen(source))
+	|| s_empty(separators) || s_empty(source) )
+    {
+	return  EMPTY_STRING;
+    }
+
+    /* Skip leading separators */
+    first_char = *start_pos;
+    while (  (first_char < s_strlen(source))
+	   && (s_strchr (separators, source.string[first_char], 0) != -1) )
+	first_char++;
+
+    /* End of source string?  Then we can stop here. */
+    if (first_char >= s_strlen(source))
+    {
+	*start_pos = first_char;
+	return  EMPTY_STRING;
+    }
+
+    /* Find next separator */
+    end_char = first_char;
+    while (  (end_char < s_strlen(source))
+	   && (s_strchr (separators, source.string[end_char], 0) == -1) )
+	end_char++;
+
+    /* OK, we're practically done. */
+    *start_pos = end_char;
+    return  s_fsubstr(source, first_char, end_char-1);
+}
+
+
+
+
+/****************************************************
+ *	Misc. routines using our String type.	    *
+ ****************************************************/
+
+
+/*
+ *  Convert a char to a number in base BASE.
+ */
+static  int
+char2digit (const char	ch,
+	    const int	base)
+{
+    int			  index;
+    static  char	* translate_table	=
+				"0123456789abcdefghijklmnopqrstuvwxyz";
+
+    index = 0;
+    while (  (index < base)
+	   && (  translate_table[index]
+	       != (isalpha(ch) ? tolower(ch) : ch)))
+	index++;
+
+    if (index >= base)
+	return  -1;
+    else
+	return  index;
+}
+
+
+
+/*
+ *  Convert the String STR to a long, using the base BASE.
+ *  Leading blanks are skipped according to isblank() in <ctype.h>.
+ *  The index of the first character that couldn't be used to form
+ *  the number is returned in *FIRST_ILL_CHAR.  Returns -1 in
+ *  *first_ill_char if there was an error in the parameters.
+ *  BASE may be in the range 2..36
+ */
+#define MAXBASE	36
+EXPORT  long
+s_strtol (const String	  str,
+	  String_size	* first_ill_char,
+	  const int	  base		)
+
+{
+    long		  number	= 0;	/* The result */
+    int			  sign		= 0;	/* Sign o' the times :-) */
+    String_size		  char_no;
+    int			  digit;
+
+
+    assert (base >= 2  &&  base <= MAXBASE);
+
+    if (s_empty(str))
+    {
+	*first_ill_char = -1;
+	return  0;
+    }
+
+
+    /* Skip all blanks */
+    char_no = 0;
+    while ( (char_no < s_strlen(str)) && isspace(str.string[char_no]) )
+	char_no++;
+
+    /* Find any sign character (+ or -) */
+    if (str.string[char_no] == '+')
+    {
+	sign = +1;
+	char_no++;
+    }
+    else if (str.string[char_no] == '-')
+    {
+	sign = -1;
+	char_no++;
+    }
+
+    while (   (char_no < s_strlen(str))
+	   && ((digit = char2digit(str.string[char_no], base)) != -1) )
+    {
+	number = number * base + digit;
+	char_no++;
+    }
+
+    *first_ill_char = char_no++;
+    if (sign != -1)
+	return  number;
+    else
+	return  -number;
+}
+
+
+
+
+/************************************************
+ *	Input/Output routines for String	*
+ ************************************************/
+
+
+
+/*
+ *  Outputs the string STR on the stream STREAM.  No information
+ *  about the length of the string is output.
+ */
+EXPORT  Success
+s_fputs (FILE		* stream,
+	 const String	  str)
+
+{
+    String_size		i;
+
+    for ( i = 0 ;  i < str.len ;  i++ )
+	putc (str.string[i], stream);
+
+    return OK;
+}
+
+
+/*
+ * Create an ordinary C string from a String.
+ * The pointer returned will point to a '\0'-terminated character
+ * array which is obtained with the malloc-function supplied to
+ * s_set_storage_management(). It should be freed by the caller.
+ * NULL is returned if there is an error. The String may contain
+ * '\0's, but the resulting string will be truncated at the first
+ * '\n'. Thou shalt not depend on this behaviour. Later versions
+ * might substitute "foobar" for '\0's.
+ */
+
+EXPORT  char *
+s_crea_c_str(const String  source)
+{
+    char *dest;
+
+    dest = MALLOC_0( 1 + s_strlen(source) );
+
+    if ( dest == NULL )
+	return NULL;
+
+    memcpy(dest, source.string, s_strlen(source));
+    dest[ s_strlen(source) ] = '\0';
+    return dest;
+}
diff --git a/src/libraries/libmisc/s-string.h b/src/libraries/libmisc/s-string.h
new file mode 100644
index 0000000000000000000000000000000000000000..bc4c4ab189d2bca9186a9730ef783a4b684df476
--- /dev/null
+++ b/src/libraries/libmisc/s-string.h
@@ -0,0 +1,445 @@
+/*
+ *  s-string.h
+ *		Our own string type.  Definition of string type,
+ *		and functions to manipulate these strings.
+ *
+ *
+ *  Copyright (C) 1990	Lysator Computer Club,
+ *			Linkoping University,  Sweden
+ *
+ *  Everyone is granted permission to copy, modify and redistribute
+ *  this code, provided the people they give it to can.
+ *
+ *
+ *  Author:	Thomas Bellman
+ *		Lysator Computer Club
+ *		Linkoping University
+ *		Sweden
+ *
+ *  email:	Bellman@Lysator.LiU.SE
+ */
+
+
+
+#ifndef  S_STRING_H_ALREADY_INCLUDED__
+#define  S_STRING_H_ALREADY_INCLUDED__
+
+
+#include <limits.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#include <misc-types.h>
+
+#include "s-collat-tables.h"
+
+
+typedef 	long		String_size;
+#define		END_OF_STRING	LONG_MAX
+
+
+/*
+ *  All objects of type String *must* be initialized to EMPTY_STRING
+ *  before using any destructive function on them.  If you only use
+ *  non-destructive functions (s_strlen(), s_strcmp(), ...), you can
+ *  set them with
+ *	str = s_fcrea_str("Hej hopp i lingonskogen");
+ *  But the value of this may *not* be used in any destructive call,
+ *  since str.string points to read-only memory.
+
+ *  Note also that you need to call s_free() on any auto variables
+ *  of type String before exiting the block they are declared in,
+ *  since otherwise the memory they use will still be allocated.
+ *  This is of course the same rules as for normal pointers.
+
+ *  To make it possible for people to use their own storage
+ *  management routines, you can set the functions to use for
+ *  malloc(), realloc() and free() with the
+ *  s_set_storage_management() function.  This MUST be called
+ *  before using any of the other functions, even if you want to
+ *  use the normal malloc(), realloc() and free().
+
+ *  Terminology:
+ *  --	A "separate" String is an object that points to some memory
+ *	that is somehow obtained from malloc() or its cousins.  This
+ *	means that it is legal to free() or realloc() it.
+ */
+
+
+typedef struct {
+	String_size	  len;
+	unsigned char	* string;
+} String;
+
+/*
+ *  Note that the first character is String.string[0], and the last
+ *  character is String.string[String.len-1]
+ */
+
+
+/*  This is the representation of the empty String  */
+#define			EMPTY_STRING_i		((String) { 0, NULL })
+extern  const String	EMPTY_STRING;
+
+
+
+/*
+ *  Functions to manipulate strings of type 'String'.
+ *  All these functions return a value of type Success, which is
+ *  an enum of OK an FAILURE (do NOT trust the order of these!).
+ *
+ *  All functions automatically allocates (and deallocates) any
+ *  necessary storage.
+ */
+
+
+
+typedef void	(*free_function) (void *);
+typedef void  * (*malloc_function) (size_t);
+typedef void  * (*realloc_function) (void *, size_t);
+
+/*
+ *  Set the functions to use for storage management.  These must
+ *  be call compatible with the normal functions malloc(),
+ *  realloc() and free().
+ */
+extern  void
+s_set_storage_management (malloc_function	new_malloc,
+			  realloc_function	new_realloc,
+			  free_function		new_free);
+
+
+/*
+ *  Returns the number of characters in a String
+ */
+#define s_strlen(str)	((str).len)
+
+
+
+/*
+ *  Create an object of type String from an ordinary C string.
+ */
+extern  Success
+s_crea_str (String	* dest_string,
+	    const char	* c_string    );
+
+
+/*
+ * Create a string from a buffer. The contents of the buffer
+ * are copied into the new string.
+ */
+
+extern  Success
+s_mem_crea_str (String	    * dest_string,
+	    	const char  * buffer,
+	    	String_size   length);
+
+/*
+ * Create a string of a given size. The contents of the string
+ * are unspecified. The LysKOM-server uses this to get a string
+ * of a fixed size into which it can fread() data. This is probably
+ * not a good idea since it relies heavily on the implementation
+ * of strings. However, by using this function, those places are
+ * easy to identify if the implementation should be done differently.
+ */
+
+extern  Success
+s_size_crea_str(String      *result,
+		String_size length);
+
+/*
+ *  Return a temporary String from a C string, i e return a struct
+ *  pointing to the actual C string.  Suitable for sending a 'String'
+ *  object as parameter to a function (IF that function does not modify
+ *  it's parameter.  Note that normally String variables should be set
+ *  by s_crea_str(), to deallocate the memory used by it.
+ */
+extern  String
+s_fcrea_str (const char	  * c_string);
+
+
+
+/*
+ *  Free's the space used by a String object.  The object is
+ *  set to EMPTY_STRING.
+ */
+extern  void
+s_clear (String   * str);
+
+
+/*
+ * Create an ordinary C string from a String.
+ * The pointer returned will point to a '\0'-terminated character
+ * array which is obtained with the malloc-function supplied to
+ * s_set_storage_management(). It should be freed by the caller.
+ * NULL is returned if there is an error. The String may contain
+ * '\0's, but the resulting string will be truncated at the first
+ * '\n'. Thou shalt not depend on this behaviour. Later versions
+ * might substitute "foobar" for '\0's.
+ */
+
+
+extern  char *
+s_crea_c_str(const String  source);
+
+
+
+/*
+ *  Copy SOURCE_STRING to DEST_STRING.  Old value of DEST_STRING is
+ *  retained if an error was encountered.  Note that it is never
+ *  legal to do 's_strcpy(&foo, foo)', since the string 'foo' is
+ *  pointing to is reallocated before it is read.
+ */
+extern  Success
+s_strcpy (String	* dest_string,
+	  const String	  source_string);
+
+
+
+/*
+ *  In String STR remove the characters starting with number FIRST
+ *  and ending with number LAST, inclusive.  If FIRST > LAST, then
+ *  no characters are removed.
+ */
+extern  Success
+s_strdel (String	* str,
+	  String_size	  first,
+	  String_size	  last );
+
+
+
+/*
+ *  Append SOURCE_STRING to the end of DEST_STRING.  DEST_STRING is not
+ *  changed if an error is encountered.
+ */
+extern  Success
+s_strcat (String	* dest_string,
+	  const String	  source_string);
+
+
+
+/*
+ *  Extract a substring from SOURCE_STRING, starting with char no
+ *  START_CHAR and ending with char no END_CHAR.  First character
+ *  is character no 0.  If END_CHAR < START_CHAR, then DEST_STRING
+ *  is set to 'EMPTY_STRING'.  If END_CHAR is equal to the macro
+ *  'END_OF_STRING', then the substring reaches to the last character
+ *  in SOURCE_STRING.
+ */
+extern  Success
+s_substr (String	* dest_string,
+	  const String	  source_string,
+	  String_size	  start_char,
+	  String_size	  end_char);
+
+
+
+/*
+ *  Fast extraction of a substring.  Returns an object of type
+ *  String wich points into SOURCE_STRING.  Thus you should NEVER
+ *  modify the result of this function.  (Raw character modifying
+ *  is OK if you know what you are doing, but never use anything
+ *  that might call free or realloc on it.)  If END_CHAR is equal
+ *  to the macro 'END_OF_STRING', then the substring reaches to
+ *  the last character in SOURCE_STRING.
+ */
+extern  String
+s_fsubstr (const String	  source_string,
+	   String_size	  start_char,
+	   String_size	  end_char	);
+
+
+
+/*  Check if a string is the empty string. Returns TRUE or FALSE.
+ */
+#define s_empty(str) (((str).len == 0) ? TRUE : FALSE)
+
+
+/*  Check if two strings are equal.
+ */
+#define s_streq(str1, str2)	(s_strcmp(str1, str2) == 0)
+#define s_usr_streq(str1, str2, collat_tab)	\
+	(s_usr_strcmp(str1, str2, collat_tab) == 0)
+
+
+
+/*
+ *  Compares two strings.  Returns -1 if STR1 is lexically less
+ *  than STR2, +1 if STR1 is greater than STR2, and 0 if they are
+ *  equal.
+ */
+extern  int
+s_strcmp (String   str1,
+	  String   str2);
+
+
+
+/*
+ *  Compares two strings with user specified collation order.
+ *  Returns the same values as s_strcmp().
+ *  COLLAT_TAB is a table of collating values for every char.
+ */
+extern  int
+s_usr_strcmp (String	str1,
+	      String	str2,
+	      char	collat_tab [ COLLAT_TAB_SIZE ]);
+
+
+
+/*
+ *  Checks if STR1 is the exact beginning of STR2, e g if STR1
+ *  is "foobar" and STR2 is "foobarf" then the result is TRUE.
+ */
+extern  Bool
+s_strhead (String	str1,
+	   String	str2);
+
+
+
+/*
+ *  Checks if STR1 is the exact beginning of STR2, but uses a
+ *  user specified collating sequence for comparison (as in
+ *  s_usr_strcmp()).
+ */
+extern  Bool
+s_usr_strhead (String	str1,
+	       String	str2,
+	       char	collat_tab [ COLLAT_TAB_SIZE ]);
+
+
+
+/*
+ *  From STR strip all trailing characters that can be found
+ *  in STRIP_STRING.  STR isn't altered in any way.  The returned
+ *  object points to the same string as STR, but with a possibly
+ *  shorter length.  The pointer is unchanged *even* if the length
+ *  should be 0, which means you don't "lose" the storage but can
+ *  free it with s_free().
+ */
+extern  String
+s_strip_trailing (String	  str,
+		  const String	  strip_string);
+
+
+
+/*
+ *  Returns the index of the first occurrence in the String STR
+ *  of the character CH.  Returns -1 if no occurrence.
+ */
+extern  String_size
+s_strchr (const String	  str,
+	  char		  ch,
+	  String_size	  start_pos);
+
+
+
+/*
+ *  Returns the index of the last occurrence in the String STR
+ *  of the character CH.  Returns -1 if no occurrence.
+ */
+extern  String_size
+s_strrchr (const String	  str,
+	   char		  ch,
+	   String_size	  start_pos);
+
+
+
+/*
+ *  Return the index of the first occurrence in the String LOOK_IN
+ *  of any of the characters in the String SEARCH_FOR, or -1 if none.
+ */
+extern  String_size
+s_strpbrk (const String	  look_in,
+	   const String	  search_for);
+
+
+
+/*
+ *  Find the first character in LOOK_IN that *is* present in
+ *  SEARCH_FOR, and return its index, or the length of LOOK_IN if
+ *  it contains only characters that are not present in SEARCH_FOR.
+ */
+extern  String_size
+s_strcspn (const String	  look_in,
+	   const String	  search_for);
+
+
+
+/*
+ *  Find the first character in LOOK_IN that is *not* present in
+ *  SKLIP_CHARS, and return its index, or the length of LOOK_IN if
+ *  it contains only characters that are present in SKIP_CHARS.
+ */
+extern  String_size
+s_strspn (const String	  look_in,
+	  const String	  skip_chars);
+
+
+
+/*
+ *  Pick out the first token from SOURCE separated by one or more
+ *  of the characters in SEPARATORS, starting in position START_POS.
+ *
+ *  More specifically: start in position START_POS and skip over
+ *  separator characters (any of those present in SEPARATORS).
+ *  Extract the substring starting with the first non-separator,
+ *  and ending the character immediately before the first separator
+ *  following.  *start_pos will be the index of the first separator
+ *  character after the token.
+ *
+ *  Note that the return value actually points into SOURCE.  It
+ *  is not separately allocated.
+ */
+extern  String
+s_strtok (const String	  source,
+	  String_size	* start_pos,
+	  const String	  separators);
+
+
+
+
+/****************************************************
+ *	Misc. routines using our String type.	    *
+ ****************************************************/
+
+
+/*
+ *  Convert the String STR to a long, using the base BASE.
+ *  Leading blanks are skipped according to isblank() in <ctype.h>.
+ *  The index of the first character that couldn't be used to form
+ *  the number is returned in *FIRST_ILL_CHAR.  Returns -1 in
+ *  *first_ill_char if there was an error in the parameters.
+ *  BASE may be in the range 2..36
+ */
+extern  long
+s_strtol (const String	  str,
+	  String_size	* first_ill_char,
+	  const int	  base		);
+
+
+
+
+/************************************************
+ *	Input/Output routines for String	*
+ ************************************************/
+
+
+
+/*
+ *  Outputs the string STR on the stream STREAM.  No information
+ *  about the length of the string is output.
+ */
+extern Success
+s_fputs (FILE		* stream,
+	 const String	  str);
+
+
+
+/*
+ *  Outputs the string STR on stdout.  No information
+ *  about the length of the string is output.
+ */
+#define s_puts(str) s_fputs(stdout, str)
+
+
+#endif  /*  _S_STRING_H_ALREADY_INCLUDED__  */
diff --git a/src/libraries/libmisc/zmalloc.c b/src/libraries/libmisc/zmalloc.c
new file mode 100644
index 0000000000000000000000000000000000000000..80a20070789245120d7da8acd95c6dc768a110f7
--- /dev/null
+++ b/src/libraries/libmisc/zmalloc.c
@@ -0,0 +1,171 @@
+/*
+ *  zmalloc.c
+ *		
+ *
+ *
+ *  Copyright (C) 1990	Lysator Computer Club,
+ *			Linkoping University,  Sweden
+ *
+ *  Everyone is granted permission to copy, modify and redistribute
+ *  this code, provided the people they give it to can.
+ *
+ *
+ *  Author:	Thomas Bellman
+ *		Lysator Computer Club
+ *		Linkoping University
+ *		Sweden
+ *
+ *  email:	Bellman@Lysator.LiU.SE
+ *
+ *
+ *  Any opinions expressed in this code are the author's PERSONAL opinions,
+ *  and does NOT, repeat NOT, represent any official standpoint of Lysator,
+ *  even if so stated.
+ */
+
+
+
+#include <stddef.h>
+#include <malloc.h>
+#include <string.h>
+
+#include <compiler.h>
+
+#include "zmalloc.h"
+
+
+#define EXPORT
+
+
+typedef	struct	{
+	int		refcount;
+	size_t		size;
+}  z_info;
+
+
+
+#define	REFCOUNT(pointer)	\
+	(((z_info *) ((char *) pointer - sizeof (z_info)))->refcount)
+
+#define	AREA_SIZE(pointer)	\
+	(((z_info *) ((char *) pointer - sizeof (z_info)))->size)
+
+
+#define MIN(n1, n2)		(((n1) < (n2)) ? (n1) : (n2))
+
+
+
+EXPORT  void *
+zmalloc (size_t	   size)
+{
+    void		* memory;
+
+    memory = malloc (size + sizeof (z_info));
+    if (memory == NULL)
+	return  NULL;
+    ((z_info *) memory)->size = size;
+    ((z_info *) memory)->refcount = 1;
+    return  (char *) memory + sizeof (z_info);
+}
+
+
+
+EXPORT  void *
+zcalloc (size_t	   n,
+	 size_t	   size)
+
+{
+    void		* memory;
+
+    memory = malloc (n * size + sizeof (z_info));
+    if (memory == NULL)
+	return  NULL;
+    ((z_info *) memory)->size = n * size;
+    ((z_info *) memory)->refcount = 1;
+    memset ((char *) memory + sizeof (z_info),
+	    0, n * size);
+
+    return  (char *) memory + sizeof (z_info);
+}
+
+
+
+EXPORT  void *
+zrealloc (void	  * ptr,
+	  size_t    size)
+
+{
+    void		* memory;
+
+    if (ptr == NULL)
+	return  zmalloc (size);
+    if (REFCOUNT (ptr) > 1)
+    {
+	memory = zmalloc (size);
+	if (memory == NULL)
+	    return  NULL;
+	memcpy (memory, ptr, MIN (size, AREA_SIZE (ptr)));
+	--REFCOUNT (ptr);
+	return  memory;
+    }
+    else
+    {
+	memory = realloc ((char *) ptr - sizeof (z_info),
+			  size + sizeof (z_info));
+	return  (char *) memory + sizeof (z_info);
+    }
+}
+
+
+
+EXPORT  void
+zfree (void	* ptr)
+{
+    if (ptr != NULL && --REFCOUNT (ptr) <= 0)
+    {
+	free ((char *) ptr - sizeof (z_info));
+    }
+}
+
+
+
+EXPORT  void
+zdestruct (void	  * ptr)
+{
+    if (ptr != NULL)
+	free ((char *) ptr - sizeof (z_info));
+}
+
+
+
+EXPORT  void *
+zuse (void	* ptr)
+{
+    if (ptr != NULL)
+    {
+	++REFCOUNT (ptr);
+    }
+    return  ptr;
+}
+
+
+
+EXPORT  void *
+zown (void	* ptr)
+{
+    void	* memory;
+
+    if (ptr == NULL)
+	return  NULL;
+    if (REFCOUNT (ptr) == 1)
+	return  ptr;
+    else
+    {
+	if ((memory = malloc (AREA_SIZE (ptr))) == NULL)
+	    return  NULL;
+	memcpy (memory, ptr, AREA_SIZE (ptr));
+	zfree (ptr);
+
+	return  memory;
+    }
+}
diff --git a/src/libraries/libmisc/zmalloc.h b/src/libraries/libmisc/zmalloc.h
new file mode 100644
index 0000000000000000000000000000000000000000..a11a8c256b6959ea832492097e8cd41d9425f52f
--- /dev/null
+++ b/src/libraries/libmisc/zmalloc.h
@@ -0,0 +1,116 @@
+/*
+ *  zmalloc.h  --  Memory allocation routines with reference counts
+ *
+ *
+ *  Copyright (C) 1990	Lysator Computer Club,
+ *			Linkoping University,  Sweden
+ *
+ *  Everyone is granted permission to copy, modify and redistribute
+ *  this code, provided the people they give it to can.
+ *
+ *
+ *  Author:	Thomas Bellman
+ *		Lysator Computer Club
+ *		Linkoping University
+ *		Sweden
+ *
+ *  email:	Bellman@Lysator.LiU.SE
+ */
+
+
+#ifndef  _ZMALLOC_H_INCLUDED__
+#define  _ZMALLOC_H_INCLUDED__
+
+
+/* Declare 'size_t' */
+#include <stddef.h>
+
+#include <compiler.h>
+
+
+
+/*
+ *  Allocate a piece of memory and set its reference count to 1.
+ *  Allocating a zero sized object is allowed, and results in a
+ *  unique pointer that can be used by all the other routines in
+ *  this package, and must be released using zfree(), but it
+ *  points to "nothing".
+ */
+extern  void *
+zmalloc (size_t	   size);
+
+
+/*
+ *  Allocate N contigous objects of size SIZE, set the contents
+ *  to binary 0 and set the reference count to 1.  Allocating 0
+ *  objecs, or objects of size zero, is allowed, and results in a
+ *  unique pointer that can be used by all the other routines in
+ *  this package, and must be released using zfree(), but it
+ *  points to "nothing".
+ */
+extern  void *
+zcalloc (size_t	   n,
+	 size_t	   size);
+
+
+/*
+
+ *  Reallocate the storage PTR points to the size SIZE.  If
+ *  "others" are still holding references to this memory, they
+ *  can still use it, and the caller of zrealloc() gets a copy of
+ *  the original memory area.  NULL is returned if the request
+ *  couldn't be honored, and the memory area is still in use by
+ *  the caller.  Reallocating the NULL pointer is equivalent to
+ *  doing a zmalloc() with the same size.  The same rules for
+ *  allocating objects of size 0 as for zmalloc() and zcalloc()
+ *  applies.
+
+ */
+extern  void *
+zrealloc (void	  * ptr,
+	  size_t    size);
+
+
+/*
+ *  Indicate that the memory pointed to by PTR is not used anymore
+ *  by the caller, i e the reference count is decremented by one.
+ *  The memory pointed to might be released as a result of this
+ *  call.  Freeing the NULL pointer is a no-op.
+ */
+extern  void
+zfree (void	* ptr);
+
+
+
+/*
+ *  Free the area pointed to by PTR regardless of how many are
+ *  referencing it.  This invalidiates all pointers to the area.
+ *  Calling zdestruct() on a NULL pointer is a no-op.
+ */
+extern  void
+zdestruct (void	  * ptr);
+
+
+
+/*
+ *  Add onother user of the memory pointed to by PTR, i e increase
+ *  the reference count by one.  Return value is PTR.  Using the
+ *  NULL pointer is a no-op, i e it just returns NULL.
+ */
+extern  void *
+zuse (void	* ptr);
+
+
+
+/*
+ *  Get a private copy of the area pointed to by PTR.  If
+ *  necessary, i e if others are holding references to the area,
+ *  copies the contents to a new place, and releases the original
+ *  area.  If you want to keep a reference to the old area, you
+ *  should do 'zown(zuse(p))'.
+ */
+extern  void *
+zown (void	* ptr);
+
+
+#endif  /*  _ZMALLOC_H_INCLUDED__  */