From 87b51f5430bf0f4a4abeea5235618d4b0fba8e80 Mon Sep 17 00:00:00 2001 From: Qball Cow Date: Tue, 13 May 2014 10:45:59 +0200 Subject: [PATCH] Extract out the history code and create functions for it. (Easier to fix issues later on) --- Makefile.am | 2 + include/history.h | 60 +++++++++++ source/history.c | 256 ++++++++++++++++++++++++++++++++++++++++++++ source/run-dialog.c | 179 ++----------------------------- source/ssh-dialog.c | 157 +++------------------------ 5 files changed, 341 insertions(+), 313 deletions(-) create mode 100644 include/history.h create mode 100644 source/history.c diff --git a/Makefile.am b/Makefile.am index 5888f5c0..2f482ad7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -26,12 +26,14 @@ rofi_SOURCES=\ source/dmenu-dialog.c\ source/run-dialog.c\ source/ssh-dialog.c\ + source/history.c\ config/config.c\ include/rofi.h\ include/run-dialog.h\ include/ssh-dialog.h\ include/dmenu-dialog.h\ include/xrmoptions.h\ + include/history.h\ include/textbox.h ## diff --git a/include/history.h b/include/history.h new file mode 100644 index 00000000..6d3ae7a2 --- /dev/null +++ b/include/history.h @@ -0,0 +1,60 @@ +/** + * rofi + * + * MIT/X11 License + * Copyright 2013-2014 Qball Cow + * + * 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. + * + */ +#ifndef __HISTORY_H__ +#define __HISTORY_H__ + +/** + * @param filename The filename of the history cache. + * @param entry The entry to add/increment + * + * Sets the entry in the history, if it exists its use-count is incremented. + * + */ +void history_set ( const char *filename, const char *entry ); + + +/** + * @param filename The filename of the history cache. + * @param entry The entry to remove + * + * Removes the entry from the history. + */ +void history_remove ( const char *filename, const char *entry ); + + +/** + * @param filename The filename of the history cache. + * @param length The length of the returned list. + * + * Gets the entries in the list (in order of usage) + * @returns a list of entries length long. (and NULL terminated). + */ +char ** history_get_list ( const char *filename, unsigned int * length); + + + +#endif diff --git a/source/history.c b/source/history.c new file mode 100644 index 00000000..5eda4773 --- /dev/null +++ b/source/history.c @@ -0,0 +1,256 @@ +/** + * rofi + * + * MIT/X11 License + * Copyright 2013-2014 Qball Cow + * + * 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 +#include +#include +#include +#include +#include +#include "rofi.h" +#include "history.h" + +#define HISTORY_NAME_LENGTH 256 +#define HISTORY_MAX_ENTRIES 25 + +typedef struct __element +{ + long int index; + char name[HISTORY_NAME_LENGTH]; +}_element; + +static int __element_sort_func ( const void *ea, const void *eb ) +{ + _element *a = *(_element * *) ea; + _element *b = *(_element * *) eb; + return b->index - a->index; +} + +static void __history_write_element_list( FILE *fd, _element **list, unsigned int length) +{ + if(list == NULL) { + return; + } + // Sort the list before writing out. + qsort ( list, length, sizeof ( _element* ), __element_sort_func ); + + // Set the max length of the list. + length = (length > HISTORY_MAX_ENTRIES)? HISTORY_MAX_ENTRIES:length; + + // Write out entries. + for(unsigned int iter = 0; iter < length ;iter++) + { + fprintf(fd , "%ld %s\n", list[iter]->index, list[iter]->name); + } +} + +static _element ** __history_get_element_list ( FILE *fd, unsigned int *length ) +{ + _element **retv = NULL; + + if (length == NULL) + { + return NULL; + } + *length = 0; + + if( fd == NULL) + { + return NULL; + } + char buffer[HISTORY_NAME_LENGTH+16]; + while ( fgets (buffer, HISTORY_NAME_LENGTH+16, fd ) != NULL) + { + // Skip empty lines. + if ( strlen ( buffer ) == 0 ) + { + continue; + } + retv = reallocate ( retv, ( *length + 2 ) * sizeof ( _element* ) ); + retv[(*length)] = allocate ( sizeof ( _element ) ); + // remove trailing \n + buffer[strlen ( buffer ) - 1] = '\0'; + // Parse the number of times. + char * start = NULL; + retv[(*length)]->index = strtol ( buffer, &start, 10 ); + strncpy(retv[(*length)]->name, (start+1),HISTORY_NAME_LENGTH); + // Force trailing '\0' + retv[(*length)]->name[HISTORY_NAME_LENGTH-1] = '\0'; + retv[(*length) + 1] = NULL; + + (*length)++; + } + return retv; +} + + +void history_set ( const char *filename, const char *entry ) +{ + int found = 0; + unsigned int curr = 0; + unsigned int length = 0; + // Open file for reading and writing. + FILE *fd = fopen(filename, "a+"); + if(fd == NULL) + { + fprintf(stderr, "Failed to open file: %s\n", strerror(errno)); + return ; + } + // Get list. + _element ** list = __history_get_element_list(fd, &length); + + // Look if the entry exists. + for(unsigned int iter = 0;!found && iter < length; iter++) + { + if(strcmp(list[iter]->name, entry) == 0) + { + curr = iter; + found = 1; + } + } + + if(found) { + // If exists, increment list index number + list[curr]->index++; + }else{ + // If not exists, add it. + // Increase list by one + list = reallocate(list,(length+2)*sizeof(_element *)); + list[length] = allocate(sizeof(_element)); + // Copy name + strncpy(list[length]->name, entry, HISTORY_NAME_LENGTH); + list[length]->name[HISTORY_NAME_LENGTH-1] = '\0'; + // set # hits + list[length]->index = 1; + + length++; + list[length] = NULL; + } + + // Rewind. + fseek(fd, 0L, SEEK_SET); + // Clear file. + ftruncate(fileno(fd), 0); + + // Write list. + __history_write_element_list(fd, list, length); + + + // Free the list. + for(unsigned int iter = 0; iter < length; iter++) + { + if(list[iter] != NULL) { free(list[iter]); } + } + if(list != NULL) free(list); + // Close file. + fclose(fd); +} + +void history_remove ( const char *filename, const char *entry ) +{ + int found = 0; + unsigned int curr = 0; + unsigned int length = 0; + // Open file for reading and writing. + FILE *fd = fopen(filename, "a+"); + if(fd == NULL) + { + fprintf(stderr, "Failed to open file: %s\n", strerror(errno)); + return ; + } + // Get list. + _element ** list = __history_get_element_list(fd, &length); + + // Find entry. + for(unsigned int iter = 0;!found && iter < length; iter++) + { + if(strcmp(list[iter]->name, entry) == 0) + { + curr = iter; + found = 1; + } + } + + // If found, remove it and write out new file. + if(found) { + // Remove the entry. + free(list[curr]); + // Swap last to here (if list is size 1, we just swap empty sets). + list[curr] = list[length-1]; + // Empty last. + list[length-1] = NULL; + length--; + + // Rewind. + fseek(fd, 0L, SEEK_SET); + // Clear list. + ftruncate(fileno(fd), 0); + + // Write list. + __history_write_element_list(fd, list, length); + } + + // Free the list. + for(unsigned int iter = 0; iter < length; iter++) + { + if(list[iter] != NULL) { free(list[iter]); } + } + if(list != NULL) free(list); + // Close file. + fclose(fd); +} + +char ** history_get_list ( const char *filename, unsigned int *length ) +{ + char **retv = NULL; + // Open file. + FILE *fd = fopen(filename, "r"); + if(fd == NULL) + { + if(errno != ENOENT) { + fprintf(stderr, "Failed to open file: %s\n", strerror(errno)); + } + return NULL; + } + // Get list. + _element ** list = __history_get_element_list(fd, length); + + // Copy list in right format. + if((*length) > 0 ) + { + retv = allocate(((*length)+1)*sizeof(char *)); + for ( int iter = 0; iter < (*length); iter++) + { + retv[iter] = strdup(list[iter]->name); + free(list[iter]); + } + retv[(*length)] = NULL; + free(list); + } + + fclose(fd); + return retv; +} diff --git a/source/run-dialog.c b/source/run-dialog.c index 1b39d438..1fca28da 100644 --- a/source/run-dialog.c +++ b/source/run-dialog.c @@ -40,6 +40,7 @@ #include #include "rofi.h" +#include "history.h" #include "run-dialog.h" #ifdef TIMING #include @@ -88,10 +89,6 @@ static pid_t exec_cmd ( const char *cmd, int run_in_term ) exit ( EXIT_FAILURE ); } - int curr = -1; - unsigned int index = 0; - element **retv = NULL; - /** * This happens in non-critical time (After launching app) * It is allowed to be a bit slower. @@ -100,79 +97,7 @@ static pid_t exec_cmd ( const char *cmd, int run_in_term ) if(asprintf ( &path, "%s/%s", cache_dir, RUN_CACHE_FILE ) == -1) { return -1; } - - FILE *fd = fopen ( path, "r" ); - - if ( fd != NULL ) - { - char buffer[1024]; - while ( fgets ( buffer, 1024, fd ) != NULL ) - { - if ( strlen ( buffer ) == 0 ) - { - continue; - } - retv = reallocate ( retv, ( index + 2 ) * sizeof ( element* ) ); - retv[index] = allocate ( sizeof ( element ) ); - // remove trailing \n - buffer[strlen ( buffer ) - 1] = '\0'; - char * start = NULL; - retv[index]->index = strtol ( buffer, &start, 10 ); - snprintf ( retv[index]->name, RUN_DIALOG_NAME_LENGTH, "%s", start + 1 ); - retv[index + 1] = NULL; - - if ( strcasecmp ( retv[index]->name, cmd ) == 0 ) - { - curr = index; - } - index++; - } - - fclose ( fd ); - } - - if ( curr < 0 ) - { - retv = reallocate ( retv, ( index + 2 ) * sizeof ( element* ) ); - retv[index] = allocate ( sizeof ( element ) ); - retv[index]->index = 1; - snprintf ( retv[index]->name, RUN_DIALOG_NAME_LENGTH, "%s", cmd ); - index++; - } - else - { - retv[curr]->index++; - } - // Sort the list. - qsort ( retv, index, sizeof ( element* ), element_sort_func ); - - /** - * Write out the last 25 results again. - */ - fd = fopen ( path, "w" ); - - if ( fd ) - { - for ( int i = 0; i < ( int ) index && i < 20; i++ ) - { - if ( retv[i]->name && retv[i]->name[0] != '\0' ) - { - fprintf ( fd, "%ld %s\n", - retv[i]->index, - retv[i]->name - ); - } - } - - fclose ( fd ); - } - - for ( int i = 0; retv != NULL && retv[i] != NULL; i++ ) - { - free ( retv[i] ); - } - - free ( retv ); + history_set(path, cmd); free ( path ); @@ -181,11 +106,6 @@ static pid_t exec_cmd ( const char *cmd, int run_in_term ) // execute sub-process static void delete_entry ( const char *cmd ) { - int curr = -1; - unsigned int index = 0; - element **retv = NULL; - - /** * This happens in non-critical time (After launching app) * It is allowed to be a bit slower. @@ -194,67 +114,7 @@ static void delete_entry ( const char *cmd ) if(asprintf ( &path, "%s/%s", cache_dir, RUN_CACHE_FILE ) == -1) { return; } - - FILE *fd = fopen ( path, "r" ); - - if ( fd != NULL ) - { - char buffer[1024]; - while ( fgets ( buffer, 1024, fd ) != NULL ) - { - char * start = NULL; - if ( strlen ( buffer ) == 0 ) - { - continue; - } - retv = reallocate ( retv, ( index + 2 ) * sizeof ( element* ) ); - retv[index] = allocate ( sizeof ( element ) ); - // remove trailing \n - buffer[strlen ( buffer ) - 1] = '\0'; - retv[index]->index = strtol ( buffer, &start, 10 ); - snprintf ( retv[index]->name, RUN_DIALOG_NAME_LENGTH, "%s", start + 1 ); - retv[index + 1] = NULL; - - if ( strcasecmp ( retv[index]->name, cmd ) == 0 ) - { - curr = index; - } - index++; - } - - fclose ( fd ); - } - - /** - * Write out the last 25 results again. - */ - fd = fopen ( path, "w" ); - - if ( fd ) - { - for ( int i = 0; i < ( int ) index && i < 20; i++ ) - { - if ( i != curr ) - { - if ( retv[i]->name && retv[i]->name[0] != '\0' ) - { - fprintf ( fd, "%ld %s\n", - retv[i]->index, - retv[i]->name - ); - } - } - } - - fclose ( fd ); - } - - for ( int i = 0; retv != NULL && retv[i] != NULL; i++ ) - { - free ( retv[i] ); - } - - free ( retv ); + history_remove(path, cmd); free ( path ); } @@ -282,37 +142,10 @@ static char ** get_apps ( ) if(asprintf ( &path, "%s/%s", cache_dir, RUN_CACHE_FILE ) > 0) { - FILE *fd = fopen ( path, "r" ); - - if ( fd != NULL ) - { - char buffer[1024]; - while ( fgets ( buffer, 1024, fd ) != NULL ) - { - if ( strlen ( buffer ) == 0 ) - { - continue; - } - // remove trailing \n - buffer[strlen ( buffer ) - 1] = '\0'; - char *start = NULL; - // Don't use result. - strtol ( buffer, &start, 10 ); - if ( start == NULL ) - { - continue; - } - retv = reallocate ( retv, ( index + 2 ) * sizeof ( char* ) ); - retv[index] = strdup ( start + 1 ); - retv[index + 1] = NULL; - index++; - num_favorites++; - } - - fclose ( fd ); - } - + retv = history_get_list(path, &index); free ( path ); + // Keep track of how many where loaded as favorite. + num_favorites=index; } diff --git a/source/ssh-dialog.c b/source/ssh-dialog.c index 071d7412..f23670a4 100644 --- a/source/ssh-dialog.c +++ b/source/ssh-dialog.c @@ -40,12 +40,13 @@ #include #include "rofi.h" +#include "history.h" #include "ssh-dialog.h" #ifdef TIMING #include #endif -#define SSH_CACHE_FILE "rofi.sshcache" +#define SSH_CACHE_FILE "rofi-2.sshcache" static inline int execshssh ( const char *host ) { @@ -96,71 +97,16 @@ static pid_t exec_ssh ( const char *cmd ) exit ( EXIT_FAILURE ); } - int curr = -1; - unsigned int index = 0; - char **retv = NULL; - /** * This happens in non-critical time (After launching app) * It is allowed to be a bit slower. */ - char *path = allocate ( strlen ( cache_dir ) + strlen ( SSH_CACHE_FILE ) + 3 ); - sprintf ( path, "%s/%s", cache_dir, SSH_CACHE_FILE ); - FILE *fd = fopen ( path, "r" ); - - if ( fd != NULL ) + char *path = NULL; + if(asprintf ( &path, "%s/%s", cache_dir, SSH_CACHE_FILE ) > 0) { - char buffer[1024]; - while ( fgets ( buffer, 1024, fd ) != NULL ) - { - retv = reallocate ( retv, ( index + 2 ) * sizeof ( char* ) ); - buffer[strlen ( buffer ) - 1] = '\0'; - retv[index] = strdup ( buffer ); - retv[index + 1] = NULL; - - if ( strcasecmp ( retv[index], cmd ) == 0 ) - { - curr = index; - } - - index++; - } - - fclose ( fd ); + history_set(path, cmd); + free(path); } - - /** - * Write out the last 25 results again. - */ - fd = fopen ( path, "w" ); - - if ( fd ) - { - // Last one goes on top! - fputs ( cmd, fd ); - fputc ( '\n', fd ); - - for ( int i = 0; i < ( int ) index && i < 20; i++ ) - { - if ( i != curr ) - { - fputs ( retv[i], fd ); - fputc ( '\n', fd ); - } - } - - fclose ( fd ); - } - - for ( int i = 0; retv != NULL && retv[i] != NULL; i++ ) - { - free ( retv[i] ); - } - - free ( retv ); - - free ( path ); - return pid; } static void delete_ssh ( const char *cmd ) @@ -169,67 +115,12 @@ static void delete_ssh ( const char *cmd ) { return; } - - int curr = -1; - unsigned int index = 0; - char **retv = NULL; - - /** - * This happens in non-critical time (After launching app) - * It is allowed to be a bit slower. - */ - char *path = allocate ( strlen ( cache_dir ) + strlen ( SSH_CACHE_FILE ) + 3 ); - sprintf ( path, "%s/%s", cache_dir, SSH_CACHE_FILE ); - FILE *fd = fopen ( path, "r" ); - - if ( fd != NULL ) + char *path = NULL; + if(asprintf ( &path, "%s/%s", cache_dir, SSH_CACHE_FILE ) > 0) { - char buffer[1024]; - while ( fgets ( buffer, 1024, fd ) != NULL ) - { - retv = reallocate ( retv, ( index + 2 ) * sizeof ( char* ) ); - buffer[strlen ( buffer ) - 1] = '\0'; - retv[index] = strdup ( buffer ); - retv[index + 1] = NULL; - - if ( strcasecmp ( retv[index], cmd ) == 0 ) - { - curr = index; - } - - index++; - } - - fclose ( fd ); + history_remove(path, cmd); + free(path); } - - /** - * Write out the last 25 results again. - */ - fd = fopen ( path, "w" ); - - if ( fd ) - { - for ( int i = 0; i < ( int ) index && i < 20; i++ ) - { - if ( i != curr ) - { - fputs ( retv[i], fd ); - fputc ( '\n', fd ); - } - } - - fclose ( fd ); - } - - for ( int i = 0; retv != NULL && retv[i] != NULL; i++ ) - { - free ( retv[i] ); - } - - free ( retv ); - - free ( path ); } static int sort_func ( const void *a, const void *b ) { @@ -253,34 +144,20 @@ static char ** get_ssh ( ) return NULL; } - path = allocate ( strlen ( cache_dir ) + strlen ( "/"SSH_CACHE_FILE ) + 2 ); - sprintf ( path, "%s/%s", cache_dir, SSH_CACHE_FILE ); - FILE *fd = fopen ( path, "r" ); - char buffer[1024]; - - if ( fd != NULL ) + if(asprintf ( &path, "%s/%s", cache_dir, SSH_CACHE_FILE ) > 0) { - while ( fgets ( buffer, 1024, fd ) != NULL ) - { - retv = reallocate ( retv, ( index + 2 ) * sizeof ( char* ) ); - buffer[strlen ( buffer ) - 1] = '\0'; - retv[index] = strdup ( buffer ); - retv[index + 1] = NULL; - index++; - num_favorites++; - } - - fclose ( fd ); + retv = history_get_list(path, &index); + free(path); + num_favorites = index; } - free ( path ); const char *hd = getenv ( "HOME" ); - path = allocate ( strlen ( hd ) + strlen ( ".ssh/config" ) + 3 ); - sprintf ( path, "%s/%s", hd, ".ssh/config" ); - fd = fopen ( path, "r" ); + asprintf ( &path, "%s/%s", hd, ".ssh/config" ); + FILE *fd = fopen ( path, "r" ); if ( fd != NULL ) { + char buffer[1024]; while ( fgets ( buffer, 1024, fd ) != NULL ) { if ( strncasecmp ( buffer, "Host", 4 ) == 0 )