diff options
| -rw-r--r-- | COPYING | 2 | ||||
| -rw-r--r-- | src/main.c | 83 | ||||
| -rw-r--r-- | src/main.h | 10 | ||||
| -rw-r--r-- | src/ui.c | 55 | ||||
| -rw-r--r-- | src/ui.h | 14 | ||||
| -rw-r--r-- | src/ui_act.c | 30 | ||||
| -rw-r--r-- | src/ui_act.h | 4 | ||||
| -rw-r--r-- | src/ui_readline.c | 110 | ||||
| -rw-r--r-- | src/ui_readline.h | 32 | 
9 files changed, 197 insertions, 143 deletions
| @@ -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 @@ -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); @@ -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 */ @@ -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; @@ -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 */ | 
