+
+static void
+index_elem_add(int type, char *a, char *b)
+{
+ struct index_elem *tmp = NULL, *cur, *cur2;
+ int field, len = 0;
+
+ if(!a || !*a)
+ return;
+
+ switch(type) {
+ case INDEX_TEXT:
+ tmp = xmalloc(sizeof(struct index_elem));
+ tmp->d.text = xstrdup(a);
+ break;
+ case INDEX_FIELD: /* fall through */
+ case INDEX_ALT_FIELD:
+ find_field_number(a, &field);
+ if(field == -1)
+ return;
+ len = (b && *b && is_number(b)) ? atoi(b) : 0;
+ tmp = xmalloc(sizeof(struct index_elem));
+ tmp->d.field.id = field;
+ tmp->d.field.len = len;
+ break;
+ default:
+ assert(0);
+ }
+ tmp->type = type;
+ tmp->next = NULL;
+ tmp->d.field.next = NULL;
+
+ if(!index_elements) { /* first element */
+ index_elements = tmp;
+ return;
+ }
+
+ for(cur = index_elements; cur->next; cur = cur->next)
+ ;
+ if(type != INDEX_ALT_FIELD)
+ cur->next = tmp;
+ else { /* add as an alternate field */
+ tmp->d.field.len = cur->d.field.len;
+ for(cur2 = cur; cur2->d.field.next; cur2 = cur2->d.field.next)
+ ;
+ cur2->d.field.next = tmp;
+ }
+}
+
+static void
+parse_index_format(char *s)
+{
+ char *p, *start, *lstart = NULL;
+ int in_field = 0, in_alternate = 0, in_length = 0, type;
+
+ p = start = s;
+
+ while(*p) {
+ if(*p == '{' && !in_field) {
+ *p = 0;
+ index_elem_add(INDEX_TEXT, start, NULL);
+ start = ++p;
+ in_field = 1;
+ } else if(*p == ':' && in_field && !in_alternate) {
+ *p = 0;
+ lstart = ++p;
+ in_length = 1;
+ } else if(*p == '|' && in_field) {
+ *p = 0;
+ type = in_alternate ? INDEX_ALT_FIELD : INDEX_FIELD;
+ index_elem_add(type, start, in_length ? lstart : NULL);
+ start = ++p;
+ in_length = 0;
+ in_alternate = 1;
+ } else if(*p == '}' && in_field) {
+ *p = 0;
+ type = in_alternate ? INDEX_ALT_FIELD : INDEX_FIELD;
+ index_elem_add(type, start, in_length ? lstart : NULL);
+ start = ++p;
+ in_field = in_alternate = in_length = 0;
+ } else
+ p++;
+ }
+ if(!in_field)
+ index_elem_add(INDEX_TEXT, start, NULL);
+}
+
+void
+init_index()
+{
+ assert(!index_elements);
+ parse_index_format(opt_get_str(STR_INDEX_FORMAT));
+}