-
Notifications
You must be signed in to change notification settings - Fork 37
/
ebib-db.el
575 lines (487 loc) · 22.9 KB
/
ebib-db.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
;;; ebib-db.el --- Part of Ebib, a BibTeX database manager -*- lexical-binding: t -*-
;; Copyright (c) 2003-2024 Joost Kremers
;; All rights reserved.
;; Author: Joost Kremers <[email protected]>
;; Maintainer: Joost Kremers <[email protected]>
;; Redistribution and use in source and binary forms, with or without
;; modification, are permitted provided that the following conditions
;; are met:
;;
;; 1. Redistributions of source code must retain the above copyright
;; notice, this list of conditions and the following disclaimer.
;; 2. Redistributions in binary form must reproduce the above copyright
;; notice, this list of conditions and the following disclaimer in the
;; documentation and/or other materials provided with the distribution.
;; 3. The name of the author may not be used to endorse or promote products
;; derived from this software without specific prior written permission.
;;
;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
;; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
;; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
;; IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
;; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
;; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE,
;; DATA, OR PROFITS ; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
;; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
;; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
;; THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;;; Commentary:
;; This file is part of Ebib, a BibTeX database manager for Emacs. It contains
;; the database code.
;;; Code:
(require 'seq)
(require 'subr-x) ; hash-table-keys
;; Each database is represented by an alist.
(defvar ebib-db '((entries) ; Hashtable containing the BibTeX entries.
(strings) ; Alist with the @String definitions.
(preamble) ; String with the @Preamble definition.
(comments) ; List of @Comments.
(local-vars) ; The file's local variable block.
(dialect) ; The dialect of this database.
(buffer) ; The index buffer.
(cur-entry) ; The current entry.
(marked-entries) ; List of marked entries.
(filter) ; The active filter.
(sortinfo) ; Custom sorting.
(filename) ; Name of the BibTeX file that holds this database.
(main) ; The main database, or nil if this database is not a dependent.
(keys) ; The keys in the database.
(modtime) ; Modification time of the .bib file.
(modified) ; Flag indicating whether this database has been modified.
(backup))) ; Flag indicating whether we need to make a backup of the .bib file.
(defvar ebib-db-bibdata '(entries strings preamble comment local-vars dialect)
"Fields in `ebib-db' that contain data from the underlying .bib file.")
;; Accessing the fields of the `ebib-db' alist can be done with `assq' or
;; `alist-get', but should in most cases be done with `ebib-db-val' (which is
;; `setf'-able), because it checks whether the database is a dependent database and
;; accesses the main database for the fields in `ebib-db-bibdata'.
(defun ebib-db-val (field db)
"Return the value for FIELD in DB.
If DB is a dependent database and FIELD is one of the fields in
`ebib-db-bibdata', return the value of FIELD in DB's main
database."
(cdr (assq field (or (and (memq field ebib-db-bibdata)
(cdr (assq 'main db)))
db))))
(gv-define-setter ebib-db-val (value field db)
`(setcdr (assq ,field (or (and (memq ,field ebib-db-bibdata)
(cdr (assq 'main ,db)))
,db))
,value))
(defun ebib-db-new-database (&optional main)
"Create a new database instance and return it.
If MAIN is non-nil, it should be a database object, which is set
as the main database of the new database."
(let ((db (copy-tree ebib-db)))
(if main
(setf (ebib-db-val 'main db) main)
(setf (ebib-db-val 'entries db) (make-hash-table :test 'equal)))
db))
(defun ebib-db-clear-database (db)
"Remove all information in DB.
The database object itself is retained, only the references to
the relevant data in it is deleted.
Note that the data itself is not destroyed, but may eventually be
GC'ed, with the exception of the buffer pointed to by the buffer
field. This should be killed separately."
;; We use `alist-get' here instead of `ebib-db-val' because we don't want to
;; be redirected to the main database.
(if (not (alist-get 'main db))
(clrhash (alist-get 'entries db)))
(mapc (lambda (item)
(setf (alist-get item db) nil))
(delq 'entries (mapcar #'car db))))
(defun ebib-db-count-entries (db)
"Return the number of entries in DB."
(if (ebib-db-val 'main db)
(length (ebib-db-val 'keys db))
(hash-table-count (ebib-db-val 'entries db))))
(defun ebib-db-get-dialect (db)
"Return the BibTeX dialect of DB."
(ebib-db-val 'dialect db))
(defun ebib-db-set-dialect (dialect db)
"Set DIALECT as the BibTeX dialect of DB."
(setf (ebib-db-val 'dialect db) dialect))
(defun ebib-db-get-comments (db)
"Return a list of @Comments for DB."
(ebib-db-val 'comments db))
(defun ebib-db-set-comment (comment db)
"Add COMMENT to the list of comments in DB."
(setf (ebib-db-val 'comments db) (append (ebib-db-val 'comments db) (list comment))))
(defun ebib-db-get-local-vars (db)
"Return the local variable block of DB."
(ebib-db-val 'local-vars db))
(defun ebib-db-set-local-vars (vars db)
"Store VARS as the local variable block of DB.
No check is performed to see if VARS is really a local variable block."
(setf (ebib-db-val 'local-vars db) vars))
(defun ebib-db-get-buffer (db)
"Return the index buffer of DB."
(ebib-db-val 'buffer db))
(defun ebib-db-set-buffer (buffer db)
"Set BUFFER as DB's index buffer."
(setf (ebib-db-val 'buffer db) buffer))
(defun ebib--db-get-current-entry-key (db)
"Return the key of the current entry in DB."
(ebib-db-val 'cur-entry db))
(defun ebib-db-set-current-entry-key (key db)
"Set KEY as the current entry of DB.
KEY is a key in DB. If KEY is not in DB, the current entry is
set to nil, which signifies that a new current entry should be
set. It is possible to pass a value of nil for KEY, to unset the
current entry unconditionally.
Return the new entry key if it could be made the new entry key,
nil otherwise."
(if (and (stringp key)
(ebib-db-get-entry key db 'noerror))
(setf (ebib-db-val 'cur-entry db) key)
(setf (ebib-db-val 'cur-entry db) nil)))
(defun ebib-db-set-entry (key data db &optional if-exists)
"Set KEY to DATA in database DB.
DATA is an alist of (FIELD . VALUE) pairs.
IF-EXISTS defines what to do when the key already exists in DB.
If it is `overwrite', replace the existing entry. If it is `uniquify',
generate a unique key by appending a letter `b', `c', etc., to it.
If it is `noerror', a duplicate key is not stored and the function
returns nil. If it is nil (or any other value), a duplicate key
triggers an error.
In order to delete an entry, DATA must be nil and IF-EXISTS must be
`overwrite'.
If storing/updating/deleting the entry is successful, return its key.
Note that this function should not be used to add an entry to a
dependent database. The entry will be added to the main database
instead. Use `ebib-db-add-entries-to-dependent' instead."
(let ((exists (gethash key (ebib-db-val 'entries db))))
(when exists
(cond
;; If so required, make the entry unique:
((eq if-exists 'uniquify)
(setq key (ebib-db-uniquify-key key db))
(setq exists nil))
;; If the entry is an update, we simply pretend the key does not exist:
((eq if-exists 'overwrite)
(setq exists nil))
;; Otherwise signal an error, if so requested:
((not (eq if-exists 'noerror))
(error "[Ebib] Key `%s' exists in database `%s'; cannot overwrite" key (ebib-db-get-filename db 'shortened)))))
(unless exists
(if data
(puthash key data (ebib-db-val 'entries db))
(remhash key (ebib-db-val 'entries db)))
key)))
(defun ebib-db-add-entries-to-dependent (entries db)
"Add ENTRIES to dependent database DB.
ENTRIES is either an entry key (a string) or a list of entry
keys. Entries that are already in DB are not added again. This
function does not check if DB is really a dependent database, nor
whether the entries to be added actually exist in DB's main
database."
(if (stringp entries)
(unless (member entries (ebib-db-val 'keys db))
(push entries (ebib-db-val 'keys db)))
(setf (ebib-db-val 'keys db) (delete-dups (append entries (ebib-db-val 'keys db))))))
(defun ebib-db-remove-entry (key db)
"Remove entry KEY from DB.
Note: do not use this function to remove an entry from a
dependent database, since the entry will be removed from its main
database instead. Use `ebib-db-remove-entries-from-dependent'."
(ebib-db-set-entry key nil db 'overwrite))
(defun ebib-db-remove-entries-from-dependent (entries db)
"Remove ENTRIES from dependent database DB.
ENTRIES is either an entry key (a string) or a list of entry
keys. They are removed from DB unconditionally: no error is
raised if the entries do not exist in DB."
(setf (ebib-db-val 'keys db) (if (stringp entries)
(delete entries (ebib-db-val 'keys db))
(seq-difference (ebib-db-val 'keys db) entries))))
(defun ebib-db-get-entry (key db &optional noerror)
"Return entry KEY in database DB as an alist.
The entry is returned as an alist of (FIELD . VALUE) pairs.
Trigger an error if KEY does not exist, unless NOERROR is T."
(let ((entry (gethash key (ebib-db-val 'entries db))))
(unless (or entry noerror)
(error "[Ebib] Entry `%s' does not exist" key))
entry))
(defun ebib-db-uniquify-key (key db)
"Return a key based on KEY that is unique in DB.
The key is made unique by suffixing `b' to it. If that does not
yield a unique key, `c' is suffixed instead, etc., until a unique
key is found. If suffixing `z' does not yield a unique key, `aa'
is suffixed, then `ab' etc."
(let* ((suffix ?b)
(unique-key (concat key (list suffix))))
(while (gethash unique-key (ebib-db-val 'entries db))
(setq suffix (1+ suffix))
(setq unique-key (concat key (list suffix)))
(when (eq suffix ?z)
(setq key (concat key "a"))
(setq suffix ?a)))
unique-key))
(defun ebib-db-has-entries (db)
"Return non-nil if DB has entries."
(if (ebib-db-val 'main db)
(not (null (ebib-db-val 'keys db)))
(> (hash-table-count (ebib-db-val 'entries db)) 0)))
(defun ebib-db-list-keys (db)
"Return a list of keys in DB."
(if (ebib-db-val 'main db)
(copy-sequence (ebib-db-val 'keys db)) ; Use `copy-tree' because `ebib--sort-keys-list' is destructive.
(hash-table-keys (ebib-db-val 'entries db))))
(defun ebib-db-has-key (key db)
"Return non-nil if KEY exists in DB."
(if (ebib-db-val 'main db)
(member key (ebib-db-val 'keys db))
(gethash key (ebib-db-val 'entries db))))
(defun ebib-db-change-key (key new-key db &optional if-exists)
"Change entry key KEY to NEW-KEY in DB.
IF-EXISTS determines what to do when NEW-KEY already exists. If
it is nil, an error is triggered. If it is `noerror', no error
is triggered and nothing is updated. If it is `overwrite', the
existing entry under NEW-KEY is overwritten. If it is
`uniquify', a unique key is created.
If there is no entry with KEY in DB, an error is triggered.
Return the new key upon succes, or nil if nothing was updated."
(let* ((data (ebib-db-get-entry key db))
(actual-new-key (ebib-db-set-entry new-key data db if-exists)))
(when actual-new-key
(ebib-db-remove-entry key db)
actual-new-key)))
(defun ebib-db-set-field-value (field value key db &optional overwrite)
"Set FIELD to VALUE in entry KEY in database DB.
OVERWRITE determines what to do if the field already exists. If
it is t, the existing value is overwritten. If it is nil, the
value is not stored and the function returns nil. OVERWRITE can
can also be the symbol `error', in which case an error is raised
and the value is not changed.
A field can be removed from the entry by passing nil as VALUE and
setting OVERWRITE to t.
Return t upon success, or nil if the value could not be stored."
(let* ((entry (ebib-db-get-entry key db))
(elem (assoc-string field entry 'case-fold))
(old-value (cdr elem)))
;; If the field has a value, decide what to do:
(if old-value
(cond
((eq overwrite 'error)
(error "[Ebib] Field `%s' exists in entry `%s'; cannot overwrite" field key))
(overwrite
(setq old-value nil)))
;; Create the field if it doesn't exist yet. The value is initially set to nil.
(unless elem
(setq elem (car (setcdr (last entry) (list (cons field nil))))))) ; Make sure `elem' points to the newly added field.
;; If there is (still) an old value, do nothing.
(unless old-value
;; Otherwise overwrite the existing entry. Note that to delete a field, we
;; set its value to nil, rather than removing it altogether from the
;; database. In `ebib--display-fields', such fields are ignored, and they're
;; not saved.
(setcdr elem value)
t))) ; Make sure we return non-nil, `value' may be nil, after all.
(defun ebib-db-remove-field-value (field key db)
"Remove FIELD from entry KEY in DB."
(ebib-db-set-field-value field nil key db 'overwrite))
(defun ebib-db-get-field-value (field key db &optional noerror)
"Return the value of FIELD in entry KEY in database DB.
If FIELD or KEY does not exist, trigger an error, unless NOERROR
is non-nil. In this case, if NOERROR is a string, return NOERROR,
otherwise return nil."
(let ((value (cdr (assoc-string field (ebib-db-get-entry key db noerror) 'case-fold))))
(unless (or value noerror)
(error "[Ebib] Field `%s' does not exist in entry `%s'" field key))
(when (and (not value)
(stringp noerror))
(setq value noerror))
value))
(defun ebib-db-set-string (abbr value db &optional overwrite)
"Set the @string definition ABBR to VALUE in database DB.
If ABBR does not exist, create it.
OVERWRITE determines what to do when ABBR already exists. If it
is t, the new string replaces the existing one. If it is nil,
the string is not stored and the function returns nil. If it is
the symbol `error', an error is raised.
In order to remove a @String definition, pass nil as VALUE and
set IF-EXISTS to `overwrite'."
(let* ((strings-list (ebib-db-val 'strings db))
(old-string (cdr (assoc abbr strings-list))))
(if old-string
(cond
((eq overwrite 'error)
(error "[Ebib] @String abbreviation `%s' exists in database %s"
abbr (ebib-db-get-filename db 'short)))
((and overwrite value)
(setcdr (assoc-string abbr strings-list) value)
(setq value nil)) ; Set `value' to nil to indicate we're done.
(overwrite
(setq strings-list (delete (cons abbr old-string) strings-list))
(setq value nil)))) ; Set `value' to nil to indicate we're done.
(when value
;; Put the new string at the end of the list, to keep them in the order in
;; which they appear in the .bib file. This is preferable for version
;; control.
(if strings-list
(setcdr (last strings-list) (list (cons abbr value)))
(setq strings-list (list (cons abbr value)))))
(setf (ebib-db-val 'strings db) strings-list)))
(defun ebib-db-remove-string (abbr db)
"Remove @String definition ABBR ttfrom DB."
(ebib-db-set-string abbr nil db 'overwrite))
(defun ebib-db-get-string (abbr db &optional noerror)
"Return the value of @String definition ABBR in database DB.
If ABBR does not exist, trigger an error, unless NOERROR is
non-nil, in which case return nil."
;; I assume abbreviations should be case-sensitive, so I use assoc
;; instead of assoc-string here.
(let ((value (cdr (assoc abbr (ebib-db-val 'strings db)))))
(unless (or value noerror)
(error "[Ebib] @String abbreviation `%s' does not exist" abbr))
value))
(defun ebib-db-get-all-strings (db)
"Return the alist containing all @String definitions in DB."
(ebib-db-val 'strings db))
(defsubst ebib-db-list-strings (db)
"Return a list of @String abbreviations in DB without expansions."
(mapcar #'car (ebib-db-val 'strings db)))
(defun ebib-db-set-preamble (preamble db &optional if-exists)
"Set PREAMBLE as the preamble of DB.
IF-EXISTS determines what to do if there already is a preamble:
if its value is `append', PREAMBLE is appended to the existing
text (with a newline and hash in between); if it is `overwrite',
PREAMBLE replaces the existing text. If it is `noerror', PREAMBLE
is not stored and the function returns nil. If it is nil (or any
other value), an error is raised.
In order to delete the preamble, PREAMBLE should be nil and
IF-EXISTS should be `overwrite'.
Return non-nil on success or nil if PREAMBLE could not be stored."
(let ((existing-preamble (ebib-db-get-preamble db)))
(when existing-preamble
(cond
((eq if-exists 'append)
(setq preamble (concat existing-preamble "\n# " preamble))
(setq existing-preamble nil))
((eq if-exists 'overwrite)
(setq existing-preamble nil))))
(if (not existing-preamble)
(setf (ebib-db-val 'preamble db) preamble)
(unless (eq if-exists 'noerror)
(error "[Ebib] Preamble is not empty; cannot overwrite")))))
(defun ebib-db-remove-preamble (db)
"Remove the @Preamble definition from DB."
(ebib-db-set-preamble nil db 'overwrite))
(defun ebib-db-get-preamble (db)
"Return the preamble of DB.
If DB has no preamble, return nil."
(ebib-db-val 'preamble db))
(defun ebib-db-set-modified (mod db)
"Set the modification flag of DB to MOD."
(setf (ebib-db-val 'modified db) mod))
(defun ebib-db-modified-p (db)
"Return t if DB has been modified, nil otherwise."
(ebib-db-val 'modified db))
(defun ebib-db-set-filename (filename db &optional if-exists)
"Set FILENAME as the filename of DB.
IF-EXISTS determines what to do when the database already has a
filename. If it is `overwrite', the filename is changed. If
`noerror', the filename is not changed an nil is returned. If
IF-EXISTS is nil, an existing filename triggers an error."
(let ((exists (ebib-db-val 'filename db)))
(when exists
(cond
((eq if-exists 'overwrite)
(setq exists nil))
((not (eq if-exists 'noerror))
(error "[Ebib] Database has a filename; cannot overwrite"))))
(unless exists
(setf (ebib-db-val 'filename db) filename))))
(defun ebib-db-get-filename (db &optional shortened)
"Return the filename of DB.
If SHORTENED is non-nil, return only the filename part, otherwise
return the full path. If DB is nil, return nil."
(when db
(if shortened
(file-name-nondirectory (ebib-db-val 'filename db))
(ebib-db-val 'filename db))))
(defun ebib-db-get-main (db)
"Return the main database of DB.
If DB is not a dependent database, return nil."
(ebib-db-val 'main db))
(defun ebib-db-set-main (main db)
"Set MAIN as the main database of DB."
(setf (ebib-db-val 'main db) main))
(defun ebib-db-dependent-p (db)
"Return non-nil if DB is a dependent database."
(ebib-db-val 'main db))
(defun ebib-db-get-modtime (db)
"Return the mod time stored for DB."
(ebib-db-val 'modtime db))
(defun ebib-db-set-modtime (modtime db)
"Set MODTIME of DB."
(setf (ebib-db-val 'modtime db) modtime))
(defun ebib-db-marked-entries-p (db)
"Return t if there are marked enries in DB."
(ebib-db-val 'marked-entries db))
(defun ebib-db-marked-p (entry db)
"Return t if ENTRY is marked in DB.
ENTRY is an entry key."
(member entry (ebib-db-val 'marked-entries db)))
(defun ebib-db-mark-entry (entries db)
"Add ENTRIES to the list of marked entries in DB.
ENTRIES is an entry key or a list of entry keys."
;; We do not check if `entries' is already in the list of marked entries,
;; because when we unmark an entries, we use `remove', which removes all
;; occurrences anyway.
(cond
((stringp entries)
(push entries (ebib-db-val 'marked-entries db)))
((listp entries)
(setf (ebib-db-val 'marked-entries db) (append entries (ebib-db-val 'marked-entries db))))))
(defun ebib-db-unmark-entry (entries db)
"Remove ENTRIES from the list of marked entries in DB.
ENTRIES is an entry key or a list of entry keys."
;; Use `remove' here to ensure that *all* occurrences of `entries' are removed.
(cond
((stringp entries)
(setf (ebib-db-val 'marked-entries db) (remove entries (ebib-db-val 'marked-entries db))))
((listp entries)
(setf (ebib-db-val 'marked-entries db) (seq-difference (ebib-db-val 'marked-entries db) entries)))))
(defun ebib-db-toggle-mark (entry db)
"Toggle the mark on ENTRY in DB."
(if (ebib-db-marked-p entry db)
(ebib-db-unmark-entry entry db)
(ebib-db-mark-entry entry db)))
(defun ebib-db-list-marked-entries (db)
"Return a list of entry keys of all marked entries in DB."
(copy-sequence (ebib-db-val 'marked-entries db)))
(defun ebib-db-filtered-p (db)
"Return t if a filter exists for DB."
(ebib-db-val 'filter db))
(defun ebib-db-set-filter (filter db)
"Set FILTER as the filter of DB.
The filter is set unconditionally, overwriting any existing filter."
(setf (ebib-db-val 'filter db) filter))
(defun ebib-db-get-filter (db)
"Return the filter of DB."
(ebib-db-val 'filter db))
(defun ebib-db-set-sortinfo (sortinfo db)
"Set the SORTINFO of DB.
The sortinfo is set unconditionally, overwriting any existing
sortinfo."
(setf (ebib-db-val 'sortinfo db) sortinfo))
(defun ebib-db-get-sortinfo (db)
"Return the sort infor for DB."
(ebib-db-val 'sortinfo db))
(defun ebib-db-get-sort-field (db)
"Return the sort field of DB, or nil if there is none."
(car (ebib-db-val 'sortinfo db)))
(defun ebib-db-get-sort-order (db)
"Return the sort order of DB, or nil if there is none."
(cdr (ebib-db-val 'sortinfo db)))
(defun ebib-db-set-backup (backup db)
"Set BACKUP as the backup flag of DB.
BACKUP must be either t (make backup at next save) or nil (do not
make backup at next save)."
(setf (ebib-db-val 'backup db) backup))
(defun ebib-db-backup-p (db)
"Return backup flag of DB."
(ebib-db-val 'backup db))
(provide 'ebib-db)
;;; ebib-db.el ends here