From 988181b71ee24df0c349a2c0ad0a0e656eefe7e9 Mon Sep 17 00:00:00 2001
From: James Y Knight <jyknight@google.com>
Date: Tue, 30 Jul 2019 11:59:25 -0400
Subject: [PATCH] Add support for the glibc-specific error.h header.

This includes the functions 'error', 'error_at_line', and their
associated global variables.
---
 dynamic.list       |  4 +++
 include/error.h    | 21 ++++++++++++++
 src/legacy/error.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 94 insertions(+)
 create mode 100644 include/error.h
 create mode 100644 src/legacy/error.c

diff --git a/dynamic.list b/dynamic.list
index ee0d363b..9c8450f4 100644
--- a/dynamic.list
+++ b/dynamic.list
@@ -42,4 +42,8 @@ __progname;
 __progname_full;
 
 __stack_chk_guard;
+
+error_print_progname;
+error_message_count;
+error_one_per_line;
 };
diff --git a/include/error.h b/include/error.h
new file mode 100644
index 00000000..03b1ca41
--- /dev/null
+++ b/include/error.h
@@ -0,0 +1,21 @@
+#ifndef _ERROR_H
+#define _ERROR_H
+
+#include <features.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void (*error_print_progname) (void);
+extern unsigned int error_message_count;
+extern int error_one_per_line;
+
+void error(int, int, const char *, ...);
+void error_at_line(int, int, const char *, unsigned int, const char *, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/legacy/error.c b/src/legacy/error.c
new file mode 100644
index 00000000..c5000fa4
--- /dev/null
+++ b/src/legacy/error.c
@@ -0,0 +1,69 @@
+#include <error.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "libc.h"
+
+void (*error_print_progname) (void) = 0;
+unsigned int error_message_count = 0;
+int error_one_per_line = 0;
+
+static unsigned int saved_linenum = 0;
+static const char *saved_file = 0;
+
+static void errorv(int status, int errnum, const char *file, unsigned int linenum, const char *fmt, va_list ap)
+{
+	++error_message_count;
+
+	fflush(stdout);
+	flockfile(stderr);
+
+	if (error_print_progname)
+		error_print_progname();
+	else {
+		fprintf(stderr, "%s:", __progname_full);
+		if (!file)
+			fputc(' ', stderr);
+	}
+
+	if (file)
+		fprintf(stderr, "%s:%u: ", file, linenum);
+
+	vfprintf(stderr, fmt, ap);
+	if (errnum)
+		fprintf(stderr, ": %s", strerror(errnum));
+	fputc('\n', stderr);
+
+	funlockfile(stderr);
+
+	if (status)
+		exit(status);
+}
+
+void error(int status, int errnum, const char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	errorv(status, errnum, NULL, 0, fmt, ap);
+	va_end(ap);
+}
+
+void error_at_line(int status, int errnum, const char *file, unsigned int linenum, const char *fmt, ...)
+{
+	if (error_one_per_line) {
+		if(saved_linenum == linenum && file != NULL &&
+		   saved_file != NULL && !strcmp(file, saved_file))
+			return;
+		saved_linenum = linenum;
+		// Assuming that the lifetime of the passed in file name extends
+		// until the next call is rather questionable, but appears to be
+		// the expected semantics.
+		saved_file = file;
+	}
+
+	va_list ap;
+	va_start(ap, fmt);
+	errorv(status, errnum, file, linenum, fmt, ap);
+	va_end(ap);
+}
-- 
2.22.0.709.g102302147b-goog