summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--INSTALL1
-rw-r--r--src/CMakeLists.txt10
-rw-r--r--src/FindReadline.cmake37
-rw-r--r--src/main.c14
-rw-r--r--src/ui.c69
-rw-r--r--src/ui_act.c30
-rw-r--r--src/ui_readline.c195
-rw-r--r--src/ui_readline.h28
8 files changed, 263 insertions, 121 deletions
diff --git a/INSTALL b/INSTALL
index 151ff6e..e458e15 100644
--- a/INSTALL
+++ b/INSTALL
@@ -13,7 +13,6 @@ libfaad2 http://www.audiocoding.com/downloads.html
AND/OR libmad http://www.underbit.com/products/mad/
libxml2 http://xmlsoft.org/
pthreads
-readline
UTF-8 console/locale!
Building
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)
diff --git a/src/main.c b/src/main.c
index 06f5975..8de5d6f 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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");
}
diff --git a/src/ui.c b/src/ui.c
index 6154371..91860cf 100644
--- a/src/ui.c
+++ b/src/ui.c
@@ -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);
+