From 3322529804da43f4efe4a5f03c960fb5f4b5dc4a Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Mon, 12 Feb 2018 12:53:41 +0100 Subject: [PATCH] Support for unicode names in directory listing --- src/Makefile | 2 +- src/filesel.c | 116 +++++++++++++++++++++++++++++++++++++++++++++----- src/filesel.h | 2 +- src/global.h | 1 + src/io.c | 33 +++++++++++--- src/main.c | 1 + src/struct.h | 6 ++- 7 files changed, 139 insertions(+), 22 deletions(-) diff --git a/src/Makefile b/src/Makefile index 3922da6d..83101635 100644 --- a/src/Makefile +++ b/src/Makefile @@ -541,7 +541,7 @@ OBJS = main.o init.o graph.o sdlscreen.o misc.o special.o \ transform.o pversion.o factory.o $(PLATFORMOBJ) \ fileformats.o miscfileformats.o libraw2crtc.o \ brush_ops.o buttons_effects.o layers.o \ - oldies.o tiles.o colorred.o + oldies.o tiles.o colorred.o unicode.o OBJ = $(addprefix $(OBJDIR)/,$(OBJS)) SKINS = skin_classic.png skin_modern.png skin_DPaint.png \ diff --git a/src/filesel.c b/src/filesel.c index 686e9568..61481790 100644 --- a/src/filesel.c +++ b/src/filesel.c @@ -60,6 +60,7 @@ #include "readline.h" #include "input.h" #include "help.h" +#include "unicode.h" #include "filesel.h" #define NORMAL_FILE_COLOR MC_Light // color du texte pour une ligne de @@ -205,23 +206,102 @@ void Free_fileselector_list(T_Fileselector *list) // On fait avancer la tête de la liste list->First=list->First->Next; // Et on efface l'ancien premier élément de la liste + free(temp_item->Unicode_full_name); + free(temp_item->Unicode_short_name); free(temp_item); temp_item = NULL; } Recount_files(list); } -int Position_last_dot(const char * fname) +static int Position_last_dot(const char * fname) { int pos_last_dot = -1; int c = 0; - + for (c = 0; fname[c]!='\0'; c++) if (fname[c]=='.') pos_last_dot = c; return pos_last_dot; } - + +static int Position_last_dot_unicode(const word * fname) +{ + int pos_last_dot = -1; + int c = 0; + + for (c = 0; fname[c]!='\0'; c++) + if (fname[c]=='.') + pos_last_dot = c; + return pos_last_dot; +} + +word * Format_filename_unicode(const word * fname, word max_length, int type) +{ + static word result[40]; + int c; + int other_cursor; + int pos_last_dot; + + // safety + if (max_length>40) + max_length=40; + + if (Unicode_char_strcmp(fname,PARENT_DIR)==0) + { + Unicode_char_strlcpy(result, "\x11 PARENT DIRECTORY", 40); + // Append spaces + for (c=18; c= max_length-1) + result[max_length-2]=(byte)ELLIPSIS_CHARACTER; + } + else + { + // Initialize as all spaces + for (c = 0; c max_length-6) + { + result[max_length-6]=(byte)ELLIPSIS_CHARACTER; + break; + } + result[c]=fname[c]; + } + + // Ensuite on recopie la partie qui suit le point (si nécessaire): + if (pos_last_dot != -1) + { + for (c = pos_last_dot+1,other_cursor=max_length-4;fname[c]!='\0' && other_cursor < max_length-1;c++,other_cursor++) + result[other_cursor]=fname[c]; + } + } + return result; +} + char * Format_filename(const char * fname, word max_length, int type) { static char result[40]; @@ -305,17 +385,20 @@ char * Format_filename(const char * fname, word max_length, int type) // -- Rajouter a la liste des elements de la liste un element --------------- -void Add_element_to_list(T_Fileselector *list, const char * full_name, const char *short_name, int type, byte icon) +T_Fileselector_item * Add_element_to_list(T_Fileselector *list, const char * full_name, const char *short_name, int type, byte icon) // Cette procedure ajoute a la liste chainee un fichier passé en argument. { // Working element T_Fileselector_item * temp_item; + size_t short_name_len; + short_name_len = strlen(short_name) + 1; // Allocate enough room for one struct + the visible label - temp_item=(T_Fileselector_item *)malloc(sizeof(T_Fileselector_item)+strlen(short_name)); + temp_item=(T_Fileselector_item *)malloc(sizeof(T_Fileselector_item)+short_name_len); + memset(temp_item, 0, sizeof(T_Fileselector_item)); // Initialize element - strcpy(temp_item->Short_name,short_name); + memcpy(temp_item->Short_name,short_name,short_name_len); strcpy(temp_item->Full_name,full_name); temp_item->Type = type; temp_item->Icon = icon; @@ -329,6 +412,7 @@ void Add_element_to_list(T_Fileselector *list, const char * full_name, const cha // Put new element at the beginning list->First=temp_item; + return temp_item; } /// @@ -374,8 +458,8 @@ struct Read_dir_pdata static void Read_dir_callback(void * pdata, const char *file_name, const word *unicode_name, byte is_file, byte is_directory, byte is_hidden) { + T_Fileselector_item * item; struct Read_dir_pdata * p = (struct Read_dir_pdata *)pdata; - (void)unicode_name; if (p == NULL) // error ! return; @@ -401,7 +485,9 @@ static void Read_dir_callback(void * pdata, const char *file_name, const word *u return; // Add to list - Add_element_to_list(p->list, file_name, Format_filename(file_name, 19, 1), 1, ICON_NONE); + item = Add_element_to_list(p->list, file_name, Format_filename(file_name, 19, 1), 1, ICON_NONE); + item->Unicode_full_name = Unicode_strdup(unicode_name); + item->Unicode_short_name = Unicode_strdup(Format_filename_unicode(unicode_name, 19, 1)); p->list->Nb_directories++; } else if (is_file && // It's a file @@ -413,7 +499,9 @@ static void Read_dir_callback(void * pdata, const char *file_name, const word *u if (Check_extension(file_name, ext)) { // Add to list - Add_element_to_list(p->list, file_name, Format_filename(file_name, 19, 0), 0, ICON_NONE); + item = Add_element_to_list(p->list, file_name, Format_filename(file_name, 19, 0), 0, ICON_NONE); + item->Unicode_full_name = Unicode_strdup(unicode_name); + item->Unicode_short_name = Unicode_strdup(Format_filename_unicode(unicode_name, 19, 0)); p->list->Nb_files++; // Stop searching break; @@ -871,9 +959,15 @@ void Display_file_list(T_Fileselector *list, short offset_first,short selector_o // Name preceded by an icon Print_in_window(16,95+index*8,current_item->Short_name,text_color,background_color); Window_display_icon_sprite(8,95+index*8,current_item->Icon); - } else + } + else + { // Name without icon - Print_in_window(8,95+index*8,current_item->Short_name,text_color,background_color); + if (current_item->Unicode_short_name) + Print_in_window_utf16(8,95+index*8,current_item->Unicode_short_name,text_color,background_color); + else + Print_in_window(8,95+index*8,current_item->Short_name,text_color,background_color); + } // On passe à la ligne suivante selector_offset--; diff --git a/src/filesel.h b/src/filesel.h index 8942998d..98162db7 100644 --- a/src/filesel.h +++ b/src/filesel.h @@ -31,7 +31,7 @@ byte Button_Load_or_Save(T_Selector_settings *settings, byte load, T_IO_Context *context); -void Add_element_to_list(T_Fileselector *list, const char * full_name, const char *short_name, int type, byte icon); +T_Fileselector_item * Add_element_to_list(T_Fileselector *list, const char * full_name, const char *short_name, int type, byte icon); /// /// Formats a display name for a file, directory, or similar name (drive, volume). /// The returned value is a pointer to a single static buffer of maximum 40 characters diff --git a/src/global.h b/src/global.h index 8ddbd191..ff180be1 100644 --- a/src/global.h +++ b/src/global.h @@ -770,6 +770,7 @@ GFX2_GLOBAL int Line_number_in_INI_file; #endif GFX2_GLOBAL iconv_t cd; GFX2_GLOBAL iconv_t cd_inv; +GFX2_GLOBAL iconv_t cd_utf16; #endif /* ENABLE_FILENAMES_ICONV */ // -- Specific to SDL diff --git a/src/io.c b/src/io.c index fa5d18d1..665e7490 100644 --- a/src/io.c +++ b/src/io.c @@ -51,6 +51,7 @@ #include "struct.h" #include "io.h" #include "realpath.h" +#include "global.h" // Lit un octet // Renvoie -1 si OK, 0 en cas d'erreur @@ -393,17 +394,18 @@ void For_each_file(const char * directory_name, void Callback(const char *)) /// Scans a directory, calls Callback for each file or directory in it, void For_each_directory_entry(const char * directory_name, void * pdata, T_File_dir_cb Callback) { - // Pour scan de répertoire - DIR* current_directory; //Répertoire courant - struct dirent* entry; // Structure de lecture des éléments + DIR* current_directory; // current directory + struct dirent* entry; // directory entry struct char full_filename[MAX_PATH_CHARACTERS]; word * unicode_filename = NULL; + word unicode_buffer[MAX_PATH_CHARACTERS]; int filename_position; - strcpy(full_filename, directory_name); - current_directory=opendir(full_filename); - if(current_directory == NULL) return; // Répertoire invalide ... - filename_position = strlen(full_filename); + current_directory=opendir(directory_name); + if(current_directory == NULL) return; // Invalid directory + + filename_position = strlen(directory_name); + memcpy(full_filename, directory_name, filename_position+1); #if defined(__AROS__) if (filename_position==0 || (strcmp(full_filename+filename_position-1,PATH_SEPARATOR) && strcmp(full_filename+filename_position-1,":"))) #else @@ -416,6 +418,23 @@ void For_each_directory_entry(const char * directory_name, void * pdata, T_File_ while ((entry=readdir(current_directory))) { struct stat Infos_enreg; +#ifdef ENABLE_FILENAMES_ICONV + char * input = entry->d_name; + size_t inbytesleft = strlen(entry->d_name); + char * output = (char *)unicode_buffer; + size_t outbytesleft = sizeof(unicode_buffer) - 2; + unicode_filename = NULL; + if (cd_utf16 != (iconv_t)-1) + { + size_t r = iconv(cd_utf16, &input, &inbytesleft, &output, &outbytesleft); + if (r != (size_t)-1) + { + output[0] = '\0'; + output[1] = '\0'; + unicode_filename = unicode_buffer; + } + } +#endif strcpy(&full_filename[filename_position], entry->d_name); stat(full_filename,&Infos_enreg); Callback( diff --git a/src/main.c b/src/main.c index 15fc0657..3eea120f 100644 --- a/src/main.c +++ b/src/main.c @@ -496,6 +496,7 @@ int Init_program(int argc,char * argv[]) // utilisé pour convertir les noms de fichiers cd = iconv_open(TOCODE, FROMCODE); // From UTF8 to ANSI cd_inv = iconv_open(FROMCODE, TOCODE); // From ANSI to UTF8 + cd_utf16 = iconv_open("UTF-16LE", FROMCODE); // From UTF8 to UTF16 #endif /* ENABLE_FILENAMES_ICONV */ // On en profite pour le mémoriser dans le répertoire principal: diff --git a/src/struct.h b/src/struct.h index 1e6177ba..32041eba 100644 --- a/src/struct.h +++ b/src/struct.h @@ -180,9 +180,11 @@ typedef struct T_Fileselector_item struct T_Fileselector_item * Next; ///< Pointer to next item of the current fileselector. struct T_Fileselector_item * Previous;///< Pointer to previous item of the current fileselector. + + word * Unicode_full_name; ///< Pointer to allocated unicode string. Filesystem name + word * Unicode_short_name; ///< Pointer to allocated unicode string. Name to display - word Length_short_name; ///< Number of bytes allocated for :Short_name - #if __GNUC__ < 3 +#if __GNUC__ < 3 char Short_name[0]; ///< Name to display. #else char Short_name[]; ///< Name to display.