summaryrefslogtreecommitdiff
path: root/src/libpiano
diff options
context:
space:
mode:
authorLars-Dominik Braun <lars@6xq.net>2013-08-04 18:53:43 +0200
committerLars-Dominik Braun <lars@6xq.net>2013-08-07 17:37:33 +0200
commitee2e73cd7b5a1de68c8316e916c4ef3a88302bed (patch)
treee952d75d075598123d5ecbe92f14838ce75f6db5 /src/libpiano
parent36ea2f13f87b9310219790c3cee498201d54f8e0 (diff)
downloadpianobar-ee2e73cd7b5a1de68c8316e916c4ef3a88302bed.tar.gz
pianobar-ee2e73cd7b5a1de68c8316e916c4ef3a88302bed.tar.bz2
pianobar-ee2e73cd7b5a1de68c8316e916c4ef3a88302bed.zip
piano: Generic linked lists
Introduces generic linked list structure and functions (like append, delete, …). Removes a lot of copy&pasted code and improves code readability/reusability. Heads up: This change breaks libpiano’s ABI.
Diffstat (limited to 'src/libpiano')
-rw-r--r--src/libpiano/list.c112
-rw-r--r--src/libpiano/piano.c27
-rw-r--r--src/libpiano/piano.h42
-rw-r--r--src/libpiano/request.c6
-rw-r--r--src/libpiano/response.c163
5 files changed, 194 insertions, 156 deletions
diff --git a/src/libpiano/list.c b/src/libpiano/list.c
new file mode 100644
index 0000000..2e83ab0
--- /dev/null
+++ b/src/libpiano/list.c
@@ -0,0 +1,112 @@
+/*
+Copyright (c) 2013
+ Lars-Dominik Braun <lars@6xq.net>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <assert.h>
+
+#include "piano.h"
+
+#define PianoListForeach(l) for (; (l) != NULL; (l) = (void *) (l)->next)
+
+/* append element e to list l, return new list head
+ */
+void *PianoListAppend (PianoListHead_t * const l, PianoListHead_t * const e) {
+ assert (e != NULL);
+ assert (e->next == NULL);
+
+ if (l == NULL) {
+ return e;
+ } else {
+ PianoListHead_t *curr = l;
+ while (curr->next != NULL) {
+ curr = curr->next;
+ }
+ curr->next = e;
+ return l;
+ }
+}
+
+/* prepend element e to list l, returning new list head
+ */
+void *PianoListPrepend (PianoListHead_t * const l, PianoListHead_t * const e) {
+ assert (e != NULL);
+ assert (e->next == NULL);
+
+ e->next = l;
+ return e;
+}
+
+/* delete element e from list l, return new list head
+ */
+void *PianoListDelete (PianoListHead_t * const l, PianoListHead_t * const e) {
+ assert (l != NULL);
+ assert (e != NULL);
+
+ PianoListHead_t *first = l, *curr = l, *prev = NULL;
+ PianoListForeach (curr) {
+ if (curr == e) {
+ /* found it! */
+ if (prev != NULL) {
+ prev->next = curr->next;
+ } else {
+ /* no successor */
+ first = curr->next;
+ }
+ break;
+ }
+ prev = curr;
+ }
+
+ return first;
+}
+
+/* get nth element of list
+ */
+void *PianoListGet (PianoListHead_t * const l, const size_t n) {
+ PianoListHead_t *curr = l;
+ size_t i = n;
+
+ PianoListForeach (curr) {
+ if (i == 0) {
+ return curr;
+ }
+ --i;
+ }
+
+ return NULL;
+}
+
+/* count elements in list l
+ */
+size_t PianoListCount (const PianoListHead_t * const l) {
+ assert (l != NULL);
+
+ size_t count = 0;
+ const PianoListHead_t *curr = l;
+
+ PianoListForeach (curr) {
+ ++count;
+ }
+
+ return count;
+}
+
diff --git a/src/libpiano/piano.c b/src/libpiano/piano.c
index 9020a6a..b519f49 100644
--- a/src/libpiano/piano.c
+++ b/src/libpiano/piano.c
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2008-2012
+Copyright (c) 2008-2013
Lars-Dominik Braun <lars@6xq.net>
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -80,7 +80,7 @@ static void PianoDestroyArtists (PianoArtist_t *artists) {
free (curArtist->musicId);
free (curArtist->seedId);
lastArtist = curArtist;
- curArtist = curArtist->next;
+ curArtist = (PianoArtist_t *) curArtist->head.next;
free (lastArtist);
}
}
@@ -113,7 +113,7 @@ static void PianoDestroyStations (PianoStation_t *stations) {
curStation = stations;
while (curStation != NULL) {
lastStation = curStation;
- curStation = curStation->next;
+ curStation = (PianoStation_t *) curStation->head.next;
PianoDestroyStation (lastStation);
free (lastStation);
}
@@ -141,7 +141,7 @@ void PianoDestroyPlaylist (PianoSong_t *playlist) {
free (curSong->detailUrl);
free (curSong->trackToken);
lastSong = curSong;
- curSong = curSong->next;
+ curSong = (PianoSong_t *) curSong->head.next;
free (lastSong);
}
}
@@ -163,7 +163,7 @@ static void PianoDestroyGenres (PianoGenre_t *genres) {
free (curGenre->name);
free (curGenre->musicId);
lastGenre = curGenre;
- curGenre = curGenre->next;
+ curGenre = (PianoGenre_t *) curGenre->head.next;
free (lastGenre);
}
}
@@ -201,7 +201,7 @@ void PianoDestroy (PianoHandle_t *ph) {
PianoDestroyGenres (curGenreCat->genres);
free (curGenreCat->name);
lastGenreCat = curGenreCat;
- curGenreCat = curGenreCat->next;
+ curGenreCat = (PianoGenreCategory_t *) curGenreCat->head.next;
free (lastGenreCat);
}
memset (ph, 0, sizeof (*ph));
@@ -221,14 +221,17 @@ void PianoDestroyRequest (PianoRequest_t *req) {
* @param search for this
* @return the first station structure matching the given id
*/
-PianoStation_t *PianoFindStationById (PianoStation_t *stations,
- const char *searchStation) {
- while (stations != NULL) {
- if (strcmp (stations->id, searchStation) == 0) {
- return stations;
+PianoStation_t *PianoFindStationById (PianoStation_t * const stations,
+ const char * const searchStation) {
+ assert (searchStation != NULL);
+
+ PianoStation_t *currStation = stations;
+ PianoListForeachP (currStation) {
+ if (strcmp (currStation->id, searchStation) == 0) {
+ return currStation;
}
- stations = stations->next;
}
+
return NULL;
}
diff --git a/src/libpiano/piano.h b/src/libpiano/piano.h
index 04f33b5..ce66171 100644
--- a/src/libpiano/piano.h
+++ b/src/libpiano/piano.h
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2008-2011
+Copyright (c) 2008-2013
Lars-Dominik Braun <lars@6xq.net>
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -42,19 +42,23 @@ THE SOFTWARE.
#define PIANO_RPC_HOST "tuner.pandora.com"
#define PIANO_RPC_PATH "/services/json/?"
+typedef struct PianoListHead {
+ struct PianoListHead *next;
+} PianoListHead_t;
+
typedef struct PianoUserInfo {
char *listenerId;
char *authToken;
} PianoUserInfo_t;
typedef struct PianoStation {
+ PianoListHead_t head;
char isCreator;
char isQuickMix;
char useQuickMix; /* station will be included in quickmix */
char *name;
char *id;
char *seedId;
- struct PianoStation *next;
} PianoStation_t;
typedef enum {
@@ -78,6 +82,7 @@ typedef enum {
} PianoAudioQuality_t;
typedef struct PianoSong {
+ PianoListHead_t head;
char *artist;
char *stationId;
char *album;
@@ -92,28 +97,27 @@ typedef struct PianoSong {
float fileGain;
PianoSongRating_t rating;
PianoAudioFormat_t audioFormat;
- struct PianoSong *next;
} PianoSong_t;
/* currently only used for search results */
typedef struct PianoArtist {
+ PianoListHead_t head;
char *name;
char *musicId;
char *seedId;
int score;
- struct PianoArtist *next;
} PianoArtist_t;
typedef struct PianoGenre {
+ PianoListHead_t head;
char *name;
char *musicId;
- struct PianoGenre *next;
} PianoGenre_t;
typedef struct PianoGenreCategory {
+ PianoListHead_t head;
char *name;
PianoGenre_t *genres;
- struct PianoGenreCategory *next;
} PianoGenreCategory_t;
typedef struct PianoPartner {
@@ -298,6 +302,27 @@ typedef enum {
PIANO_RET_P_RATE_LIMIT = PIANO_RET_OFFSET+1039,
} PianoReturn_t;
+/* list stuff */
+#ifndef __GNUC__
+# define __attribute__(x)
+#endif
+size_t PianoListCount (const PianoListHead_t * const l);
+#define PianoListCountP(l) PianoListCount(&(l)->head)
+void *PianoListAppend (PianoListHead_t * const l, PianoListHead_t * const e)
+ __attribute__ ((warn_unused_result));
+#define PianoListAppendP(l,e) PianoListAppend(&(l)->head, &(e)->head)
+void *PianoListDelete (PianoListHead_t * const l, PianoListHead_t * const e)
+ __attribute__ ((warn_unused_result));
+#define PianoListDeleteP(l,e) PianoListDelete(&(l)->head, &(e)->head)
+#define PianoListNextP(e) ((void *) (e)->head.next)
+void *PianoListPrepend (PianoListHead_t * const l, PianoListHead_t * const e)
+ __attribute__ ((warn_unused_result));
+#define PianoListPrependP(l,e) PianoListPrepend (&(l)->head, &(e)->head)
+void *PianoListGet (PianoListHead_t * const l, const size_t n);
+#define PianoListGetP(l,n) PianoListGet (&(l)->head, n)
+#define PianoListForeachP(l) for (; (l) != NULL; (l) = (void *) (l)->head.next)
+
+/* memory management */
PianoReturn_t PianoInit (PianoHandle_t *, const char *,
const char *, const char *, const char *,
const char *);
@@ -306,12 +331,15 @@ void PianoDestroyPlaylist (PianoSong_t *);
void PianoDestroySearchResult (PianoSearchResult_t *);
void PianoDestroyStationInfo (PianoStationInfo_t *);
+/* pandora rpc */
PianoReturn_t PianoRequest (PianoHandle_t *, PianoRequest_t *,
PianoRequestType_t);
PianoReturn_t PianoResponse (PianoHandle_t *, PianoRequest_t *);
void PianoDestroyRequest (PianoRequest_t *);
-PianoStation_t *PianoFindStationById (PianoStation_t *, const char *);
+/* misc */
+PianoStation_t *PianoFindStationById (PianoStation_t * const,
+ const char * const);
const char *PianoErrorToStr (PianoReturn_t);
#endif /* _PIANO_H */
diff --git a/src/libpiano/request.c b/src/libpiano/request.c
index 85d6286..82bf350 100644
--- a/src/libpiano/request.c
+++ b/src/libpiano/request.c
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2008-2012
+Copyright (c) 2008-2013
Lars-Dominik Braun <lars@6xq.net>
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -272,14 +272,12 @@ PianoReturn_t PianoRequest (PianoHandle_t *ph, PianoRequest_t *req,
PianoStation_t *curStation = ph->stations;
json_object *a = json_object_new_array ();
- while (curStation != NULL) {
+ PianoListForeachP (curStation) {
/* quick mix can't contain itself */
if (curStation->useQuickMix && !curStation->isQuickMix) {
json_object_array_add (a,
json_object_new_string (curStation->id));
}
-
- curStation = curStation->next;
}
json_object_object_add (j, "quickMixStationIds", a);
diff --git a/src/libpiano/response.c b/src/libpiano/response.c
index ae7b140..41bbfd3 100644
--- a/src/libpiano/response.c
+++ b/src/libpiano/response.c
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2008-2012
+Copyright (c) 2008-2013
Lars-Dominik Braun <lars@6xq.net>
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -193,21 +193,13 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {
}
/* start new linked list or append */
- if (ph->stations == NULL) {
- ph->stations = tmpStation;
- } else {
- PianoStation_t *curStation = ph->stations;
- while (curStation->next != NULL) {
- curStation = curStation->next;
- }
- curStation->next = tmpStation;
- }
+ ph->stations = PianoListAppendP (ph->stations, tmpStation);
}
/* fix quickmix flags */
if (mix != NULL) {
PianoStation_t *curStation = ph->stations;
- while (curStation != NULL) {
+ PianoListForeachP (curStation) {
for (size_t i = 0; i < json_object_array_length (mix); i++) {
json_object *id = json_object_array_get_idx (mix, i);
if (strcmp (json_object_get_string (id),
@@ -215,7 +207,6 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {
curStation->useQuickMix = true;
}
}
- curStation = curStation->next;
}
}
break;
@@ -293,16 +284,7 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {
break;
}
- /* begin linked list or append */
- if (playlist == NULL) {
- playlist = song;
- } else {
- PianoSong_t *curSong = playlist;
- while (curSong->next != NULL) {
- curSong = curSong->next;
- }
- curSong->next = song;
- }
+ playlist = PianoListAppendP (playlist, song);
}
reqData->retPlaylist = playlist;
@@ -340,23 +322,9 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {
assert (station != NULL);
- /* delete station from local station list */
- PianoStation_t *curStation = ph->stations, *lastStation = NULL;
- while (curStation != NULL) {
- if (curStation == station) {
- if (lastStation != NULL) {
- lastStation->next = curStation->next;
- } else {
- /* first station in list */
- ph->stations = curStation->next;
- }
- PianoDestroyStation (curStation);
- free (curStation);
- break;
- }
- lastStation = curStation;
- curStation = curStation->next;
- }
+ ph->stations = PianoListDeleteP (ph->stations, station);
+ PianoDestroyStation (station);
+ free (station);
break;
}
@@ -385,16 +353,8 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {
artist->name = PianoJsonStrdup (a, "artistName");
artist->musicId = PianoJsonStrdup (a, "musicToken");
- /* add result to linked list */
- if (searchResult->artists == NULL) {
- searchResult->artists = artist;
- } else {
- PianoArtist_t *curArtist = searchResult->artists;
- while (curArtist->next != NULL) {
- curArtist = curArtist->next;
- }
- curArtist->next = artist;
- }
+ searchResult->artists =
+ PianoListAppendP (searchResult->artists, artist);
}
}
@@ -413,16 +373,8 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {
song->artist = PianoJsonStrdup (s, "artistName");
song->musicId = PianoJsonStrdup (s, "musicToken");
- /* add result to linked list */
- if (searchResult->songs == NULL) {
- searchResult->songs = song;
- } else {
- PianoSong_t *curSong = searchResult->songs;
- while (curSong->next != NULL) {
- curSong = curSong->next;
- }
- curSong->next = song;
- }
+ searchResult->songs =
+ PianoListAppendP (searchResult->songs, song);
}
}
break;
@@ -438,32 +390,14 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {
PianoJsonParseStation (result, tmpStation);
- if (ph->stations == NULL) {
- ph->stations = tmpStation;
- } else {
- PianoStation_t *curStation = ph->stations, *prevStation = NULL;
- while (curStation->next != NULL) {
- /* replace if station with same id exists already */
- if (strcmp (curStation->id, tmpStation->id) == 0) {
- if (prevStation == NULL) {
- ph->stations = tmpStation;
- } else {
- prevStation->next = tmpStation;
- }
- tmpStation->next = curStation->next;
-
- PianoDestroyStation (curStation);
- free (curStation);
- break;
- }
- prevStation = curStation;
- curStation = curStation->next;
- }
- /* append otherwise */
- if (tmpStation->next == NULL) {
- curStation->next = tmpStation;
- }
+ PianoStation_t *search = PianoFindStationById (ph->stations,
+ tmpStation->id);
+ if (search != NULL) {
+ ph->stations = PianoListDeleteP (ph->stations, search);
+ PianoDestroyStation (search);
+ free (search);
}
+ ph->stations = PianoListAppendP (ph->stations, tmpStation);
break;
}
@@ -514,29 +448,14 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {
tmpGenre->musicId = PianoJsonStrdup (s,
"stationToken");
- /* append station */
- if (tmpGenreCategory->genres == NULL) {
- tmpGenreCategory->genres = tmpGenre;
- } else {
- PianoGenre_t *curGenre =
- tmpGenreCategory->genres;
- while (curGenre->next != NULL) {
- curGenre = curGenre->next;
- }
- curGenre->next = tmpGenre;
- }
- }
- }
- /* append category */
- if (ph->genreStations == NULL) {
- ph->genreStations = tmpGenreCategory;
- } else {
- PianoGenreCategory_t *curCat = ph->genreStations;
- while (curCat->next != NULL) {
- curCat = curCat->next;
+ tmpGenreCategory->genres =
+ PianoListAppendP (tmpGenreCategory->genres,
+ tmpGenre);
}
- curCat->next = tmpGenreCategory;
}
+
+ ph->genreStations = PianoListAppendP (ph->genreStations,
+ tmpGenreCategory);
}
}
break;
@@ -615,15 +534,8 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {
seedSong->artist = PianoJsonStrdup (s, "artistName");
seedSong->seedId = PianoJsonStrdup (s, "seedId");
- if (info->songSeeds == NULL) {
- info->songSeeds = seedSong;
- } else {
- PianoSong_t *curSong = info->songSeeds;
- while (curSong->next != NULL) {
- curSong = curSong->next;
- }
- curSong->next = seedSong;
- }
+ info->songSeeds = PianoListAppendP (info->songSeeds,
+ seedSong);
}
}
@@ -643,15 +555,8 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {
seedArtist->name = PianoJsonStrdup (a, "artistName");
seedArtist->seedId = PianoJsonStrdup (a, "seedId");
- if (info->artistSeeds == NULL) {
- info->artistSeeds = seedArtist;
- } else {
- PianoArtist_t *curArtist = info->artistSeeds;
- while (curArtist->next != NULL) {
- curArtist = curArtist->next;
- }
- curArtist->next = seedArtist;
- }
+ info->artistSeeds =
+ PianoListAppendP (info->artistSeeds, seedArtist);
}
}
}
@@ -679,16 +584,8 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {
json_object_object_get (s, "isPositive")) ?
PIANO_RATE_LOVE : PIANO_RATE_BAN;
-
- if (info->feedback == NULL) {
- info->feedback = feedbackSong;
- } else {
- PianoSong_t *curSong = info->feedback;
- while (curSong->next != NULL) {
- curSong = curSong->next;
- }
- curSong->next = feedbackSong;
- }
+ info->feedback = PianoListAppendP (info->feedback,
+ feedbackSong);
}
}
}