+
+
+
+/*
+ * Return a newly-allocated string whose contents
+ * concatenate those of s1, s2, s3.
+ */
+char *
+concat (s1, s2, s3)
+ char *s1, *s2, *s3;
+{
+ int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
+ char *result = xnew (len1 + len2 + len3 + 1, char);
+
+ strcpy (result, s1);
+ strcpy (result + len1, s2);
+ strcpy (result + len1 + len2, s3);
+ result[len1 + len2 + len3] = '\0';
+
+ return result;
+}
+
+/*
+ * Read a line of text from `stream' into `linebuffer'.
+ * Return the number of characters read from `stream',
+ * which is the length of the line including the newline, if any.
+ */
+long
+readline (linebuffer, stream)
+ struct linebuffer *linebuffer;
+ register FILE *stream;
+{
+ char *buffer = linebuffer->buffer;
+ register char *p = linebuffer->buffer;
+ register char *pend;
+ int chars_deleted;
+
+ pend = p + linebuffer->size; /* Separate to avoid 386/IX compiler bug. */
+
+ while (1)
+ {
+ register int c = getc (stream);
+ if (p == pend)
+ {
+ linebuffer->size *= 2;
+ buffer = (char *) xrealloc (buffer, linebuffer->size);
+ p += buffer - linebuffer->buffer;
+ pend = buffer + linebuffer->size;
+ linebuffer->buffer = buffer;
+ }
+ if (c == EOF)
+ {
+ *p = '\0';
+ chars_deleted = 0;
+ break;
+ }
+ if (c == '\n')
+ {
+ if (p > buffer && p[-1] == '\r')
+ {
+ *--p = '\0';
+ chars_deleted = 2;
+ }
+ else
+ {
+ *p = '\0';
+ chars_deleted = 1;
+ }
+ break;
+ }
+ *p++ = c;
+ }
+
+ return (p - buffer + chars_deleted);
+}
+
+/*
+ * Like malloc but get fatal error if memory is exhausted.
+ */
+long *
+xmalloc (size)
+ unsigned int size;
+{
+ long *result = (long *) malloc (size);
+ if (result == NULL)
+ fatal ("virtual memory exhausted");
+ return result;
+}
+
+long *
+xrealloc (ptr, size)
+ char *ptr;
+ unsigned int size;
+{
+ long *result = (long *) realloc (ptr, size);
+ if (result == NULL)
+ fatal ("virtual memory exhausted");
+ return result;
+}
+
+void
+fatal (message)
+ char *message;
+{
+ fprintf (stderr, "%s: %s\n", progname, message);
+ exit (BAD);
+}
+