+ int i;
+ char *p;
+
+ // If target address is not wildcard, add the database
+ if (*set->target && !zurl_wildcard(set->target))
+ find_database(set->target, 0);
+
+ // Determine if we already have a dictionary entry
+ if (!strncmp(set->name, "pz:", 3) && (p = strchr(set->name + 3, ':')))
+ *(p + 1) = '\0';
+ for (i = 0; i < dictionary->num; i++)
+ if (!strcmp(dictionary->dict[i], set->name))
+ return;
+
+ if (!strncmp(set->name, "pz:", 3)) // Probably a typo in config file
+ {
+ yaz_log(YLOG_FATAL, "Unknown pz: setting '%s'", set->name);
+ exit(1);
+ }
+
+ // Create a new dictionary entry
+ // Grow dictionary if necessary
+ if (!dictionary->size)
+ dictionary->dict = nmem_malloc(nmem, (dictionary->size = 50) * sizeof(char*));
+ else if (dictionary->num + 1 > dictionary->size)
+ {
+ char **tmp = nmem_malloc(nmem, dictionary->size * 2 * sizeof(char*));
+ memcpy(tmp, dictionary->dict, dictionary->size * sizeof(char*));
+ dictionary->dict = tmp;
+ dictionary->size *= 2;
+ }
+ dictionary->dict[dictionary->num++] = nmem_strdup(nmem, set->name);
+}
+
+// This is called from grep_databases -- adds/overrides setting for a target
+// This is also where the rules for precedence of settings are implemented
+static void update_database(void *context, struct database *db)
+{
+ struct setting *set = (struct setting *) context;
+ struct setting *s, **sp;
+ int offset;
+
+ // Is this the right database?
+ if (!match_zurl(db->url, set->target))
+ return;
+
+#ifdef GAGA
+ // Initialize settings array if it doesn't exist.
+ // If so, also set the 'id' automatic setting
+ if (!db->settings)
+ {
+ struct setting *id = nmem_malloc(nmem, sizeof(struct setting));
+
+ db->settings = nmem_malloc(nmem, sizeof(struct settings*) * dictionary->num);
+ memset(db->settings, 0, sizeof(struct settings*) * dictionary->num);
+ id->precedence = 0;
+ id->name = "pz:id";
+ id->target = id->value = db->url;
+ id->next = 0;
+ db->settings[PZ_ID] = id;
+ }
+#endif
+ if ((offset = settings_offset_cprefix(set->name)) < 0)
+ abort(); // Should never get here
+
+ // First we determine if this setting is overriding any existing settings
+ // with the same name.
+ for (s = db->settings[offset], sp = &db->settings[offset]; s;
+ sp = &s->next, s = s->next)
+ if (!strcmp(s->name, set->name))
+ {
+ if (s->precedence < set->precedence)
+ // We discard the value (nmem keeps track of the space)
+ *sp = (*sp)->next; // unlink value from existing setting
+ else if (s->precedence > set->precedence)
+ // Db contains a higher-priority setting. Abort search
+ break;
+ if (zurl_wildcard(s->target) > zurl_wildcard(set->target))
+ // target-specific value trumps wildcard. Delete.
+ *sp = (*sp)->next; // unlink.....
+ else if (!zurl_wildcard(s->target))
+ // Db already contains higher-priority setting. Abort search
+ break;
+ }
+ if (!s) // s will be null when there are no higher-priority settings -- we add one
+ {
+ struct setting *new = nmem_malloc(nmem, sizeof(*new));
+
+ memset(new, 0, sizeof(*new));
+ new->precedence = set->precedence;
+ new->target = nmem_strdup(nmem, set->target);
+ new->name = nmem_strdup(nmem, set->name);
+ new->value = nmem_strdup(nmem, set->value);
+ new->next = db->settings[offset];
+ db->settings[offset] = new;
+ }
+}
+
+// Callback -- updates database records with dictionary entries as appropriate
+// This is used in pass 2 to assign name/value pairs to databases
+static void update_databases(struct setting *set)
+{
+ predef_grep_databases(set, 0, update_database);
+}
+
+// This simply copies the 'hard' (application-specific) settings
+// to the settings dictionary.
+static void initialize_hard_settings(struct setting_dictionary *dict)
+{
+ dict->dict = nmem_malloc(nmem, sizeof(hard_settings) - sizeof(char*));
+ dict->size = (sizeof(hard_settings) - sizeof(char*)) / sizeof(char*);
+ memcpy(dict->dict, hard_settings, dict->size * sizeof(char*));
+ dict->num = dict->size;
+}
+
+// Read any settings names introduced in service definition (config) and add to dictionary
+// This is done now to avoid errors if user settings are declared in session overrides
+static void initialize_soft_settings()
+{
+ struct conf_service *service = config->servers->service;
+ int i;
+
+ for (i = 0; i < service->num_metadata; i++)
+ {
+ struct setting set;
+ struct conf_metadata *md = &service->metadata[i];
+
+ if (md->setting == Metadata_setting_no)
+ continue;
+
+ set.precedence = 0;
+ set.target = "";
+ set.name = md->name;
+ set.value = "";
+ set.next = 0;
+ prepare_dictionary(&set);
+ }