summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--COPYING2
-rw-r--r--src/main.c83
-rw-r--r--src/main.h10
-rw-r--r--src/ui.c55
-rw-r--r--src/ui.h14
-rw-r--r--src/ui_act.c30
-rw-r--r--src/ui_act.h4
-rw-r--r--src/ui_readline.c110
-rw-r--r--src/ui_readline.h32
9 files changed, 197 insertions, 143 deletions
diff --git a/COPYING b/COPYING
index af7b233..1ca7f75 100644
--- a/COPYING
+++ b/COPYING
@@ -1,4 +1,4 @@
-Copyright (c) 2008-2010
+Copyright (c) 2008-2011
Lars-Dominik Braun <lars@6xq.net>
Permission is hereby granted, free of charge, to any person obtaining a copy
diff --git a/src/main.c b/src/main.c
index 14e7c89..54d6006 100644
--- a/src/main.c
+++ b/src/main.c
@@ -53,7 +53,7 @@ THE SOFTWARE.
#include "ui_act.h"
#include "ui_readline.h"
-typedef void (*BarKeyShortcutFunc_t) (BarApp_t *app, FILE *curFd);
+typedef void (*BarKeyShortcutFunc_t) (BarApp_t *app);
/* copy proxy settings to waitress handle
*/
@@ -94,17 +94,19 @@ static bool BarMainLoginUser (BarApp_t *app) {
/* ask for username/password if none were provided in settings
*/
-static void BarMainGetLoginCredentials (BarSettings_t *settings) {
+static void BarMainGetLoginCredentials (BarSettings_t *settings,
+ BarReadlineFds_t *input) {
if (settings->username == NULL) {
char nameBuf[100];
BarUiMsg (MSG_QUESTION, "Username: ");
- BarReadlineStr (nameBuf, sizeof (nameBuf), 0, stdin);
+ BarReadlineStr (nameBuf, sizeof (nameBuf), input, BAR_RL_DEFAULT);
settings->username = strdup (nameBuf);
}
if (settings->password == NULL) {
char passBuf[100];
BarUiMsg (MSG_QUESTION, "Password: ");
- BarReadlineStr (passBuf, sizeof (passBuf), 1, stdin);
+ BarReadlineStr (passBuf, sizeof (passBuf), input, BAR_RL_NOECHO);
+ write (STDIN_FILENO, "\n", 1);
settings->password = strdup (passBuf);
}
}
@@ -136,8 +138,8 @@ static void BarMainGetInitialStation (BarApp_t *app) {
}
/* no autostart? ask the user */
if (app->curStation == NULL) {
- app->curStation = BarUiSelectStation (&(app->ph), "Select station: ",
- app->settings.sortOrder, stdin);
+ app->curStation = BarUiSelectStation (&app->ph, "Select station: ",
+ app->settings.sortOrder, &app->input);
}
if (app->curStation != NULL) {
BarUiPrintStation (app->curStation);
@@ -147,35 +149,12 @@ static void BarMainGetInitialStation (BarApp_t *app) {
/* wait for user input
*/
static void BarMainHandleUserInput (BarApp_t *app) {
- struct timeval selectTimeout;
- fd_set readSetCopy;
- char buf = '\0';
-
- /* select modifies its arguments => copy the set */
- memcpy (&readSetCopy, &app->readSet, sizeof (app->readSet));
- selectTimeout.tv_sec = 1;
- selectTimeout.tv_usec = 0;
-
- /* in the meantime: wait for user actions */
- if (select (app->maxFd, &readSetCopy, NULL, NULL, &selectTimeout) > 0) {
- FILE *curFd = NULL;
-
- if (FD_ISSET(app->selectFds[0], &readSetCopy)) {
- curFd = stdin;
- } else if (app->selectFds[1] != -1 && FD_ISSET(app->selectFds[1],
- &readSetCopy)) {
- curFd = app->ctlFd;
- }
- buf = fgetc (curFd);
- if (buf == EOF) {
- /* select() is going wild if fdset contains EOFed fd's */
- FD_CLR (fileno (curFd), &app->readSet);
- }
-
- size_t i;
- for (i = 0; i < BAR_KS_COUNT; i++) {
+ char buf[2];
+ if (BarReadline (buf, sizeof (buf), NULL, &app->input,
+ BAR_RL_FULLRETURN | BAR_RL_NOECHO, 1) > 0) {
+ for (size_t i = 0; i < BAR_KS_COUNT; i++) {
if (app->settings.keys[i] != BAR_KS_DISABLED &&
- app->settings.keys[i] == buf) {
+ app->settings.keys[i] == buf[0]) {
static const BarKeyShortcutFunc_t idToF[] = {BarUiActHelp,
BarUiActLoveSong, BarUiActBanSong,
BarUiActAddMusic, BarUiActCreateStation,
@@ -188,11 +167,11 @@ static void BarMainHandleUserInput (BarApp_t *app) {
BarUiActPrintUpcoming, BarUiActSelectQuickMix,
BarUiActDebug, BarUiActBookmark, BarUiActVolDown,
BarUiActVolUp};
- idToF[i] (app, curFd);
+ idToF[i] (app);
break;
}
- }
- }
+ } /* end for */
+ } /* end if */
}
/* append current song to history list and move to the next song
@@ -345,7 +324,7 @@ static void BarMainPrintTime (BarApp_t *app) {
static void BarMainLoop (BarApp_t *app) {
pthread_t playerThread;
- BarMainGetLoginCredentials (&app->settings);
+ BarMainGetLoginCredentials (&app->settings, &app->input);
BarMainLoadProxy (&app->settings, &app->waith);
@@ -435,28 +414,26 @@ int main (int argc, char **argv) {
}
/* init fds */
- FD_ZERO(&app.readSet);
- app.selectFds[0] = fileno (stdin);
- FD_SET(app.selectFds[0], &app.readSet);
+ FD_ZERO(&app.input.set);
+ app.input.fds[0] = STDIN_FILENO;
+ FD_SET(app.input.fds[0], &app.input.set);
BarGetXdgConfigDir (PACKAGE "/ctl", ctlPath, sizeof (ctlPath));
- /* FIXME: why is r_+_ required? */
- app.ctlFd = fopen (ctlPath, "r+");
- if (app.ctlFd != NULL) {
- app.selectFds[1] = fileno (app.ctlFd);
- FD_SET(app.selectFds[1], &app.readSet);
+ /* open fifo read/write so it won't EOF if nobody writes to it */
+ assert (sizeof (app.input.fds) / sizeof (*app.input.fds) >= 2);
+ app.input.fds[1] = open (ctlPath, O_RDWR);
+ if (app.input.fds[1] != -1) {
+ FD_SET(app.input.fds[1], &app.input.set);
BarUiMsg (MSG_INFO, "Control fifo at %s opened\n", ctlPath);
- } else {
- app.selectFds[1] = -1;
}
- app.maxFd = app.selectFds[0] > app.selectFds[1] ? app.selectFds[0] :
- app.selectFds[1];
- ++app.maxFd;
+ app.input.maxfd = app.input.fds[0] > app.input.fds[1] ? app.input.fds[0] :
+ app.input.fds[1];
+ ++app.input.maxfd;
BarMainLoop (&app);
- if (app.ctlFd != NULL) {
- fclose (app.ctlFd);
+ if (app.input.fds[1] != -1) {
+ close (app.input.fds[1]);
}
PianoDestroy (&app.ph);
diff --git a/src/main.h b/src/main.h
index 2ef651c..14d1368 100644
--- a/src/main.h
+++ b/src/main.h
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2008-2010
+Copyright (c) 2008-2011
Lars-Dominik Braun <lars@6xq.net>
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -27,10 +27,9 @@ THE SOFTWARE.
#include <piano.h>
#include <waitress.h>
-#include <sys/select.h>
-
#include "player.h"
#include "settings.h"
+#include "ui_readline.h"
typedef struct {
PianoHandle_t ph;
@@ -42,10 +41,7 @@ typedef struct {
PianoSong_t *songHistory;
PianoStation_t *curStation;
char doQuit;
- fd_set readSet;
- int maxFd;
- int selectFds[2];
- FILE *ctlFd;
+ BarReadlineFds_t input;
} BarApp_t;
#endif /* _MAIN_H */
diff --git a/src/ui.c b/src/ui.c
index 6166044..5df8cdc 100644
--- a/src/ui.c
+++ b/src/ui.c
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2008-2010
+Copyright (c) 2008-2011
Lars-Dominik Braun <lars@6xq.net>
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -297,13 +297,16 @@ PianoStation_t **BarSortedStations (PianoStation_t *unsortedStations,
/* let user pick one station
* @param piano handle
+ * @param prompt string
+ * @param station list sort order
+ * @param input fds
* @return pointer to selected station or NULL
*/
PianoStation_t *BarUiSelectStation (PianoHandle_t *ph, const char *prompt,
- BarStationSorting_t order, FILE *curFd) {
+ BarStationSorting_t order, BarReadlineFds_t *input) {
PianoStation_t **sortedStations = NULL, *retStation = NULL;
size_t stationCount, i;
- int input;
+ int selected;
if (ph->stations == NULL) {
BarUiMsg (MSG_ERR, "No station available.\n");
@@ -323,12 +326,12 @@ PianoStation_t *BarUiSelectStation (PianoHandle_t *ph, const char *prompt,
BarUiMsg (MSG_QUESTION, prompt);
/* FIXME: using a _signed_ int is ugly */
- if (BarReadlineInt (&input, curFd) == 0) {
+ if (BarReadlineInt (&selected, input) == 0) {
free (sortedStations);
return NULL;
}
- if (input < stationCount) {
- retStation = sortedStations[input];
+ if (selected < stationCount) {
+ retStation = sortedStations[selected];
}
free (sortedStations);
return retStation;
@@ -337,18 +340,18 @@ PianoStation_t *BarUiSelectStation (PianoHandle_t *ph, const char *prompt,
/* let user pick one song
* @param pianobar settings
* @param song list
- * @param current fd
+ * @param input fds
* @return pointer to selected item in song list or NULL
*/
PianoSong_t *BarUiSelectSong (const BarSettings_t *settings,
- PianoSong_t *startSong, FILE *curFd) {
+ PianoSong_t *startSong, BarReadlineFds_t *input) {
PianoSong_t *tmpSong = NULL;
int i = 0;
i = BarUiListSongs (settings, startSong);
BarUiMsg (MSG_QUESTION, "Select song: ");
- if (BarReadlineInt (&i, curFd) == 0) {
+ if (BarReadlineInt (&i, input) == 0) {
return NULL;
}
@@ -363,9 +366,11 @@ PianoSong_t *BarUiSelectSong (const BarSettings_t *settings,
/* let user pick one artist
* @param artists (linked list)
+ * @param input fds
* @return pointer to selected artist or NULL on abort
*/
-PianoArtist_t *BarUiSelectArtist (PianoArtist_t *startArtist, FILE *curFd) {
+PianoArtist_t *BarUiSelectArtist (PianoArtist_t *startArtist,
+ BarReadlineFds_t *input) {
PianoArtist_t *tmpArtist = NULL;
int i = 0;
@@ -377,7 +382,7 @@ PianoArtist_t *BarUiSelectArtist (PianoArtist_t *startArtist, FILE *curFd) {
tmpArtist = tmpArtist->next;
}
BarUiMsg (MSG_QUESTION, "Select artist: ");
- if (BarReadlineInt (&i, curFd) == 0) {
+ if (BarReadlineInt (&i, input) == 0) {
return NULL;
}
tmpArtist = startArtist;
@@ -389,12 +394,11 @@ PianoArtist_t *BarUiSelectArtist (PianoArtist_t *startArtist, FILE *curFd) {
}
/* search music: query, search request, return music id
- * @param piano handle
- * @param read data from fd
+ * @param app handle
* @param allow seed suggestions if != NULL
* @return musicId or NULL on abort/error
*/
-char *BarUiSelectMusicId (BarApp_t *app, FILE *curFd, char *similarToId) {
+char *BarUiSelectMusicId (BarApp_t *app, char *similarToId) {
char *musicId = NULL;
char lineBuf[100], selectBuf[2];
PianoSearchResult_t searchResult;
@@ -402,7 +406,8 @@ char *BarUiSelectMusicId (BarApp_t *app, FILE *curFd, char *similarToId) {
PianoSong_t *tmpSong;
BarUiMsg (MSG_QUESTION, "Search for artist/title: ");
- if (BarReadlineStr (lineBuf, sizeof (lineBuf), 0, curFd) > 0) {
+ if (BarReadlineStr (lineBuf, sizeof (lineBuf), &app->input,
+ BAR_RL_DEFAULT) > 0) {
if (strcmp ("?", lineBuf) == 0 && similarToId != NULL) {
PianoReturn_t pRet;
WaitressReturn_t wRet;
@@ -436,15 +441,17 @@ char *BarUiSelectMusicId (BarApp_t *app, FILE *curFd, char *similarToId) {
searchResult.artists != NULL) {
/* songs and artists found */
BarUiMsg (MSG_QUESTION, "Is this an [a]rtist or [t]rack name? ");
- BarReadline (selectBuf, sizeof (selectBuf), "at", 1, 0, curFd);
+ BarReadline (selectBuf, sizeof (selectBuf), "at", &app->input,
+ BAR_RL_FULLRETURN, -1);
if (*selectBuf == 'a') {
- tmpArtist = BarUiSelectArtist (searchResult.artists, curFd);
+ tmpArtist = BarUiSelectArtist (searchResult.artists,
+ &app->input);
if (tmpArtist != NULL) {
musicId = strdup (tmpArtist->musicId);
}
} else if (*selectBuf == 't') {
tmpSong = BarUiSelectSong (&app->settings, searchResult.songs,
- curFd);
+ &app->input);
if (tmpSong != NULL) {
musicId = strdup (tmpSong->musicId);
}
@@ -452,13 +459,13 @@ char *BarUiSelectMusicId (BarApp_t *app, FILE *curFd, char *similarToId) {
} else if (searchResult.songs != NULL) {
/* songs found */
tmpSong = BarUiSelectSong (&app->settings, searchResult.songs,
- curFd);
+ &app->input);
if (tmpSong != NULL) {
musicId = strdup (tmpSong->musicId);
}
} else if (searchResult.artists != NULL) {
/* artists found */
- tmpArtist = BarUiSelectArtist (searchResult.artists, curFd);
+ tmpArtist = BarUiSelectArtist (searchResult.artists, &app->input);
if (tmpArtist != NULL) {
musicId = strdup (tmpArtist->musicId);
}
@@ -472,9 +479,9 @@ char *BarUiSelectMusicId (BarApp_t *app, FILE *curFd, char *similarToId) {
}
/* browse genre stations and create shared station
- * @param piano handle
+ * @param app handle
*/
-void BarStationFromGenre (BarApp_t *app, FILE *curFd) {
+void BarStationFromGenre (BarApp_t *app) {
PianoReturn_t pRet;
WaitressReturn_t wRet;
PianoGenreCategory_t *curCat;
@@ -504,7 +511,7 @@ void BarStationFromGenre (BarApp_t *app, FILE *curFd) {
}
/* select category or exit */
BarUiMsg (MSG_QUESTION, "Select category: ");
- if (BarReadlineInt (&i, curFd) == 0) {
+ if (BarReadlineInt (&i, &app->input) == 0) {
return;
}
curCat = app->ph.genreStations;
@@ -522,7 +529,7 @@ void BarStationFromGenre (BarApp_t *app, FILE *curFd) {
curGenre = curGenre->next;
}
BarUiMsg (MSG_QUESTION, "Select genre: ");
- if (BarReadlineInt (&i, curFd) == 0) {
+ if (BarReadlineInt (&i, &app->input) == 0) {
return;
}
curGenre = curCat->genres;
diff --git a/src/ui.h b/src/ui.h
index 6664f8e..4d4b555 100644
--- a/src/ui.h
+++ b/src/ui.h
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2008-2010
+Copyright (c) 2008-2011
Lars-Dominik Braun <lars@6xq.net>
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -30,6 +30,7 @@ THE SOFTWARE.
#include "settings.h"
#include "player.h"
#include "main.h"
+#include "ui_readline.h"
typedef enum {MSG_NONE, MSG_INFO, MSG_PLAYING, MSG_TIME, MSG_ERR,
MSG_QUESTION, MSG_LIST} uiMsg_t;
@@ -37,11 +38,12 @@ typedef enum {MSG_NONE, MSG_INFO, MSG_PLAYING, MSG_TIME, MSG_ERR,
void BarUiMsg (uiMsg_t type, const char *format, ...);
PianoReturn_t BarUiPrintPianoStatus (PianoReturn_t ret);
PianoStation_t *BarUiSelectStation (PianoHandle_t *, const char *,
- BarStationSorting_t, FILE *);
-PianoSong_t *BarUiSelectSong (const BarSettings_t *, PianoSong_t *, FILE *);
-PianoArtist_t *BarUiSelectArtist (PianoArtist_t *startArtist, FILE *curFd);
-char *BarUiSelectMusicId (BarApp_t *, FILE *, char *);
-void BarStationFromGenre (BarApp_t *, FILE *);
+ BarStationSorting_t, BarReadlineFds_t *);
+PianoSong_t *BarUiSelectSong (const BarSettings_t *, PianoSong_t *,
+ BarReadlineFds_t *);
+PianoArtist_t *BarUiSelectArtist (PianoArtist_t *, BarReadlineFds_t *);
+char *BarUiSelectMusicId (BarApp_t *, char *);
+void BarStationFromGenre (BarApp_t *);
void BarUiPrintStation (PianoStation_t *);
void BarUiPrintSong (const BarSettings_t *, const PianoSong_t *,
const PianoStation_t *);
diff --git a/src/ui_act.c b/src/ui_act.c
index dac104a..f8c9879 100644
--- a/src/ui_act.c
+++ b/src/ui_act.c
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2008-2010
+Copyright (c) 2008-2011
Lars-Dominik Braun <lars@6xq.net>
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -126,7 +126,7 @@ BarUiActCallback(BarUiActAddMusic) {
RETURN_IF_NO_STATION;
- reqData.musicId = BarUiSelectMusicId (app, curFd, app->playlist->musicId);
+ reqData.musicId = BarUiSelectMusicId (app, app->playlist->musicId);
if (reqData.musicId != NULL) {
if (!BarTransformIfShared (app, app->curStation)) {
return;
@@ -172,7 +172,7 @@ BarUiActCallback(BarUiActCreateStation) {
WaitressReturn_t wRet;
PianoRequestDataCreateStation_t reqData;
- reqData.id = BarUiSelectMusicId (app, curFd, NULL);
+ reqData.id = BarUiSelectMusicId (app, NULL);
if (reqData.id != NULL) {
reqData.type = "mi";
BarUiMsg (MSG_INFO, "Creating station... ");
@@ -191,8 +191,8 @@ BarUiActCallback(BarUiActAddSharedStation) {
char stationId[50];
BarUiMsg (MSG_QUESTION, "Station id: ");
- if (BarReadline (stationId, sizeof (stationId), "0123456789", 0, 0,
- curFd) > 0) {
+ if (BarReadline (stationId, sizeof (stationId), "0123456789", &app->input,
+ BAR_RL_DEFAULT, -1) > 0) {
reqData.id = stationId;
reqData.type = "sh";
BarUiMsg (MSG_INFO, "Adding shared station... ");
@@ -211,7 +211,7 @@ BarUiActCallback(BarUiActDeleteStation) {
BarUiMsg (MSG_QUESTION, "Really delete \"%s\"? [yN] ",
app->curStation->name);
- if (BarReadlineYesNo (0, curFd)) {
+ if (BarReadlineYesNo (false, &app->input)) {
BarUiMsg (MSG_INFO, "Deleting station... ");
if (BarUiActDefaultPianoCall (PIANO_REQUEST_DELETE_STATION,
app->curStation)) {
@@ -247,7 +247,7 @@ BarUiActCallback(BarUiActExplain) {
*/
BarUiActCallback(BarUiActStationFromGenre) {
/* use genre station */
- BarStationFromGenre (app, curFd);
+ BarStationFromGenre (app);
}
/* print verbose song information
@@ -333,7 +333,7 @@ BarUiActCallback(BarUiActMoveSong) {
RETURN_IF_NO_SONG;
reqData.to = BarUiSelectStation (&app->ph, "Move song to station: ",
- app->settings.sortOrder, curFd);
+ app->settings.sortOrder, &app->input);
if (reqData.to != NULL) {
/* find original station (just is case we're playing a quickmix
* station) */
@@ -376,7 +376,7 @@ BarUiActCallback(BarUiActRenameStation) {
RETURN_IF_NO_STATION;
BarUiMsg (MSG_QUESTION, "New name: ");
- if (BarReadlineStr (lineBuf, sizeof (lineBuf), 0, curFd) > 0) {
+ if (BarReadlineStr (lineBuf, sizeof (lineBuf), &app->input, BAR_RL_DEFAULT) > 0) {
PianoRequestDataRenameStation_t reqData;
if (!BarTransformIfShared (app, app->curStation)) {
return;
@@ -395,7 +395,7 @@ BarUiActCallback(BarUiActRenameStation) {
*/
BarUiActCallback(BarUiActSelectStation) {
PianoStation_t *newStation = BarUiSelectStation (&app->ph, "Select station: ",
- app->settings.sortOrder, curFd);
+ app->settings.sortOrder, &app->input);
if (newStation != NULL) {
app->curStation = newStation;
BarUiPrintStation (app->curStation);
@@ -446,7 +446,7 @@ BarUiActCallback(BarUiActSelectQuickMix) {
PianoStation_t *selStation;
while ((selStation = BarUiSelectStation (&app->ph,
"Toggle quickmix for station: ", app->settings.sortOrder,
- curFd)) != NULL) {
+ &app->input)) != NULL) {
selStation->useQuickMix = !selStation->useQuickMix;
}
BarUiMsg (MSG_INFO, "Setting quickmix stations... ");
@@ -474,7 +474,7 @@ BarUiActCallback(BarUiActHistory) {
if (app->songHistory != NULL) {
selectedSong = BarUiSelectSong (&app->settings, app->songHistory,
- curFd);
+ &app->input);
if (selectedSong != NULL) {
/* use user-defined keybindings */
allowedBuf[0] = app->settings.keys[BAR_KS_LOVE];
@@ -487,7 +487,8 @@ BarUiActCallback(BarUiActHistory) {
app->settings.keys[BAR_KS_LOVE],
app->settings.keys[BAR_KS_BAN],
app->settings.keys[BAR_KS_TIRED]);
- BarReadline (selectBuf, sizeof (selectBuf), allowedBuf, 1, 0, curFd);
+ BarReadline (selectBuf, sizeof (selectBuf), allowedBuf,
+ &app->input, BAR_RL_FULLRETURN, -1);
if (selectBuf[0] == app->settings.keys[BAR_KS_LOVE] ||
selectBuf[0] == app->settings.keys[BAR_KS_BAN] ||
@@ -557,7 +558,8 @@ BarUiActCallback(BarUiActBookmark) {
RETURN_IF_NO_SONG;
BarUiMsg (MSG_QUESTION, "Bookmark [s]ong or [a]rtist? ");
- BarReadline (selectBuf, sizeof (selectBuf), "sa", 1, 0, curFd);
+ BarReadline (selectBuf, sizeof (selectBuf), "sa", &app->input,
+ BAR_RL_FULLRETURN, -1);
if (selectBuf[0] == 's') {
BarUiMsg (MSG_INFO, "Bookmarking song... ");
BarUiActDefaultPianoCall (PIANO_REQUEST_BOOKMARK_SONG, app->playlist);
diff --git a/src/ui_act.h b/src/ui_act.h
index d4e6948..b1dce62 100644
--- a/src/ui_act.h
+++ b/src/ui_act.h
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2008-2010
+Copyright (c) 2008-2011
Lars-Dominik Braun <lars@6xq.net>
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -26,7 +26,7 @@ THE SOFTWARE.
#include "main.h"
-#define BarUiActCallback(name) void name (BarApp_t *app, FILE *curFd)
+#define BarUiActCallback(name) void name (BarApp_t *app)
BarUiActCallback(BarUiActHelp);
BarUiActCallback(BarUiActAddMusic);
diff --git a/src/ui_readline.c b/src/ui_readline.c
index 98af5ea..8e6ecb4 100644
--- a/src/ui_readline.c
+++ b/src/ui_readline.c
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2008-2010
+Copyright (c) 2008-2011
Lars-Dominik Braun <lars@6xq.net>
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -24,6 +24,10 @@ THE SOFTWARE.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include "ui_readline.h"
static inline void BarReadlineMoveLeft (char *buf, size_t *bufPos,
size_t *bufLen) {
@@ -52,33 +56,73 @@ static inline char BarReadlineIsUtf8Content (char b) {
* @param buffer
* @param buffer size
* @param accept these characters
- * @param return if buffer full (otherwise more characters are not accepted)
- * @param don't echo anything (for passwords)
- * @param read from this fd
+ * @param input fds
+ * @param flags
+ * @param timeout (seconds) or -1 (no timeout)
* @return number of bytes read from stdin
*/
-size_t BarReadline (char *buf, size_t bufSize, const char *mask,
- char fullReturn, char noEcho, FILE *fd) {
- int chr = 0;
+size_t BarReadline (char *buf, const size_t bufSize, const char *mask,
+ BarReadlineFds_t *input, const BarReadlineFlags_t flags, int timeout) {
size_t bufPos = 0;
size_t bufLen = 0;
unsigned char escapeState = 0;
+ fd_set set;
+ const bool echo = !(flags & BAR_RL_NOECHO);
+
+ assert (buf != NULL);
+ assert (bufSize > 0);
+ assert (input != NULL);
memset (buf, 0, bufSize);
/* if fd is a fifo fgetc will always return EOF if nobody writes to
* it, stdin will block */
- while ((chr = fgetc (fd)) != EOF) {
+ while (1) {
+ int curFd = -1;
+ char chr;
+ struct timeval timeoutstruct;
+
+ /* select modifies set and timeout */
+ memcpy (&set, &input->set, sizeof (set));
+ timeoutstruct.tv_sec = timeout;
+ timeoutstruct.tv_usec = 0;
+
+ if (select (input->maxfd, &set, NULL, NULL,
+ (timeout == -1) ? NULL : &timeoutstruct) <= 0) {
+ /* fail or timeout */
+ break;
+ }
+
+ assert (sizeof (input->fds) / sizeof (*input->fds) == 2);
+ if (FD_ISSET(input->fds[0], &set)) {
+ curFd = input->fds[0];
+ } else if (input->fds[1] != -1 && FD_ISSET(input->fds[1], &set)) {
+ curFd = input->fds[1];
+ }
+ if (read (curFd, &chr, sizeof (chr)) <= 0) {
+ /* select() is going wild if fdset contains EOFed stdin, only check
+ * for stdin, fifo is "reopened" as soon as another writer is
+ * available
+ * FIXME: ugly */
+ if (curFd == STDIN_FILENO) {
+ FD_CLR (curFd, &input->set);
+ }
+ continue;
+ }
switch (chr) {
/* EOT */
case 4:
- printf ("\n");
+ if (echo) {
+ fputs ("\n", stdout);
+ }
return bufLen;
break;
/* return */
case 10:
- printf ("\n");
+ if (echo) {
+ fputs ("\n", stdout);
+ }
return bufLen;
break;
@@ -109,15 +153,15 @@ size_t BarReadline (char *buf, size_t bufSize, const char *mask,
}
}
/* move caret back and delete last character */
- if (!noEcho) {
- printf ("\033[D\033[K");
+ if (echo) {
+ fputs ("\033[D\033[K", stdout);
fflush (stdout);
}
} else if (bufPos == 0 && buf[bufPos] != '\0') {
/* delete char at position 0 but don't move cursor any further */
buf[bufPos] = '\0';
- if (!noEcho) {
- printf ("\033[K");
+ if (echo) {
+ fputs ("\033[K", stdout);
fflush (stdout);
}
}
@@ -145,18 +189,21 @@ size_t BarReadline (char *buf, size_t bufSize, const char *mask,
buf[bufPos] = chr;
++bufPos;
++bufLen;
- if (!noEcho) {
- fputc (chr, stdout);
+ if (echo) {
+ putchar (chr);
+ fflush (stdout);
}
/* buffer full => return if requested */
- if (fullReturn && bufPos >= bufSize-1) {
- printf ("\n");
+ if (bufPos >= bufSize-1 && (flags & BAR_RL_FULLRETURN)) {
+ if (echo) {
+ fputs ("\n", stdout);
+ }
return bufLen;
}
}
break;
- }
- }
+ } /* end switch */
+ } /* end while */
return 0;
}
@@ -165,35 +212,36 @@ size_t BarReadline (char *buf, size_t bufSize, const char *mask,
* @param buffer size
* @return number of bytes read from stdin
*/
-size_t BarReadlineStr (char *buf, size_t bufSize, char noEcho,
- FILE *fd) {
- return BarReadline (buf, bufSize, NULL, 0, noEcho, fd);
+size_t BarReadlineStr (char *buf, const size_t bufSize,
+ BarReadlineFds_t *input, const BarReadlineFlags_t flags) {
+ return BarReadline (buf, bufSize, NULL, input, flags, -1);
}
/* Read int from stdin
* @param write result into this variable
* @return number of bytes read from stdin
*/
-size_t BarReadlineInt (int *ret, FILE *fd) {
+size_t BarReadlineInt (int *ret, BarReadlineFds_t *input) {
int rlRet = 0;
char buf[16];
- rlRet = BarReadline (buf, sizeof (buf), "0123456789", 0, 0, fd);
+ rlRet = BarReadline (buf, sizeof (buf), "0123456789", input,
+ BAR_RL_DEFAULT, -1);
*ret = atoi ((char *) buf);
return rlRet;
}
/* Yes/No?
- * @param defaul (user presses enter)
+ * @param default (user presses enter)
*/
-int BarReadlineYesNo (char def, FILE *fd) {
+bool BarReadlineYesNo (bool def, BarReadlineFds_t *input) {
char buf[2];
- BarReadline (buf, sizeof (buf), "yYnN", 1, 0, fd);
- if (*buf == 'y' || *buf == 'Y' || (def == 1 && *buf == '\0')) {
- return 1;
+ BarReadline (buf, sizeof (buf), "yYnN", input, BAR_RL_FULLRETURN, -1);
+ if (*buf == 'y' || *buf == 'Y' || (def == true && *buf == '\0')) {
+ return true;
} else {
- return 0;
+ return false;
}
}
diff --git a/src/ui_readline.h b/src/ui_readline.h
index 96356b7..55411fe 100644
--- a/src/ui_readline.h
+++ b/src/ui_readline.h
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2008-2010
+Copyright (c) 2008-2011
Lars-Dominik Braun <lars@6xq.net>
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -21,8 +21,30 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
-size_t BarReadline (char *, size_t, const char *, char, char, FILE *);
-size_t BarReadlineStr (char *, size_t, char, FILE *);
-size_t BarReadlineInt (int *, FILE *);
-int BarReadlineYesNo (char def, FILE *);
+#ifndef _UI_READLINE_H
+#define _UI_READLINE_H
+
+#include <stdbool.h>
+#include <sys/select.h>
+
+typedef enum {
+ BAR_RL_DEFAULT = 0,
+ BAR_RL_FULLRETURN = 1, /* return if buffer is full */
+ BAR_RL_NOECHO = 2, /* don't echo to stdout */
+} BarReadlineFlags_t;
+
+typedef struct {
+ fd_set set;
+ int maxfd;
+ int fds[2];
+} BarReadlineFds_t;
+
+size_t BarReadline (char *, const size_t, const char *,
+ BarReadlineFds_t *, const BarReadlineFlags_t, int);
+size_t BarReadlineStr (char *, const size_t,
+ BarReadlineFds_t *, const BarReadlineFlags_t);
+size_t BarReadlineInt (int *, BarReadlineFds_t *);
+bool BarReadlineYesNo (bool, BarReadlineFds_t *);
+
+#endif /* _UI_READLINE_H */