diff options
| author | Lars-Dominik Braun <PromyLOPh@lavabit.com> | 2009-04-10 14:32:16 +0200 | 
|---|---|---|
| committer | Lars-Dominik Braun <PromyLOPh@lavabit.com> | 2009-04-10 14:32:16 +0200 | 
| commit | 71d9447316133c8e447ca7538d9533e1ef61e0eb (patch) | |
| tree | 2c59aca8ad2f671f458065eb8e7554a3cd9a64ed /src | |
| parent | dc7fe1e2405c49338e5dca5f559f17e8c5977b98 (diff) | |
| download | pianobar-71d9447316133c8e447ca7538d9533e1ef61e0eb.tar.gz pianobar-71d9447316133c8e447ca7538d9533e1ef61e0eb.tar.bz2 pianobar-71d9447316133c8e447ca7538d9533e1ef61e0eb.zip | |
Goodbye readline
"It's too big and too slow." -- man readline
Diffstat (limited to 'src')
| -rw-r--r-- | src/CMakeLists.txt | 10 | ||||
| -rw-r--r-- | src/FindReadline.cmake | 37 | ||||
| -rw-r--r-- | src/main.c | 14 | ||||
| -rw-r--r-- | src/ui.c | 69 | ||||
| -rw-r--r-- | src/ui_act.c | 30 | ||||
| -rw-r--r-- | src/ui_readline.c | 195 | ||||
| -rw-r--r-- | src/ui_readline.h | 28 | 
7 files changed, 263 insertions, 120 deletions
| diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f871b7b..5fb020c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,7 +8,6 @@ option (USE_MAD "Use libmad for mp3 decoding (if available)" on)  find_package (LibXml2 REQUIRED)  find_package (CURL REQUIRED) -find_package (Readline REQUIRED)  find_package (LibAo REQUIRED)  # find threading implementation @@ -57,12 +56,13 @@ include_directories (  	${pianobar_SOURCE_DIR}/libpiano/src  	${pianobar_SOURCE_DIR}/libwardrobe/src  	${LIBXML2_INCLUDE_DIR} -	${CURL_INCLUDE_DIRS} ${READLINE_INCLUDE_DIR} ${FAAD_INCLUDE_DIRS} -	${LIBAO_INCLUDE_DIRS} ${MAD_INCLUDE_DIRS}) +	${CURL_INCLUDE_DIRS} ${FAAD_INCLUDE_DIRS} ${LIBAO_INCLUDE_DIRS} +	${MAD_INCLUDE_DIRS}) -add_executable (pianobar main.c terminal.c settings.c player.c ui.c ui_act.c) +add_executable (pianobar main.c terminal.c settings.c player.c ui.c ui_act.c +	ui_readline.c)  target_link_libraries (pianobar piano wardrobe ${CURL_LIBRARIES} -	${LIBXML2_LIBRARIES} ${READLINE_LIBRARY} ${FAAD_LIBRARY} ${LIBAO_LIBRARY} +	${LIBXML2_LIBRARIES} ${FAAD_LIBRARY} ${LIBAO_LIBRARY}  	${CMAKE_THREAD_LIBS_INIT} ${MAD_LIBRARIES} ${LIBM})  install (TARGETS pianobar RUNTIME DESTINATION bin) diff --git a/src/FindReadline.cmake b/src/FindReadline.cmake deleted file mode 100644 index 67ea232..0000000 --- a/src/FindReadline.cmake +++ /dev/null @@ -1,37 +0,0 @@ -# - Find readline -# -#  READLINE_INCLUDE_DIRS - where to find curl/curl.h, etc. -#  READLINE_LIBRARIES    - List of libraries when using curl. -#  READLINE_FOUND        - True if curl found. - -# Look for the header file. -FIND_PATH(READLINE_INCLUDE_DIR NAMES readline/readline.h) -MARK_AS_ADVANCED(READLINE_INCLUDE_DIR) - -# Look for the library. -FIND_LIBRARY(READLINE_LIBRARY NAMES readline) -MARK_AS_ADVANCED(READLINE_LIBRARY) - -# Copy the results to the output variables. -IF(READLINE_INCLUDE_DIR AND READLINE_LIBRARY) -  SET(READLINE_FOUND 1) -  SET(READLINE_LIBRARIES ${READLINE_LIBRARY}) -  SET(READLINE_INCLUDE_DIRS ${READLINE_INCLUDE_DIR}) -ELSE(READLINE_INCLUDE_DIR AND READLINE_LIBRARY) -  SET(READLINE_FOUND 0) -  SET(READLINE_LIBRARIES) -  SET(READLINE_INCLUDE_DIRS) -ENDIF(READLINE_INCLUDE_DIR AND READLINE_LIBRARY) - -# Report the results. -IF(NOT READLINE_FOUND) -  SET(READLINE_DIR_MESSAGE -    "READLINE was not found. Make sure READLINE_LIBRARY and READLINE_INCLUDE_DIR are set.") -  IF(NOT READLINE_FIND_QUIETLY) -    MESSAGE(STATUS "${READLINE_DIR_MESSAGE}") -  ELSE(NOT READLINE_FIND_QUIETLY) -    IF(READLINE_FIND_REQUIRED) -      MESSAGE(FATAL_ERROR "${READLINE_DIR_MESSAGE}") -    ENDIF(READLINE_FIND_REQUIRED) -  ENDIF(NOT READLINE_FIND_QUIETLY) -ENDIF(NOT READLINE_FOUND) @@ -44,8 +44,6 @@ THE SOFTWARE.  #include <pthread.h> -#include <readline/readline.h> -  /* pandora.com library */  #include <piano.h> @@ -55,6 +53,7 @@ THE SOFTWARE.  #include "terminal.h"  #include "config.h"  #include "ui.h" +#include "ui_readline.h"  int main (int argc, char **argv) {  	/* handles */ @@ -79,6 +78,7 @@ int main (int argc, char **argv) {  	BarUiMsg (MSG_NONE, "Welcome to " PACKAGE "!\n");  	/* init some things */ +	BarTermSetEcho (0);  	curl_global_init (CURL_GLOBAL_SSL);  	xmlInitParser ();  	ao_initialize (); @@ -101,14 +101,16 @@ int main (int argc, char **argv) {  	}  	if (settings.username == NULL) { +		char nameBuf[100];  		BarUiMsg (MSG_QUESTION, "Username: "); -		settings.username = readline (NULL); +		BarReadlineStr (nameBuf, sizeof (nameBuf), 0); +		settings.username = strdup (nameBuf);  	}  	if (settings.password == NULL) { -		BarTermSetEcho (0); +		char passBuf[100];  		BarUiMsg (MSG_QUESTION, "Password: "); -		settings.password = readline (NULL); -		BarTermSetEcho (1); +		BarReadlineStr (passBuf, sizeof (passBuf), 1); +		settings.password = strdup (passBuf);  		BarUiMsg (MSG_NONE, "\n");  	} @@ -36,6 +36,7 @@ THE SOFTWARE.  #include <sys/wait.h>  #include "ui.h" +#include "ui_readline.h"  /*	output message and flush stdout   *	@param message @@ -90,41 +91,6 @@ inline PianoReturn_t BarUiPrintPianoStatus (PianoReturn_t ret) {  	return ret;  } -/*	check if all characters of string are numeric - *	@param the string - *	@return 1 = yes, 0 = not numeric - */ -char BarIsNumericStr (const char *str) { -	while (*str != '\0') { -		if (isdigit (*str) == 0) { -			return 0; -		} -		str++; -	} -	return 1; -} - -/*	use readline to get integer value - *	@param prompt or NULL - *	@param returns integer - *	@return 1 = success, 0 = failure (not an integer, ...) - */ -char BarReadlineInt (const char *prompt, int *retVal) { -	char *buf; -	char ret = 0; - -	BarUiMsg (MSG_QUESTION, prompt); -	if ((buf = readline (NULL)) != NULL && strlen (buf) > 0 && -			BarIsNumericStr (buf)) { -		*retVal = atoi (buf); -		ret = 1; -	} -	if (buf != NULL) { -		free (buf); -	} -	return ret; -} -  /*	sort linked list (station)   *	@param stations   *	@return NULL-terminated array with sorted stations @@ -200,7 +166,8 @@ PianoStation_t *BarUiSelectStation (PianoHandle_t *ph, const char *prompt) {  		i++;  	} -	if (!BarReadlineInt (prompt, &i)) { +	BarUiMsg (MSG_QUESTION, prompt); +	if (BarReadlineInt (&i) == 0) {  		free (ss);  		return NULL;  	} @@ -230,7 +197,8 @@ PianoSong_t *BarUiSelectSong (PianoSong_t *startSong) {  		i++;  		tmpSong = tmpSong->next;  	} -	if (!BarReadlineInt ("Select song: ", &i)) { +	BarUiMsg (MSG_QUESTION, "Select song: "); +	if (BarReadlineInt (&i) == 0) {  		return NULL;  	}  	tmpSong = startSong; @@ -256,7 +224,8 @@ PianoArtist_t *BarUiSelectArtist (PianoArtist_t *startArtist) {  		i++;  		tmpArtist = tmpArtist->next;  	} -	if (!BarReadlineInt ("Select artist: ", &i)) { +	BarUiMsg (MSG_QUESTION, "Select artist: "); +	if (BarReadlineInt (&i) == 0) {  		return NULL;  	}  	tmpArtist = startArtist; @@ -272,19 +241,17 @@ PianoArtist_t *BarUiSelectArtist (PianoArtist_t *startArtist) {   *	@return musicId or NULL on abort/error   */  char *BarUiSelectMusicId (const PianoHandle_t *ph) { -	char *musicId = NULL, *lineBuf; -	char yesnoBuf; +	char *musicId = NULL; +	char lineBuf[100], selectBuf[2];  	PianoSearchResult_t searchResult;  	PianoArtist_t *tmpArtist;  	PianoSong_t *tmpSong;  	BarUiMsg (MSG_QUESTION, "Search for artist/title: "); -	lineBuf = readline (NULL); -	if (lineBuf != NULL && strlen (lineBuf) > 0) { +	if (BarReadlineStr (lineBuf, sizeof (lineBuf), 0) > 0) {  		BarUiMsg (MSG_INFO, "Searching... ");  		if (BarUiPrintPianoStatus (PianoSearchMusic (ph, lineBuf,  				&searchResult)) != PIANO_RET_OK) { -			free (lineBuf);  			return NULL;  		}  		BarUiMsg (MSG_NONE, "\r"); @@ -292,14 +259,13 @@ char *BarUiSelectMusicId (const PianoHandle_t *ph) {  			/* songs and artists found */  			BarUiMsg (MSG_QUESTION, "Is this an [a]rtist or [t]rack name? "  					"Press c to abort. "); -			read (fileno (stdin), &yesnoBuf, sizeof (yesnoBuf)); -			BarUiMsg (MSG_NONE, "\n"); -			if (yesnoBuf == 'a') { +			BarReadline (selectBuf, sizeof (selectBuf), "atc", 1, 0); +			if (*selectBuf == 'a') {  				tmpArtist = BarUiSelectArtist (searchResult.artists);  				if (tmpArtist != NULL) {  					musicId = strdup (tmpArtist->musicId);  				} -			} else if (yesnoBuf == 't') { +			} else if (*selectBuf == 't') {  				tmpSong = BarUiSelectSong (searchResult.songs);  				if (tmpSong != NULL) {  					musicId = strdup (tmpSong->musicId); @@ -322,9 +288,6 @@ char *BarUiSelectMusicId (const PianoHandle_t *ph) {  		}  		PianoDestroySearchResult (&searchResult);  	} -	if (lineBuf != NULL) { -		free (lineBuf); -	}  	return musicId;  } @@ -355,7 +318,8 @@ void BarStationFromGenre (PianoHandle_t *ph) {  		curCat = curCat->next;  	}  	/* select category or exit */ -	if (!BarReadlineInt ("Select category: ", &i)) { +	BarUiMsg (MSG_QUESTION, "Select category: "); +	if (BarReadlineInt (&i) == 0) {  		return;  	}  	curCat = ph->genreStations; @@ -372,7 +336,8 @@ void BarStationFromGenre (PianoHandle_t *ph) {  		i++;  		curStation = curStation->next;  	} -	if (!BarReadlineInt ("Select genre: ", &i)) { +	BarUiMsg (MSG_QUESTION, "Select genre: "); +	if (BarReadlineInt (&i) == 0) {  		return;  	}  	curStation = curCat->stations; diff --git a/src/ui_act.c b/src/ui_act.c index 2a2e041..951116e 100644 --- a/src/ui_act.c +++ b/src/ui_act.c @@ -26,12 +26,10 @@ THE SOFTWARE.  #include <string.h>  #include <unistd.h>  #include <pthread.h> -/* needed by readline */ -#include <stdio.h> -#include <readline/readline.h>  #include "ui.h"  #include "ui_act.h" +#include "ui_readline.h"  #define RETURN_IF_NO_STATION if (*curStation == NULL) { \  		BarUiMsg (MSG_ERR, "No station selected.\n"); \ @@ -130,29 +128,24 @@ void BarUiActCreateStation (BAR_KS_ARGS) {  /*	add shared station by id   */  void BarUiActAddSharedStation (BAR_KS_ARGS) { -	char *stationId = NULL; +	char stationId[50];  	BarUiMsg (MSG_QUESTION, "Station id: "); -	if ((stationId = readline (NULL)) != NULL && -			strlen (stationId) > 0) { +	if (BarReadline (stationId, sizeof (stationId), "0123456789", 0, 0) > 0) {  		BarUiMsg (MSG_INFO, "Adding shared station... "); -		BarUiPrintPianoStatus (PianoCreateStation (ph, "sh", stationId)); -		free (stationId); +		BarUiPrintPianoStatus (PianoCreateStation (ph, "sh", +				(char *) stationId));  	}  }  /*	delete current station   */  void BarUiActDeleteStation (BAR_KS_ARGS) { -	char yesNoBuf; -  	RETURN_IF_NO_STATION;  	BarUiMsg (MSG_QUESTION, "Really delete \"%s\"? [yN] ",  			(*curStation)->name); -	read (fileno (stdin), &yesNoBuf, sizeof (yesNoBuf)); -	BarUiMsg (MSG_NONE, "\n"); -	if (yesNoBuf == 'y') { +	if (BarReadlineYesNo (0)) {  		BarUiMsg (MSG_INFO, "Deleting station... ");  		if (BarUiPrintPianoStatus (PianoDeleteStation (ph,  				*curStation)) == PIANO_RET_OK) { @@ -280,21 +273,18 @@ void BarUiActPause (BAR_KS_ARGS) {  /*	rename current station   */  void BarUiActRenameStation (BAR_KS_ARGS) { -	char *lineBuf; +	char lineBuf[100];  	RETURN_IF_NO_STATION;  	BarUiMsg (MSG_QUESTION, "New name: "); -	lineBuf = readline (NULL); -	if (lineBuf != NULL && strlen (lineBuf) > 0) { +	if (BarReadlineStr (lineBuf, sizeof (lineBuf), 0) > 0) {  		if (!BarTransformIfShared (ph, *curStation)) {  			return;  		}  		BarUiMsg (MSG_INFO, "Renaming station... "); -		BarUiPrintPianoStatus (PianoRenameStation (ph, *curStation, lineBuf)); -	} -	if (lineBuf != NULL) { -		free (lineBuf); +		BarUiPrintPianoStatus (PianoRenameStation (ph, *curStation, +				(char *) lineBuf));  	}  } diff --git a/src/ui_readline.c b/src/ui_readline.c new file mode 100644 index 0000000..fd4eb29 --- /dev/null +++ b/src/ui_readline.c @@ -0,0 +1,195 @@ +/* +Copyright (c) 2008-2009 +	Lars-Dominik Braun <PromyLOPh@lavabit.com> + +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 <stdlib.h> +#include <stdio.h> +#include <string.h> + +inline void BarReadlineMoveLeft (char *buf, size_t *bufPos, +		size_t *bufLen) { +	char *tmpBuf = &buf[*bufPos-1]; +	while (tmpBuf < &buf[*bufLen]) { +		*tmpBuf = *(tmpBuf+1); +		++tmpBuf; +	} +	--(*bufPos); +	--(*bufLen); +} + +inline char BarReadlineIsAscii (char b) { +	return !(b & (1 << 7)); +} + +inline char BarReadlineIsUtf8Start (char b) { +	return (b & (1 << 7)) && (b & (1 << 6)); +} + +inline char BarReadlineIsUtf8Content (char b) { +	return (b & (1 << 7)) && !(b & (1 << 6)); +} + +/*	readline replacement + *	@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) + *	@return number of bytes read from stdin + */ +size_t BarReadline (char *buf, size_t bufSize, const char *mask, +		char fullReturn, char noEcho) { +	int chr = 0; +	size_t bufPos = 0; +	size_t bufLen = 0; +	unsigned char escapeState = 0; + +	memset (buf, 0, bufSize); + +	while ((chr = fgetc (stdin)) != EOF) { +		switch (chr) { +			/* EOT */ +			case 4: +				printf ("\n"); +				return bufLen; +				break; + +			/* return */ +			case 10: +				printf ("\n"); +				return bufLen; +				break; + +			/* escape */ +			case 27: +				escapeState = 1; +				break; + +			/* del */ +			case 126: +				break; + +			/* backspace */ +			case 127: +				if (bufPos > 0) { +					if (BarReadlineIsAscii (buf[bufPos-1])) { +						BarReadlineMoveLeft (buf, &bufPos, &bufLen); +					} else { +						/* delete utf-8 multibyte chars */ +						/* char content */ +						while (bufPos >= 0 && +								BarReadlineIsUtf8Content (buf[bufPos-1])) { +							BarReadlineMoveLeft (buf, &bufPos, &bufLen); +						} +						/* char length */ +						if (bufPos >= 0 && +								BarReadlineIsUtf8Start (buf[bufPos-1])) { +							BarReadlineMoveLeft (buf, &bufPos, &bufLen); +						} +					} +					/* move caret back and delete last character */ +					if (!noEcho) { +						printf ("\033[D\033[K"); +						fflush (stdout); +					} +				} else if (bufPos == 0 && buf[bufPos] != '\0') { +					buf[bufPos] = '\0'; +					if (!noEcho) { +						printf ("\033[K"); +						fflush (stdout); +					} +				} +				break; + +			default: +				/* ignore control/escape characters */ +				if (chr <= 0x1F) { +					break; +				} +				if (escapeState == 2) { +					escapeState = 0; +					break; +				} +				if (escapeState == 1 && chr == '[') { +					escapeState = 2; +					break; +				} +				/* don't accept chars not in mask */ +				if (mask != NULL && !strchr (mask, chr)) { +					break; +				} +				/* don't write beyond buffer's limits */ +				if (bufPos < bufSize-1) { +					buf[bufPos] = chr; +					++bufPos; +					++bufLen; +					if (!noEcho) { +						fputc (chr, stdout); +					} +					/* buffer full => return if requested */ +					if (fullReturn && bufPos >= bufSize-1) { +						printf ("\n"); +						return bufLen; +					} +				} +				break; +		} +	} +	return 0; +} + +/*	Read string from stdin + *	@param buffer + *	@param buffer size + *	@return number of bytes read from stdin + */ +inline size_t BarReadlineStr (char *buf, size_t bufSize, char noEcho) { +	return BarReadline (buf, bufSize, NULL, 0, noEcho); +} + +/*	Read int from stdin + *	@param write result into this variable + *	@return number of bytes read from stdin + */ +size_t BarReadlineInt (int *ret) { +	int rlRet = 0; +	char buf[16]; + +	rlRet = BarReadline (buf, sizeof (buf), "0123456789", 0, 0); +	*ret = atoi ((char *) buf); + +	return rlRet; +} + +/*	Yes/No? + *	@param defaul (user presses enter) + */ +int BarReadlineYesNo (char def) { +	char buf[2]; +	BarReadline (buf, sizeof (buf), "yYnN", 1, 0); +	if (*buf == 'y' || *buf == 'Y' || (def == 1 && *buf == '\0')) { +		return 1; +	} else { +		return 0; +	} +} + diff --git a/src/ui_readline.h b/src/ui_readline.h new file mode 100644 index 0000000..3f2e886 --- /dev/null +++ b/src/ui_readline.h @@ -0,0 +1,28 @@ +/* +Copyright (c) 2008-2009 +	Lars-Dominik Braun <PromyLOPh@lavabit.com> + +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. +*/ + +size_t BarReadline (char *, size_t, const char *, char, char); +inline size_t BarReadlineStr (char *, size_t, char); +size_t BarReadlineInt (int *); +int BarReadlineYesNo (char def); + | 
