2
* $Id: database.c,v 1.2 2000/05/30 15:18:44 dfoerste Exp $
4
* This file is part of WorkMan, the civilized CD player library
5
* (c) 1991-1997 by Steven Grimm (original author)
6
* (c) by Dirk Fļæ½rsterling (current 'author' = maintainer)
7
* The maintainer can be contacted by his e-mail address:
8
* milliByte@DeathsDoor.com
10
* This library is free software; you can redistribute it and/or
11
* modify it under the terms of the GNU Library General Public
12
* License as published by the Free Software Foundation; either
13
* version 2 of the License, or (at your option) any later version.
15
* This library is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
* Library General Public License for more details.
20
* You should have received a copy of the GNU Library General Public
21
* License along with this library; if not, write to the Free
22
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
* Manage the CD database. All these routines assume that the "cd" global
26
* structure contains current information (as far as the outside world knows;
27
* obviously it won't contain track titles just after a CD is inserted.)
30
static char database_id[] = "$Id: database.c,v 1.2 2000/05/30 15:18:44 dfoerste Exp $";
32
#define RCFILE "/.workmanrc"
33
#define DBFILE "/.workmandb"
43
#include <sys/types.h>
44
#include <sys/param.h>
47
#include "include/wm_config.h"
48
#include "include/wm_helpers.h"
49
#include "include/wm_struct.h"
50
#include "include/wm_cdinfo.h"
51
#include "include/wm_cddb.h"
52
#include "include/wm_index.h"
53
#include "include/wm_database.h"
55
#define WM_MSG_CLASS WM_MSG_CLASS_DB
57
#define SWALLOW_LINE(fp) { int c; while ((c = getc(fp)) != '\n' && c != EOF); }
59
int suppress_locking = 0; /* Turn off locking of datafile (dangerous) */
61
char *rcfile = NULL; /* Personal rcfile */
62
char *dbfiles = NULL; /* Colon-separated list of databases */
63
char **databases = NULL; /* NULL-terminated list of databases */
65
char *otherrc = NULL; /* Unrecognized cruft from start of rcfile */
67
long rcpos, rclen; /* XXX */
69
int found_in_db, found_in_rc;
70
long holepos, firstpos;
72
int fuzz_frames = FUZZFRAMES;
74
int wm_db_save_disabled = FALSE;
78
extern int cur_ntracks, cur_nsections;
87
int wm_db_get_playnew( void )
95
* Split the WORKMANDB environment variable, if any, into a list of database
96
* files in the global "databases". If WORKMANDB is not available, make
97
* a single entry with $HOME/DBFILE.
99
* Also, fill the "rcfile" global with the personal preferences filename.
101
* The environment variables should have already been read and placed in the
102
* "rcfile" and "dbfiles" globals, respectively.
105
split_workmandb( void )
109
int no_rc = 0, no_db = 0;
113
if ((home = getenv("HOME")) != NULL)
115
rcfile = malloc(strlen(home) + sizeof(RCFILE));
120
perror("split_workmandb()");
124
strcpy(rcfile, home);
125
strcat(rcfile, RCFILE);
132
if ((wmdb = dbfiles) == NULL)
134
if ((home = getenv("HOME")) != NULL)
136
wmdb = malloc(strlen(home) + sizeof(DBFILE));
140
databases = malloc(2 * sizeof (databases[0]));
141
if (databases == NULL)
145
strcat(wmdb, DBFILE);
151
static char *emptydb = NULL;
153
databases = &emptydb;
160
for (home = wmdb; *home; home++)
167
databases = malloc((ndbs + 1) * sizeof(databases[0]));
168
if (databases == NULL)
171
for (i = 0; i < ndbs; i++)
174
wmdb += strlen(wmdb) + 1;
183
"WorkMan was run without a home directory, probably by a system daemon.\n");
184
fprintf(stderr, "It doesn't know where to find ");
187
fprintf(stderr, "your personal preferences file ");
189
fprintf(stderr, "or the\ndatabase of CD descriptions");
192
fprintf(stderr, "the database of CD descriptions");
195
".\nYou can use the X resources \"workman.db.shared\" and \"workman.db.personal\"\nto tell WorkMan where to look.\n");
197
wm_db_save_disabled = TRUE;
202
* print_cdinfo(cd, prefs)
204
* cd A pointer to a cdinfo struct.
205
* prefs Flag: write personal preferences?
207
* Print a CD's information (in more or less readable form) to a buffer.
208
* Returns a pointer to the buffer.
210
* XXX - could be more efficient about calling wm_strmcat() and strlen().
213
print_cdinfo(struct wm_cdinfo *cd, int prefs)
216
char tempbuf[2000]; /* XXX - is this always big enough? */
217
static char *cdibuf = NULL;
218
struct wm_playlist *l;
220
sprintf(tempbuf, "\ntracks %d", cd->ntracks);
221
for (i = 0; i < cur_ntracks; i++)
222
if (cd->trk[i].section < 2)
223
sprintf(tempbuf + strlen(tempbuf), " %d",
225
sprintf(tempbuf + strlen(tempbuf), " %d\n", cd->length);
227
wm_strmcpy(&cdibuf, tempbuf);
231
sprintf(tempbuf, "sections %d", cur_nsections);
232
/* fixed a bug here */
233
for (i = 0; i < cur_ntracks; i++)
234
if (cd->trk[i].section > 1)
235
sprintf(tempbuf + strlen(tempbuf), " %d",
237
sprintf(tempbuf + strlen(tempbuf), "\n");
239
wm_strmcat(&cdibuf, tempbuf);
245
wm_strmcat(&cdibuf, "autoplay\n");
246
for (l = cd->lists; l != NULL && l->name != NULL; l++)
248
wm_strmcat(&cdibuf, "playlist ");
250
i = strlen(cdibuf) - 1;
251
wm_strmcat(&cdibuf, l->name);
253
if (cdibuf[i] == ' ' || cdibuf[i] == '\t')
258
for (i = 0; l->list[i]; i++)
260
sprintf(tempbuf, " %d", i);
261
wm_strmcat(&cdibuf, tempbuf);
262
for (i = 0; l->list[i]; i++)
264
sprintf(tempbuf, " %d", l->list[i]);
265
wm_strmcat(&cdibuf, tempbuf);
267
wm_strmcat(&cdibuf, "\n");
270
wm_strmcat(&cdibuf, " 0\n");
276
* Have to maintain compatibility with old versions,
277
* where volume was 0-32.
279
sprintf(tempbuf, "cdvolume %d\n", (cd->volume * 32) / 100);
280
wm_strmcat(&cdibuf, tempbuf);
285
sprintf(tempbuf, "playmode %d\n", cd->playmode);
286
wm_strmcat(&cdibuf, tempbuf);
291
sprintf(tempbuf, "mark %d START\n", mark_a);
292
wm_strmcat(&cdibuf, tempbuf);
296
sprintf(tempbuf, "mark %d END\n", mark_b);
297
wm_strmcat(&cdibuf, tempbuf);
301
wm_strmcat(&cdibuf, cd->otherrc);
303
for (i = 0; i < cur_ntracks; i++)
305
if (cd->trk[i].avoid)
307
sprintf(tempbuf, "dontplay %d\n", i + 1);
308
wm_strmcat(&cdibuf, tempbuf);
310
if (cd->trk[i].volume)
312
sprintf(tempbuf, "volume %d %d\n", i + 1,
313
(cd->trk[i].volume * 32) / 100);
314
wm_strmcat(&cdibuf, tempbuf);
316
if (cd->trk[i].otherrc)
317
wm_strmcat(&cdibuf, cd->trk[i].otherrc);
324
wm_strmcat(&cdibuf, "cdname ");
325
wm_strmcat(&cdibuf, cd->cdname);
326
wm_strmcat(&cdibuf, "\n");
331
wm_strmcat(&cdibuf, "artist ");
332
wm_strmcat(&cdibuf, cd->artist);
333
wm_strmcat(&cdibuf, "\n");
337
wm_strmcat(&cdibuf, cd->otherdb);
339
for (i = 0; i < cur_ntracks; i++)
341
if (cd->trk[i].section > 1)
342
wm_strmcat(&cdibuf, "s-");
343
wm_strmcat(&cdibuf, "track ");
344
if (cd->trk[i].songname != NULL)
345
wm_strmcat(&cdibuf, cd->trk[i].songname);
346
wm_strmcat(&cdibuf, "\n");
347
if (cd->trk[i].contd)
349
if (cd->trk[i].section > 1)
350
wm_strmcat(&cdibuf, "s-");
351
wm_strmcat(&cdibuf, "continue\n");
353
if (cd->trk[i].otherdb)
354
wm_strmcat(&cdibuf, cd->trk[i].otherdb);
359
} /* print_cdinfo() */
362
* Open the rcfile for reading or writing.
368
open_rcfile(char *name, char *mode)
373
fp = fopen(name, mode);
376
if (errno != ENOENT || mode[0] == 'w')
381
/* Don't let people open directories or devices */
382
if (fstat(fileno(fp), &st) < 0)
390
if (! S_ISREG(st.st_mode))
392
if ((st.st_mode & S_IFMT) != S_IFREG)
401
if (mode[0] == 'w') /* create -- put data in so locks work */
403
fputs("# WorkMan database file\n", fp);
405
fp = fopen(name, "r+");
417
* allocate and clear "trackmap".
420
int *reset_tracks(void)
425
* Since we access track numbers indirectly (to handle sections
426
* with at least a little elegance), the track mapping needs to be
427
* set up before we read anything. Initially it must assume that
428
* no sections will appear in this datafile.
430
trackmap = malloc(sizeof(int) * cur_ntracks);
431
if (trackmap == NULL)
437
for (i = 0; i < cd->ntracks; i++)
440
while (cd->trk[++j].section > 1)
444
} /* reset_tracks() */
447
* Load a new-format database file, searching for a match with the currently
448
* inserted CD. Modify the in-core copy of the CD info based on what's found
451
* Returns 1 if there was a match or 0 if not.
453
* fp FILE* of database or rcfile.
454
* prefs 1 if we're searching .workmanrc, 0 for .workmandb,
455
* 2 if just reading settings
456
* scan Scan for "tracks" location and entry size only
457
* holesize_wanted How big a hole we're looking for, if any.
459
* If a hole was found along the way, update the global "holepos" with its
460
* starting offset in the file. A hole is defined as a bunch of blank lines
461
* preceding a "tracks" line. Holepos will contain the best match.
463
* In addition, "firstpos" will be filled with the position of the first
464
* "tracks" keyword, so we know how much room is available for global
465
* settings at the rcfile's start.
468
search_db( FILE *fp, int prefs, int scan, int holesize_wanted )
471
char keyword[64], listname[64], *c;
472
int b, i, j, track = 0, listsize, ntracks, scratch, searching = 1;
473
int *trackmap = 0, gotsections = 0;
474
int fudge, maxfudge, sizediff, bestfudge = 0;
475
long pos = 0, thisholepos = -1, holesize = 99991239;
476
struct wm_playlist *l;
480
wm_lib_message(WM_MSG_CLASS_DB|WM_MSG_LEVEL_DEBUG , "db: Reached search_db()\n" );
482
/* We may not find any holes at all! */
487
trackmap = reset_tracks();
498
while (b != EOF && b != '\n' && isspace(b));
500
if (b == EOF || feof(fp))
506
fscanf(fp, "%s", &keyword[1]);
508
if (keyword[0] == '\0') /* Blank line. */
515
/* Strip off "s-" if we've seen a "sections" keyword */
516
if (gotsections && keyword[0] == 's' && keyword[1] == '-')
518
for (c = &keyword[2]; (c[-2] = *c) != '\0'; c++)
520
wm_lib_message(WM_MSG_CLASS_DB|WM_MSG_LEVEL_DEBUG , "db: stripped off the 's-'. Result is %s\n", keyword);
523
/* If this is the start of a CD entry, see if it matches. */
524
if (! strcmp(keyword, "tracks"))
529
/* Is this the end of a hole? */
530
if (holesize_wanted && (thisholepos >= 0))
532
/* Yep. Is it better than the last one? */
533
if (pos - thisholepos < holesize && pos -
534
thisholepos >= holesize_wanted)
536
holepos = thisholepos;
537
holesize = pos - thisholepos;
542
/* Is it the start of the CD entries? */
546
/* Is this the end of the entry we really wanted? */
553
/* If we have a near match, indicate that we
554
should stop reading tracks, etc now */
561
fscanf(fp, "%d", &ntracks);
563
if (ntracks != cd->ntracks)
571
maxfudge = (ntracks * fuzz_frames) >> 1;
573
for (i = 0; i < ntracks; i++)
575
fscanf(fp, "%d", &scratch);
576
if (scratch != cd->trk[track].start)
578
sizediff = abs(scratch - cd->trk[track].start);
579
if (sizediff > fuzz_frames ||
584
while (cd->trk[++track].section > 1)
590
if (fudge > 0) /* best near match? */
592
if (fudge > maxfudge)
594
if (bestfudge == 0 || fudge < bestfudge)
602
else /* probably exact match */
604
fscanf(fp, "%d", &scratch);
606
if (scratch != -1 && scratch != cd->length)
615
SWALLOW_LINE(fp); /* Get rid of newline */
618
/* Global mode stuff goes here */
619
else if (! strcmp(keyword, "cddbprotocol"))
622
i = getc(fp); /* only first letter is used */
623
cddb.protocol = i == 'c' ? 1 :
627
while (i != '\n' && i != EOF);
630
else if (! strcmp(keyword, "cddbserver"))
632
getc(fp); /* lose the space */
633
if (cddb.cddb_server[0])
636
while (i != '\n' && i != EOF);
639
fgets(cddb.cddb_server,
640
sizeof(cddb.cddb_server), fp);
641
if ((i = strlen(cddb.cddb_server)))
642
cddb.cddb_server[i - 1] = '\0';
646
else if (! strcmp(keyword, "cddbmailadress"))
648
getc(fp); /* lose the space */
649
if (cddb.mail_adress[0])
652
while (i != '\n' && i != EOF);
655
fgets(cddb.mail_adress,
656
sizeof(cddb.mail_adress), fp);
657
if ((i = strlen(cddb.mail_adress)))
658
cddb.mail_adress[i - 1] = '\0';
662
else if (! strcmp(keyword, "cddbpathtocgi"))
664
getc(fp); /* lose the space */
665
if (cddb.path_to_cgi[0])
668
while (i != '\n' && i != EOF);
671
fgets(cddb.path_to_cgi,
672
sizeof(cddb.path_to_cgi), fp);
673
if ((i = strlen(cddb.path_to_cgi)))
674
cddb.path_to_cgi[i - 1] = '\0';
678
else if (! strcmp(keyword, "cddbproxy"))
680
getc(fp); /* lose the space */
681
if (cddb.proxy_server[0])
684
while (i != '\n' && i != EOF);
687
fgets(cddb.proxy_server,
688
sizeof(cddb.proxy_server), fp);
689
if ((i = strlen(cddb.proxy_server)))
690
cddb.proxy_server[i - 1] = '\0';
694
else if (! strcmp(keyword, "whendone"))
697
i = getc(fp); /* only first letter is used */
698
if (cur_stopmode == -1) /* user's setting preferred */
699
cur_stopmode = i == 's' ? 0 : i == 'r' ? 1 : 2;
702
while (i != '\n' && i != EOF);
705
else if (! strcmp(keyword, "playnew"))
707
if (cur_playnew == -1)
712
/* If we're searching, skip to the next "tracks" line. */
713
else if (((searching & 1)|| scan)
714
&& !(prefs && firstpos == -1))
717
else if (! strcmp(keyword, "sections"))
720
fscanf(fp, "%d", &ntracks);
723
trackmap = (int *) malloc(sizeof(int) *
724
(cur_ntracks + ntracks));
725
if (trackmap == NULL)
727
perror("section mapping");
732
* If sections are already defined, use these as a
733
* reference, mapping this CD entry's section numbers
734
* to the ones in core.
736
* Otherwise, split the CD up according to the sections
746
fscanf(fp, "%d", &scratch);
747
while (scratch > cd->trk[track].start)
749
if (cd->trk[track].section < 2)
750
trackmap[i++] = track;
753
if (track == cur_ntracks)
757
/* rc has later sections than db... */
758
if (track == cur_ntracks)
761
/* Matches can be approximate */
762
if (scratch+75 > cd->trk[track].start &&
763
scratch-75 < cd->trk[track].start)
764
trackmap[i++] = track++;
768
if (track == cur_ntracks)
772
/* This only happens if track == cur_ntracks */
776
while (track < cur_ntracks)
778
if (cd->trk[track].section < 2)
779
trackmap[i++] = track;
790
fscanf(fp, "%d", &scratch);
791
split_trackinfo(scratch);
794
for (i = 0; i < cur_ntracks; i++)
797
/* split_trackinfo() sets this */
798
cd->trk[i].contd = 0;
805
else if (! strcmp(keyword, "track"))
809
getc(fp); /* lose the space */
811
/* don't overwrite existing track names. */
812
/* However, overwrite them if there was a "bad" fuzzy match before */
813
if ((trackmap[track] == -1 || track > (cd->ntracks + cur_nsections)) && (searching == 2))
815
else if (cd->trk[trackmap[track]].songname &&
816
cd->trk[trackmap[track]].songname[0])
819
while (i != '\n' && i != EOF);
822
fgets(buf, sizeof(buf), fp);
823
wm_lib_message(WM_MSG_CLASS_DB|WM_MSG_LEVEL_DEBUG, "found track %s\n", buf);
824
if( (i = strlen(buf)) )
826
wm_strmcpy(&cd->trk[trackmap[track]].songname, buf);
831
else if (! strcmp(keyword, "playmode"))
832
fscanf(fp, "%d", &cd->playmode);
834
else if (! strcmp(keyword, "autoplay"))
837
else if (! strcmp(keyword, "cdname"))
839
/* because of fuzzy matching that may change
840
the disk contents, we reset everything when
841
we find the name, in hopes that we will recover
842
most, if not all, of the information from the
845
* nasty bug was here. Was it? BUGBUGBUG
848
* trackmap = reset_tracks();
851
getc(fp); /* lose the space */
852
/* don't overwrite existing cd name. */
853
if (cd->cdname[0] && (searching == 2))
856
while (i != '\n' && i != EOF);
861
strcpy(cd->cdname, "Probably://");
862
fgets(cd->cdname + strlen(cd->cdname), sizeof(cd->cdname), fp);
866
fgets(cd->cdname, sizeof(cd->cdname), fp);
868
if ( (i = strlen(cd->cdname)) )
869
cd->cdname[i - 1] = '\0';
873
else if (! strcmp(keyword, "artist"))
875
getc(fp); /* lose the space */
876
/* don't overwrite existing artist names. */
880
while (i != '\n' && i != EOF);
883
fgets(cd->artist, sizeof(cd->artist), fp);
884
if( (i = strlen(cd->artist)) )
885
cd->artist[i - 1] = '\0';
889
else if (! strcmp(keyword, "cdvolume"))
891
fscanf(fp, "%d", &cd->volume);
892
cd->volume = (cd->volume * 100) / 32;
895
else if (! strcmp(keyword, "dontplay"))
897
fscanf(fp, "%d", &i);
898
if (trackmap[i - 1] != -1)
899
cd->trk[trackmap[i - 1]].avoid = 1;
902
else if (! strcmp(keyword, "continue"))
904
if (trackmap[track - 1] != -1)
905
cd->trk[trackmap[track - 1]].contd = 1;
908
else if (! strcmp(keyword, "volume"))
910
fscanf(fp, "%d", &i);
911
if (trackmap[i - 1] == -1)
916
fscanf(fp, "%d", &cd->trk[i].volume);
917
cd->trk[i].volume = (cd->trk[i].volume*100)/32;
918
if (cd->trk[i].volume > 32)
919
cd->trk[i].volume = 0;
923
else if (! strcmp(keyword, "playlist"))
926
fscanf(fp, "%s", listname);
928
/* XXX take this out at some point */
929
if (! strcmp(listname, "Default"))
930
strcpy(listname, "List A");
932
for (i = 0; listname[i]; i++)
933
if (listname[i] == '_')
936
l = new_list(cd, listname);
940
perror("playlist read");
944
fscanf(fp, "%d", &listsize);
946
l->list = malloc(sizeof(int) * (listsize + 1));
950
/* Leave out tracks that weren't in .workmandb. */
952
for (i = 0; i < listsize; i++)
954
fscanf(fp, "%d", &scratch);
955
scratch = trackmap[scratch - 1];
957
l->list[j++] = scratch + 1;
963
else if (! strcmp(keyword, "mark"))
965
int mark_val = -1, mark_namelen;
968
fscanf(fp, "%d", &mark_val);
975
fgets(mark_name, sizeof(mark_name), fp);
976
if( ( mark_namelen = strlen(mark_name)) )
977
mark_name[mark_namelen - 1] = '\0';
980
if (! strcmp(mark_name, "START"))
981
set_abtimer(0, mark_val);
982
else if (! strcmp(mark_name, "END"))
983
set_abtimer(1, mark_val);
988
/* Unrecognized keyword. Put it in the right place. */
991
char **buf, input[BUFSIZ];
993
if (track && trackmap[track - 1] == -1)
999
i = track ? trackmap[track - 1] : 0;
1000
buf = prefs ? i ? &cd->trk[i].otherrc : &cd->otherrc :
1001
i ? &cd->trk[i].otherdb : &cd->otherdb;
1002
if (firstpos == -1) {
1009
wm_strmcat(buf, keyword);
1011
input[sizeof(input) - 1] = 'x';
1012
fgets(input, sizeof(input), fp);
1013
wm_strmcat(buf, input);
1014
} while (input[sizeof(input) - 1] != 'x');
1018
if (rclen == 0 && !searching)
1019
rclen = pos - rcpos;
1021
if (searching > 1) /* A near match has been found. Good enough. */
1025
return (! searching);
1030
* Delay some amount of time without using interval timers.
1033
spinwheels(int secs) {
1038
select(0, NULL, NULL, NULL, &tv);
1039
} /* spinwheels() */
1044
* fd file descriptor
1047
* Lock a file. Time out after a little while if we can't get a lock;
1048
* this usually means the locking system is broken.
1050
* Unfortunately, if there are lots of people contending for a lock,
1051
* this can result in the file not getting locked when it probably should.
1054
lockit(int fd, int type)
1057
int result, timer = 0;
1059
if (suppress_locking)
1067
while ((result = fcntl(fd, F_SETLK, &fl)) < 0)
1069
if (errno != EACCES || errno != EAGAIN)
1084
* Search all the database files and our personal preference file for
1085
* more information about the current CD.
1093
int dbfound = 0, *trklist, i;
1094
unsigned long dbpos;
1096
/* This is some kind of profiling code. I don't change it
1097
to wm_lib_message() for now... */
1100
if( getenv( "WORKMAN_DEBUG" ) != NULL )
1103
printf("%s (%d): search start = %ld\n", __FILE__, __LINE__, t1);
1112
/* Turn the cd->trk array into a simple array of ints. */
1113
trklist = (int *)malloc(sizeof(int) * cd->ntracks);
1114
for (i = 0; i < cd->ntracks; i++)
1115
trklist[i] = cd->trk[i].start;
1118
if (*dbfile && idx_find_entry(*dbfile, cd->ntracks, trklist,
1119
cd->length * 75, 0, &dbpos) == 0)
1122
fp = *dbfile ? open_rcfile(*dbfile, "r") : NULL;
1125
if (lockit(fileno(fp), F_RDLCK))
1126
perror("Couldn't get read (db) lock");
1131
fseek(fp, dbpos, 0);
1133
if (search_db(fp, 0, 0, 0))
1136
cd->whichdb = *dbfile;
1139
if (locked && lockit(fileno(fp), F_UNLCK))
1140
perror("Couldn't relinquish (db) lock");
1144
} while (*++dbfile != NULL && cd->whichdb == NULL);
1147
if( getenv( "WORKMAN_DEBUG" ) != NULL )
1150
printf("%s (%d): db search end = %ld, elapsed = %ld\n", __FILE__, __LINE__, t2, t2 - t1);
1155
fp = rcfile ? open_rcfile(rcfile, "r") : NULL;
1159
if (lockit(fileno(fp), F_RDLCK))
1160
perror("Couldn't get read (rc) lock");
1165
found_in_rc = search_db(fp, 1, 0, 0);
1167
cd->autoplay = wm_db_get_playnew();
1169
if (locked && lockit(fileno(fp), F_UNLCK))
1170
perror("Couldn't relinquish (rc) lock");
1177
if (cur_playnew == -1)
1181
if( getenv( "WORKMAN_DEBUG" ) != NULL )
1184
printf("%s (%d): search end = %ld, elapsed = %ld\n", __FILE__, __LINE__, t2, t2 - t1);
1191
* Load program settings from the rcfile.
1194
load_settings( void )
1199
fp = rcfile ? open_rcfile(rcfile, "r") : NULL;
1203
if (lockit(fileno(fp), F_RDLCK))
1204
perror("Couldn't get read (rc) lock");
1209
found_in_rc = search_db(fp, 2, 0, 0);
1211
cd->autoplay = wm_db_get_playnew();
1213
if (locked && lockit(fileno(fp), F_UNLCK))
1214
perror("Couldn't relinquish (rc) lock");
1218
} /* load_settings() */
1223
* Save the global preferences, scooting CD entries to the end if needed.
1224
* The assumption here is that the rcfile is locked, and that firstpos has
1225
* been set by a previous scan.
1228
save_globals(FILE *fp)
1230
char *globes = NULL, *cdentry = NULL, temp[100];
1232
int globesize, hit_cdent = 0, c = 0;
1235
wm_strmcpy(&globes, otherrc);
1239
sprintf(temp, "cddbprotocol ");
1240
switch(cddb.protocol)
1243
sprintf(temp + strlen(temp), "cddbp\n");
1246
sprintf(temp + strlen(temp), "http\n");
1249
sprintf(temp + strlen(temp), "proxy\n");
1254
wm_strmcat(&globes, temp);
1256
if(cddb.mail_adress[0])
1258
sprintf(temp,"cddbmailadress %s\n",
1260
wm_strmcat(&globes, temp);
1263
if(cddb.cddb_server[0])
1265
sprintf(temp,"cddbserver %s\n",
1267
wm_strmcat(&globes, temp);
1270
if(cddb.path_to_cgi[0])
1272
sprintf(temp,"cddbpathtocgi %s\n",
1274
wm_strmcat(&globes, temp);
1277
if(cddb.proxy_server[0])
1279
sprintf(temp,"cddbproxy %s\n",
1281
wm_strmcat(&globes, temp);
1285
if (cur_stopmode == 1 || cur_stopmode == 2)
1287
sprintf(temp, "whendone %s\n", cur_stopmode == 1 ? "repeat" :
1289
wm_strmcat(&globes, temp);
1292
if (cur_playnew == 1)
1293
wm_strmcat(&globes, "playnew\n");
1299
fseek(fp, curpos, SEEK_SET);
1301
if (firstpos < (globesize = globes != NULL ? strlen(globes) : 0))
1305
temp[sizeof(temp)-1] = 'x';
1307
if (fgets(temp, sizeof(temp), fp) == NULL)
1309
fseek(fp, 0, SEEK_SET);
1312
fwrite(globes, globesize, 1, fp);
1315
if (cdentry != NULL)
1317
fwrite(cdentry, strlen(cdentry), 1, fp);
1323
if (! strncmp(temp, "tracks ", 7))
1326
if (curpos >= globesize)
1332
curpos += strlen(temp);
1333
if (temp[sizeof(temp)-1] == '\0')
1334
while ((c = getc(fp)) != '\n' &&
1343
wm_strmcat(&cdentry, temp);
1344
curpos += strlen(temp);
1345
while (temp[sizeof(temp)-1] == '\0')
1347
temp[sizeof(temp)-1] = 'x';
1348
if (fgets(temp, sizeof(temp), fp) == NULL)
1350
wm_strmcat(&cdentry, temp);
1351
curpos += strlen(temp);
1355
if (cdentry != NULL)
1357
fseek(fp, 0, SEEK_END);
1358
fwrite(cdentry, strlen(cdentry), 1, fp);
1365
fseek(fp, 0, SEEK_SET);
1366
fwrite(globes, globesize, 1, fp);
1370
while (globesize++ < curpos)
1372
} /* save_globals() */
1377
* Save the CD information to one database.
1379
* filename Database to save to.
1380
* pref 0 for hard data, 1 for preferences.
1382
* If an entry for this CD exists already, overwrite it with the new entry
1383
* if the new entry is the same size or smaller, or with newlines if the new
1384
* entry is larger (in which case the new entry is appended to the file.)
1386
* Also, if the preference information is being updated, save it to the
1387
* file while we've got it locked. Scoot stuff from the beginning of
1388
* the file to the end as needed to facilitate this.
1390
* XXX Preference-saving should probably be done elsewhere, like in an
1391
* Apply button on the Goodies popup, and in any case needs to go to a
1392
* different file (.Xdefaults?)
1394
* Returns 0 on success.
1397
save_entry(char *filename, int pref)
1401
int len, i, locked = 0;
1404
if( filename == NULL )
1407
fp = open_rcfile(filename, "r+");
1410
if (errno == ENOENT) /* doesn't exist already */
1411
fp = open_rcfile(filename, "w");
1416
if (lockit(fileno(fp), F_WRLCK))
1417
perror("Warning: Couldn't get write lock");
1421
buf = print_cdinfo(cd, pref);
1422
len = strlen(buf); /* doesn't return if there's an error */
1425
search_db(fp, pref, 1, len);
1426
if (rcpos != -1) /* XXX */
1429
* Jump to the entry's position in the database file, if
1432
fseek(fp, rcpos, SEEK_SET);
1434
if (rclen >= len && holepos == -1)
1437
* If the new entry will fit in the space occupied by
1438
* the old one, overwrite the old one and make a hole
1439
* of the appropriate size at its end.
1441
* No need to update the index file in this case, as
1442
* the entry's position hasn't changed.
1445
for (i = len; i < rclen; i++)
1451
* Overwrite the old entry with a hole and delete
1452
* its pointer in the index file.
1454
for (i = 0; i < rclen; i++)
1456
idx_delete_entry(filename, cd->trk[cd->ntracks-1].start,
1464
* Old entry wasn't found, or its new version wouldn't fit where
1470
* Write the new entry in a hole, if there is one,
1471
* or at the end of the file.
1475
fseek(fp, holepos, SEEK_SET);
1476
if (holepos < firstpos)
1481
fseek(fp, 0, SEEK_END);
1482
holepos = ftell(fp);
1487
* Write a new index entry for this CD.
1489
idx_write_entry(filename, cd->trk[cd->ntracks - 1].start,
1498
if (locked && lockit(fileno(fp), F_UNLCK))
1499
perror("Warning: Couldn't relinquish write lock");
1504
} /* save_entry() */
1509
* Save CD information to the appropriate datafile (the first file in the
1510
* list, unless the entry came from another database file) and to the
1511
* personal prefs file.
1517
if( wm_db_save_disabled == FALSE )
1519
if (save_entry(rcfile, 1))
1522
if (cd->whichdb == NULL || access(cd->whichdb, W_OK))
1523
cd->whichdb = databases[0];
1525
if (save_entry(cd->whichdb, 0))
1528
return( WM_DB_SAVE_ERROR );
1530
return( WM_DB_SAVE_DISABLED );