5 * by JH <jheinonen@users.sourceforge.net>
7 * Copyright (C) Jaakko Heinonen
25 abook_field_list *fields_list = NULL;
28 list_item *database = NULL;
31 #define ITEM_SIZE (fields_count * sizeof(char *))
33 #define INITIAL_LIST_CAPACITY 30
34 static int list_capacity = 0;
36 int standard_fields_indexed[ITEM_FIELDS];
39 * notes about adding predefined "standard" fields:
40 * - leave alone "name" and "email"
41 * - reorganize the field numbers in database.h
43 abook_field standard_fields[] = {
44 {"name", N_("Name"), FIELD_STRING}, /* NAME */
45 {"email", N_("E-mail addresses"), FIELD_EMAILS}, /* EMAIL */
46 {"address", N_("Address"), FIELD_STRING}, /* ADDRESS */
47 {"address2", N_("Address2"), FIELD_STRING}, /* ADDRESS2 */
48 {"city", N_("City"), FIELD_STRING}, /* CITY */
49 {"state", N_("State/Province"), FIELD_STRING}, /* STATE */
50 {"zip", N_("ZIP/Postal Code"), FIELD_STRING}, /* ZIP */
51 {"country", N_("Country"), FIELD_STRING}, /* COUNTRY */
52 {"phone", N_("Home Phone"), FIELD_STRING}, /* PHONE */
53 {"workphone", N_("Work Phone"), FIELD_STRING}, /* WORKPHONE */
54 {"fax", N_("Fax"), FIELD_STRING}, /* FAX */
55 {"mobile", N_("Mobile"), FIELD_STRING}, /* MOBILEPHONE */
56 {"nick", N_("Nickname/Alias"), FIELD_STRING}, /* NICK */
57 {"url", N_("URL"), FIELD_STRING}, /* URL */
58 {"notes", N_("Notes"), FIELD_STRING}, /* NOTES */
59 {"anniversary", N_("Anniversary day"), FIELD_DAY}, /* ANNIVERSARY */
64 extern int first_list_item;
66 extern char *selected;
67 extern char *datafile;
72 declare_standard_field(int i)
74 abook_field *f = xmalloc(sizeof(abook_field));
76 f = memcpy(f, &standard_fields[i], sizeof(abook_field));
77 f->name = xstrdup(gettext(f->name));
79 add_field(&fields_list, f);
81 assert(standard_fields_indexed[i] == -1);
82 standard_fields_indexed[i] = fields_count++;
88 find_standard_field(char *key, int do_declare)
92 for(i = 0; standard_fields[i].key; i++)
93 if(0 == strcmp(standard_fields[i].key, key))
99 return do_declare ? declare_standard_field(i) : &standard_fields[i];
102 /* Search for a field. Use the list of declared fields if no list specified. */
104 real_find_field(char *key, abook_field_list *list, int *number)
106 abook_field_list *cur;
109 for(cur = (list ? list : fields_list), i = 0; cur; cur = cur->next, i++)
110 if(0 == strcmp(cur->field->key, key)) {
123 get_field_keyname(int i, char **key, char **name)
125 abook_field_list *cur = fields_list;
128 assert(i < fields_count);
130 for(j = 0; i >= 0 && j < i; j++, cur = cur->next)
134 *key = (i < 0) ? NULL : cur->field->key;
136 *name = (i < 0) ? NULL : cur->field->name;
140 add_field(abook_field_list **list, abook_field *f)
142 abook_field_list *tmp;
144 for(tmp = *list; tmp && tmp->next; tmp = tmp->next)
148 tmp->next = xmalloc(sizeof(abook_field_list));
151 *list = tmp = xmalloc(sizeof(abook_field_list));
158 declare_new_field(char *key, char *name, char *type, int accept_standard)
162 if(find_declared_field(key))
163 return _("field already defined");
165 if(find_standard_field(key, accept_standard))
166 return accept_standard ? NULL /* ok, added */ :
167 _("standard field does not need to be declared");
169 f = xmalloc(sizeof(abook_field));
170 f->key = xstrdup(key);
171 f->name = xstrdup(name);
173 if(!*type || (0 == strcasecmp("string", type)))
174 f->type = FIELD_STRING;
175 else if(0 == strcasecmp("emails", type))
176 f->type = FIELD_EMAILS;
177 else if(0 == strcasecmp("list", type))
178 f->type = FIELD_LIST;
179 else if(0 == strcasecmp("day", type))
182 return _("unknown type");
184 add_field(&fields_list, f);
191 * Declare a new field while database is already loaded
192 * making it grow accordingly
195 declare_unknown_field(char *key)
199 declare_new_field(key, key, "string",
200 1 /* accept to declare "standard" fields */);
205 for(i = 0; i < fields_count; i++)
207 database[i] = xrealloc(database[i], ITEM_SIZE);
211 * Declare "standard" fields, thus preserving them while parsing a database,
212 * even if they won't be displayed.
215 init_standard_fields()
219 for(i = 0; standard_fields[i].key; i++)
220 if(standard_fields_indexed[i] == -1)
221 declare_standard_field(i);
224 /* Some initializations - Must be called _before_ load_opts() */
226 prepare_database_internals()
230 for(i = 0; i < ITEM_FIELDS; i++)
231 standard_fields_indexed[i] = -1;
233 /* the only two mandatory fields */
234 declare_standard_field(NAME);
235 declare_standard_field(EMAIL);
239 parse_database(FILE *in)
246 item = item_create();
251 if(item[field_id(NAME)] && sec) {
252 add_item2database(item);
259 if(!*line || *line == '\n' || *line == '#') {
261 } else if(*line == '[') {
262 if(item[field_id(NAME)] && sec ) {
263 add_item2database(item);
268 memset(item, 0, ITEM_SIZE);
269 if(!(tmp = strchr(line, ']')))
270 sec = 0; /*incorrect section lines are skipped*/
271 } else if((tmp = strchr(line, '=') ) && sec) {
273 find_field_number(line, &field);
275 item[field] = xstrdup(tmp);
277 } else if(!strcasecmp(opt_get_str(STR_PRESERVE_FIELDS),
279 declare_unknown_field(line);
280 item = xrealloc(item, ITEM_SIZE);
281 item[fields_count - 1] = xstrdup(tmp);
295 load_database(char *filename)
302 if ((in = abook_fopen(filename, "r")) == NULL)
307 return (items == 0) ? 2 : 0;
311 write_database(FILE *out, struct db_enumerator e)
315 abook_field_list *cur;
318 "# abook addressbook file\n\n"
320 "program=" PACKAGE "\n"
321 "version=" VERSION "\n"
325 db_enumerate_items(e) {
326 fprintf(out, "[%d]\n", i);
328 for(cur = fields_list, j = 0; cur; cur = cur->next, j++) {
329 if( database[e.item][j] != NULL &&
330 *database[e.item][j] )
331 fprintf(out, "%s=%s\n",
348 struct db_enumerator e = init_db_enumerator(ENUM_ALL);
350 if( (out = abook_fopen(datafile, "w")) == NULL )
353 if(list_is_empty()) {
360 write_database(out, e);
368 db_free_item(int item)
370 item_empty(database[item]);
378 for(i=0; i <= LAST_ITEM; i++)
388 first_list_item = curitem = -1;
394 validate_item(list_item item)
397 int i, max_field_len;
400 for(f = fields_list, i = 0; f; f = f->next, i++) {
403 switch(f->field->type) {
405 max_field_len = MAX_EMAILSTR_LEN;
407 item[i] = xstrdup("");
410 /* TODO quote string if it contains commas */
413 max_field_len = MAX_FIELD_LEN;
421 if(max_field_len && item[i] &&
422 ((int)strlen(item[i]) > max_field_len)) {
425 item[i][max_field_len - 1] = 0;
426 item[i] = xstrdup(item[i]);
433 adjust_list_capacity()
435 if(list_capacity < 1)
436 list_capacity = INITIAL_LIST_CAPACITY;
437 else if(items >= list_capacity)
439 else if(list_capacity / 2 > items)
445 database = xrealloc(database,sizeof(list_item) * list_capacity);
446 else /* allocate memory _and_ initialize pointers to NULL */
447 database = xmalloc0(sizeof(list_item) * list_capacity);
449 selected = xrealloc(selected, list_capacity);
453 add_item2database(list_item item)
455 /* 'name' field is mandatory */
456 if((item[field_id(NAME)] == NULL) || ! *item[field_id(NAME)]) {
461 if(++items > list_capacity)
462 adjust_list_capacity();
466 selected[LAST_ITEM] = 0;
468 database[LAST_ITEM] = item_create();
469 item_copy(database[LAST_ITEM], item);
476 remove_selected_items()
483 if(!selected_items())
484 selected[curitem] = 1;
486 for(j = LAST_ITEM; j >= 0; j--) {
488 db_free_item(j); /* added for .4 data_s_ */
489 for(i = j; i < LAST_ITEM; i++) {
490 item_copy(database[i], database[i + 1]);
491 selected[i] = selected[i + 1];
493 item_free(&database[LAST_ITEM]);
498 if(curitem > LAST_ITEM && items > 0)
501 adjust_list_capacity();
509 char *p = s + strlen(s);
513 while(p > s && *(p - 1) != ' ')
520 surnamecmp(const void *i1, const void *i2)
522 int ret, idx = field_id(NAME);
523 char *n1, *n2, *s1, *s2;
526 return 0; /* no 'name' field */
528 n1 = (*(list_item *)i1)[idx];
529 n2 = (*(list_item *)i2)[idx];
531 s1 = get_surname(n1);
532 s2 = get_surname(n2);
534 if( !(ret = safe_strcoll(s1, s2)) )
535 ret = safe_strcoll(n1, n2);
543 static int sort_field = -1;
546 namecmp(const void *i1, const void *i2)
550 assert(sort_field >= 0 && sort_field < fields_count);
552 n1 = (*(list_item *)i1)[sort_field];
553 n2 = (*(list_item *)i2)[sort_field];
555 return safe_strcoll(n1, n2);
559 sort_by_field(char *name)
565 name = (name == NULL) ? opt_get_str(STR_SORT_FIELD) : name;
566 find_field_number(name, &field);
569 if(name == opt_get_str(STR_SORT_FIELD))
570 statusline_msg(_("Invalid field value defined "
571 "in configuration"));
573 statusline_msg(_("Invalid field value for sorting"));
580 qsort((void *)database, items, sizeof(list_item), namecmp);
590 qsort((void *)database, items, sizeof(list_item), surnamecmp);
595 /* TODO implement a search based on more sophisticated patterns */
597 find_item(char *str, int start, int search_fields[])
600 char *findstr = NULL;
602 int ret = -1; /* not found */
603 struct db_enumerator e = init_db_enumerator(ENUM_ALL);
605 if(list_is_empty() || !is_valid_item(start))
606 return -2; /* error */
608 findstr = xstrdup(str);
609 findstr = strlower(findstr);
611 e.item = start - 1; /* must be "real start" - 1 */
612 db_enumerate_items(e) {
613 for(i = 0; search_fields[i] >= 0; i++) {
614 if((id = field_id(search_fields[i])) == -1)
616 if(database[e.item][id] == NULL)
618 tmp = xstrdup(database[e.item][id]);
619 if( tmp && strstr(strlower(tmp), findstr) ) {
634 is_selected(int item)
636 return selected[item];
640 is_valid_item(int item)
642 return item <= LAST_ITEM && item >= 0;
647 real_db_enumerate_items(struct db_enumerator e)
649 int item = max(0, e.item + 1);
658 for(i = item; i <= LAST_ITEM; i++) {
667 fprintf(stderr, "real_db_enumerate_items() "
668 "BUG: unknown db_enumerator mode: %d\n",
674 return (item > LAST_ITEM || item < 0) ? -1 : item;
678 init_db_enumerator(int mode)
680 struct db_enumerator e;
682 e.item = -1; /* important - means "start from beginning" */
692 return xmalloc0(ITEM_SIZE);
696 item_free(list_item *item)
704 item_empty(list_item item)
709 for(i = 0; i < fields_count; i++)
716 item_copy(list_item dest, list_item src)
718 memmove(dest, src, ITEM_SIZE);
722 item_duplicate(list_item dest, list_item src)
726 for(i = 0; i < fields_count; i++)
727 dest[i] = src[i] ? xstrdup(src[i]) : NULL;
731 * Things like item[field_id(NICK)] should never be used, since besides NAME
732 * and EMAIL, none of the standard fields can be assumed to be existing.
734 * Prefer the functions item_fput(), item_fget(), db_fput() and db_fget()
735 * to access fields in items and database.
738 /* quick lookup by "standard" field number */
742 assert((i >= 0) && (i < ITEM_FIELDS));
743 return standard_fields_indexed[i];
747 item_fput(list_item item, int i, char *val)
749 int id = field_id(i);
760 item_fget(list_item item, int i)
762 int id = field_id(i);
771 real_db_field_put(int item, int i, int std, char *val)
775 assert(database[item]);
777 id = std ? field_id(i) : i;
780 database[item][id] = val;
788 real_db_field_get(int item, int i, int std)
792 assert(database[item]);
794 id = std ? field_id(i) : i;
797 return database[item][id];