+#ifdef BUILDING_VARIANT
+# ifdef LEGACY_CRT1_ENVIRON
+extern char **_saved_environ;
+# endif /* LEGACY_CRT1_ENVIRON */
+#else /* !BUILDING_VARIANT */
+# ifdef LEGACY_CRT1_ENVIRON
+__private_extern__ char **_saved_environ = NULL;
+
+static int
+_legacy_crt1_environ(void)
+{
+ if (_saved_environ) *_NSGetEnviron() = _saved_environ;
+ return 0;
+}
+int (*_cthread_init_routine)(void) = _legacy_crt1_environ;
+
+# else /* !LEGACY_CRT1_ENVIRON */
+static int _do_nothing(void) { return 0; }
+int (*_cthread_init_routine)(void) = _do_nothing;
+# endif /* !LEGACY_CRT1_ENVIRON */
+
+__private_extern__ struct owned_ptr *__env_owned = NULL;
+
+/*
+ * The owned_ptr structure is a table of pointers that we own, and can
+ * realloc/free as we choose. table[0] is always NULL, so it is always
+ * less that any real pointer. "used" is the number of table entries in use
+ * (including the initial NULL), while "size" is the allocated size of the
+ * table (used to enlarge the size of the table when needed).
+ */
+struct owned_ptr {
+ const void **table;
+ int used;
+ int size;
+};
+
+#define OWNED_PTR_INITIAL_SIZE 8
+
+__private_extern__ int _owned_ptr_search(struct owned_ptr * __restrict, const void * __restrict, int * __restrict);
+
+__private_extern__ void
+_owned_ptr_add(struct owned_ptr * __restrict owned, const void * __restrict ptr)
+{
+ int index;
+
+ if (_owned_ptr_search(owned, ptr, &index) == 0) return; /* already there */
+ if (owned->used >= owned->size) {
+ int new_size = 2 * owned->size;
+ const void **new_table = (const void **)realloc(owned->table,
+ new_size * sizeof(const void *));
+ if (!new_table) {
+ /* no memory to enlarge the table, so just drop */
+ return;
+ }
+ owned->table = new_table;
+ owned->size = new_size;
+ }
+ memmove(owned->table + index + 2, owned->table + index + 1,
+ sizeof(void *) * (owned->used - index - 1));
+ owned->table[index + 1] = ptr;
+ owned->used++;
+}
+
+__private_extern__ struct owned_ptr *
+_owned_ptr_alloc(void)
+{
+ struct owned_ptr *owned;
+
+ owned = (struct owned_ptr *)malloc(sizeof(struct owned_ptr));
+ if (!owned) return NULL;
+ owned->table = (const void **)malloc(OWNED_PTR_INITIAL_SIZE *
+ sizeof(const void *));
+ if (!owned->table) {
+ int save = errno;
+ free(owned);
+ errno = save;
+ return NULL;
+ }
+ owned->table[0] = NULL;
+ owned->used = 1;
+ owned->size = OWNED_PTR_INITIAL_SIZE;
+ return owned;
+}
+
+__private_extern__ void
+_owned_ptr_delete(struct owned_ptr *owned, int index)
+{
+ if (!index || index >= owned->used) return;
+ memmove(owned->table + index, owned->table + index + 1,
+ sizeof(void *) * (owned->used - index - 1));
+ owned->used--;
+}
+
+__private_extern__ void
+_owned_ptr_free(struct owned_ptr *owned)
+{
+ free(owned->table);
+ free(owned);
+}
+
+/*
+ * Search owned->table for "ptr". Zero is returned if found, non-zero means
+ * not found. If "result" is non-NULL, the found index is returned in it, or
+ * if not found, the index of the immediate lower value (ptr can be inserted
+ * after this index).
+ */
+__private_extern__ int
+_owned_ptr_search(struct owned_ptr * __restrict owned, const void * __restrict ptr, int * __restrict result)
+{
+ int low = 0;
+ int high = owned->used - 1;
+ int cur;
+
+ if (owned->table[high] < ptr) {
+ if (result) *result = high;
+ return -1;
+ } else if (owned->table[high] == ptr) {
+ if (result) *result = high;
+ return 0;
+ }
+ while (high - low > 1) {
+ cur = (low + high) / 2;
+ if (ptr > owned->table[cur]) {
+ low = cur;
+ } else if (ptr < owned->table[cur]) {
+ high = cur;
+ } else {
+ /* match found */
+ if (result) *result = cur;
+ return 0;
+ }
+ }
+ /* no match found; *result will be the insert-after position */
+ if (result) *result = low;
+ return -1;
+}
+
+/*
+ * Initialize the process's __env_owned structure
+ */
+__private_extern__ int
+__init__env_owned_locked(int should_set_errno)
+{
+ int save;
+
+ if (__env_owned) return 0;
+
+ if (!should_set_errno)
+ save = errno;
+ __env_owned = _owned_ptr_alloc();
+ if (!__env_owned) {
+ if (!should_set_errno)
+ errno = save;
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * The copy flag may have 3 values:
+ * 1 - make a copy of the name/value pair
+ * 0 - take the name as a user-supplied name=value string
+ * -1 - like 0, except we copy of the name=value string in name
+ */
+__private_extern__ int
+__setenv_locked(name, value, rewrite, copy, environp, owned)