From fcd15e4200bd51cb3246caec7e5b687f12fb68a6 Mon Sep 17 00:00:00 2001 From: ache Date: Fri, 12 May 2017 12:31:21 +0000 Subject: Init commit --- h.c | 962 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 962 insertions(+) create mode 100755 h.c diff --git a/h.c b/h.c new file mode 100755 index 0000000..c40af47 --- /dev/null +++ b/h.c @@ -0,0 +1,962 @@ +#define _DEFAULT_SOURCE +#define _XOPEN_SOURCE 700 // For strnlen() +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifdef DEBUG + +#include + +#endif + + + + + +#define MAX_PATH 1024 + + +#define max(a, b) \ + ({ typeof(a) _a = a; \ + typeof(b) _b = b; \ + _a > _b ? _a : _b; }) + + + + +static short my_fg = COLOR_WHITE; +static short my_bg = COLOR_BLACK; +static bool visual_mode = false; +static bool input_avail = false; +static unsigned char input; +static char *msg_win_str = NULL; +static bool should_exit = false; +static WINDOW *cmd_win; +static WINDOW *sep_win; + +char status[10]; + +int color[] = { + COLOR_BLACK, COLOR_RED, + COLOR_GREEN, COLOR_YELLOW, COLOR_BLUE, + COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE}; + + + +typedef struct tagInfo { + TagLib_File *file; + TagLib_Tag *tag; + const TagLib_AudioProperties *properties; +} tagInfo; + +typedef struct itemC { + char* cstr; + int opt; + char* suffix; + char* prefix; + tagInfo info; + int selected; + int id; +} itemC; + +typedef struct menuC { + itemC* list; + int nbElem; + int hl; + int firstElem; + int opt; // SCROLL | HL_HIDE | HL_HIDE | HL_BOLD | HL_CLIGN | HL_INV [ | BORDER ] + char* suffix; + char* prefix; + int x,y,w,h; +} menuC; + + +#define HIDDEN 1 + + +// Calculates the cursor column for the readline window in a way that supports +// multibyte, multi-column and combining characters. readline itself calculates +// this as part of its default redisplay function and does not export the +// cursor column. +// +// Returns the total width (in columns) of the characters in the 'n'-byte +// prefix of the null-terminated multibyte string 's'. If 'n' is larger than +// 's', returns the total width of the string. Tries to emulate how readline +// prints some special characters. +// +// 'offset' is the current horizontal offset within the line. This is used to +// get tabstops right. +// +// Makes a guess for malformed strings. +static size_t strnwidth(const char *s, size_t n, size_t offset) +{ + mbstate_t shift_state; + wchar_t wc; + size_t wc_len; + size_t width = 0; + + // Start in the initial shift state + memset(&shift_state, '\0', sizeof shift_state); + + for (size_t i = 0; i < n; i += wc_len) { + // Extract the next multibyte character + wc_len = mbrtowc(&wc, s + i, MB_CUR_MAX, &shift_state); + switch (wc_len) { + case 0: + // Reached the end of the string + goto done; + + case (size_t)-1: case (size_t)-2: + // Failed to extract character. Guess that the remaining characters + // are one byte/column wide each. + width += strnlen(s, n - i); + goto done; + } + + if (wc == '\t') + width = ((width + offset + 8) & ~7) - offset; + else + // TODO: readline also outputs ~ and the like for some + // non-printable characters + width += iswcntrl(wc) ? 2 : max(0, wcwidth(wc)); + } + +done: + return width; +} + +// Like strnwidth, but calculates the width of the entire string +static size_t strwidth(const char *s, size_t offset) +{ + return strnwidth(s, SIZE_MAX, offset); +} + + + +static noreturn void fail_exit(const char *msg) +{ + // Make sure endwin() is only called in visual mode. As a note, calling it + // twice does not seem to be supported and messed with the cursor position. + if (visual_mode) + endwin(); + fprintf(stderr, "%s\n", msg); + exit(EXIT_FAILURE); +} + +// Checks errors for (most) ncurses functions. CHECK(fn, x, y, z) is a checked +// version of fn(x, y, z). +#define CHECK(fn, ...) \ + do \ + if (fn(__VA_ARGS__) == ERR) \ + fail_exit(#fn"() failed"); \ + while (false) + + +// Not bothering with 'input_avail' and just returning 0 here seems to do the +// right thing too, but this might be safer across readline versions +static int readline_input_avail(void) +{ + return input_avail; +} + +static int readline_getc(FILE *dummy) +{ + input_avail = false; + return input; +} +static void forward_to_readline(char c) +{ + input = c; + input_avail = true; + rl_callback_read_char(); +} +static void msg_win_redisplay(bool for_resize) +{ + CHECK(mvaddstr, 0, 0, msg_win_str ? msg_win_str : ""); + + // We batch window updates when resizing +/* + if (for_resize) + CHECK(wnoutrefresh, msg_win); + else + CHECK(wrefresh, msg_win); +*/ +} +static void got_command(char *line) +{ + if( line ) + if (*line != '\0') + add_history(line); + + free(msg_win_str); + msg_win_str = line; + //msg_win_redisplay(false); + should_exit = true; +} + +static void cmd_win_redisplay(bool for_resize) +{ + size_t prompt_width = strwidth(rl_display_prompt, 0); + size_t cursor_col = prompt_width + + strnwidth(rl_line_buffer, rl_point, prompt_width); + + CHECK(werase, cmd_win); + // This might write a string wider than the terminal currently, so don't + // check for errors + mvwprintw(cmd_win, 0, 0, "%s%s", rl_display_prompt, rl_line_buffer); + if (cursor_col >= COLS) + // Hide the cursor if it lies outside the window. Otherwise it'll + // appear on the very right. + curs_set(0); + else { + CHECK(wmove, cmd_win, 0, cursor_col); + //curs_set(2); + } + // We batch window updates when resizing + if (for_resize) + CHECK(wnoutrefresh, cmd_win); + else + CHECK(wrefresh, cmd_win); +} + +static void readline_redisplay(void) +{ + cmd_win_redisplay(false); +} + + + +void rintfc(char* fstrc, int max_length); + + +int sort_i(const void* A, const void* B) { + itemC* a = (itemC*)A; + itemC* b = (itemC*)B; + + if(a->opt > b->opt) + return -1; + else if(a->opt < b->opt) + return 1; + else { + return strcmp(a->cstr,b->cstr); + } +} +void listdir(int option, itemC** m, int* s) { + DIR *dir; + int nbitem = 0; + itemC* menu = NULL; + struct dirent *entry; + + if (!(dir = opendir("."))) + return; + + if (!(entry = readdir(dir))) + return; + + do { + if( entry->d_name[0] == '.' && !(option & HIDDEN) && strcmp(entry->d_name, "..") ) + continue; + + menu = realloc(menu, ++nbitem * sizeof *menu); + + if (entry->d_type == DT_DIR) { + char* tmp = malloc( strlen(entry->d_name)+3); + sprintf(tmp, "[%s]", entry->d_name); + menu[nbitem-1].cstr = tmp; + menu[nbitem-1].opt = 1; + menu[nbitem-1].id = nbitem-1; + menu[nbitem-1].selected = 0; + } + else { + TagLib_File *file; + TagLib_Tag *tag; + const TagLib_AudioProperties *properties; + + file = taglib_file_new(entry->d_name); + + if(file == NULL) { + menu = realloc(menu, --nbitem * sizeof *menu); + continue; + } + + tag = taglib_file_tag(file); + properties = taglib_file_audioproperties(file); + + if( ! properties ) { + fprintf(stderr, "ID3 file but not audio"); + taglib_tag_free_strings(); + taglib_file_free(file); + } + menu[nbitem-1].cstr = strdup(entry->d_name); + menu[nbitem-1].opt = 0; + menu[nbitem-1].id = nbitem-1; + menu[nbitem-1].info = (tagInfo){file, tag, properties}; + menu[nbitem-1].selected = 0; + + } + } while (entry = readdir(dir)); +end: + + closedir(dir); + *m = menu; + *s = nbitem; +} + +void printfc(char* fstrc, int max_length, ...) { + int i = 0; + int nbC = 0; + char* tmp = NULL; + int toP = 0; + + + va_list ap; + va_start(ap, max_length); + + + while(fstrc[i] && nbC < max_length) { + if( strchr( "${<%>}#", fstrc[i]) ) { + if( tmp ) { + printw("%.*s", toP, tmp); + tmp=NULL; + toP=0; + } + switch( fstrc[i] ) { + case '$': + if( fstrc[i+1] ) { + if( isdigit(fstrc[i+1]) ) { + if( fstrc[i+1] == '9') { + ; + }else + attrset( COLOR_PAIR(fstrc[i+1]-'0') | A_NORMAL); + }else{ + fprintf(stderr,"%c isn't a color, skipping", fstrc[i+1]); + } + }else{ + fprintf(stderr,"end of line by '$', expect a color after '$'"); + return; + } + i+=2; + break; + case '%': + { + int j = 1; + char format[10] = "%"; + while(j < 9 && !strchr("diouxXeEfFgGaAcsp%", format[j] = fstrc[i+j]) ); + if( j == 9 ) { + fprintf(stderr,"format too long %s...",format); + return; + } + if( strchr("di", format[j] ) ) { + printw(format, va_arg(ap, int)); + }else if( strchr("ouxX", format[j]) ) { + printw(format, va_arg(ap, unsigned int)); + }else if( strchr("eE", format[j]) ) { + printw(format, va_arg(ap, double)); + }else if( strchr("fF", format[j]) ) { + printw(format, va_arg(ap, double)); + }else if( strchr("gG", format[j]) ) { + printw(format, va_arg(ap, double)); + }else if( strchr("aA", format[j]) ) { + printw(format, va_arg(ap, double)); + }else if( strchr("c", format[j]) ) { + printw(format, va_arg(ap, int)); + }else if( strchr("s", format[j]) ) { + printw(format, va_arg(ap, const char*)); + }else if( strchr("p", format[j]) ) { + printw(format, va_arg(ap, void*)); + }else if( strchr("%", format[j]) ) { + printw("%%"); + } +// nbC+= + + i+=j; + } + } + }else{ + if( ! tmp ) + tmp = fstrc+i; + toP += 1; + nbC++; + i++; + } + } + if(tmp) + printw("%.*s", toP, tmp); + fflush(NULL); +} + +void printc(char* fstrc, int max_length) { + int i = 0; + int nbC = 0; + char* tmp = NULL; + int toP = 0; + while(fstrc[i] && nbC < max_length) { + if( strchr( "${<>}#", fstrc[i]) ) { + if( tmp ) { + printw("%.*s", toP, tmp); + tmp=NULL; + toP=0; + } + switch( fstrc[i] ) { + case '$': + if( fstrc[i+1] ) { + if( isdigit(fstrc[i+1]) ) { + if( fstrc[i+1] == '9') { + ; + }else + attrset( COLOR_PAIR(fstrc[i+1]-'0') | A_NORMAL); + }else{ + fprintf(stderr,"%c isn't a color, skipping", fstrc[i+1]); + } + }else{ + fprintf(stderr,"end of line by '$', expect a color after '$'"); + return; + } + i+=2; + } + }else{ + if( ! tmp ) + tmp = fstrc+i; + toP += 1; + nbC++; + i++; + } + } + if(tmp) + printw("%.*s", toP, tmp); + fflush(NULL); +} +void mvprintc(int x, int y, char* fstrc, int max_length) { + move(y, x); + printc(fstrc, max_length); +} +#define mvprintfc( x, y, fstrc, max, ...) (move((y),(x)),printfc(fstrc, max, __VA_ARGS__ )) +void printTagInfoHeader() { + attrset( COLOR_PAIR( COLOR_BLUE + 1) | A_BOLD); + mvprintc(COLS/2+2, 1, "Title :",15); + mvprintc(COLS/2+2, 2, "Artist :",15); + mvprintc(COLS/2+2, 3, "Album :",15); + mvprintc(COLS/2+2, 4, "Year :",15); + mvprintc(COLS/2+2, 5, "Track :",15); + mvprintc(COLS/2+2, 6, "Genre :",15); + mvprintc(COLS/2+2, 7, "Comment :",15); + attrset( COLOR_PAIR( 0 ) | A_NORMAL); +} +void printTagInfo(menuC* menu) { + static int mustClear = 0; + if( mustClear == 1 ) { + int x = menu->x; + int y = menu->y; + int h = menu->h; + int w = menu->w; + + for(int i = 0 ; i < 8 ; i++) { + move(1+i,COLS/2+14); + printw("%*s", COLS/2-14, " "); + } + mustClear = 0; + } + itemC* it = menu->list+menu->hl; + if( !it->opt ) { + char inT[6] = ""; + mvprintc( COLS/2+14, 1, taglib_tag_title(it->info.tag), COLS/2-14); + mvprintc( COLS/2+14, 2, taglib_tag_artist(it->info.tag), COLS/2-14); + mvprintc( COLS/2+14, 3, taglib_tag_album (it->info.tag), COLS/2-14); + sprintf(inT, "%d", taglib_tag_year (it->info.tag)); + mvprintc( COLS/2+14, 4, inT, COLS/2-14); + sprintf(inT, "%d", taglib_tag_track(it->info.tag)); + mvprintc( COLS/2+14, 5, inT, COLS/2-14); + mvprintc( COLS/2+14, 6, taglib_tag_genre(it->info.tag), COLS/2-14); + mvprintc( COLS/2+14, 7, taglib_tag_comment(it->info.tag), COLS/2-14); + mustClear = 1; + } + + +} +void cleanmenu(menuC* menu) { + for(int i = menu->firstElem ; i < menu->h && i < menu->nbElem; i++) { + move(menu->y+i,menu->x); + printw("%*s", menu->w, " "); + } + refresh(); +} +void printmenu(menuC* menu) { + + int x = menu->x; + int y = menu->y; + int h = menu->h; + int w = menu->w; + itemC* it = menu->list; + int s = menu->nbElem; + + if( menu->hl < (menu->firstElem) ) { + cleanmenu(menu); + } + + if( menu->hl >= (menu->firstElem+menu->h ) ) { + attrset(0 | A_NORMAL ); + menu->firstElem+=menu->h/2; + for(int i = 0 ; i < h ; i++) { + move(y+i,x); + printw("%*s", w, " "); + } + refresh(); + } + + + for(int i = menu->firstElem ; i < (h+menu->firstElem) && i < s ; i++) { + int color = 0, attr = A_NORMAL; + if( it[i].opt == 1 ) + color = COLOR_BLUE+1; + if( i == menu->hl ) + attr = A_REVERSE; + if( it[i].selected ) { + attr |= A_BOLD; + } + + attrset( COLOR_PAIR(color) | attr); + move(y,x); + printw("%*s", w, " "); + mvprintc(x,y++,it[i].cstr, w); + attrset(0 | A_NORMAL); + } +} +void printStatus(void) { + mvprintc(COLS-5,LINES-3," ",4); + mvprintc(COLS-5,LINES-3,status,4); +} + + +static void init_readline(void) +{ + // Disable completion. TODO: Is there a more robust way to do this? + if (rl_bind_key('\t', rl_insert) != 0) + fail_exit("Invalid key passed to rl_bind_key()"); + + // Let ncurses do all terminal and signal handling + rl_catch_signals = 0; + rl_catch_sigwinch = 0; + rl_deprep_term_function = NULL; + rl_prep_term_function = NULL; + + // Prevent readline from setting the LINES and COLUMNS environment + // variables, which override dynamic size adjustments in ncurses. When + // using the alternate readline interface (as we do here), LINES and + // COLUMNS are not updated if the terminal is resized between two calls to + // rl_callback_read_char() (which is almost always the case). + rl_change_environment = 0; + + // Handle input by manually feeding characters to readline + rl_getc_function = readline_getc; + rl_input_available_hook = readline_input_avail; + rl_redisplay_function = readline_redisplay; + + rl_callback_handler_install("> ", got_command); +} +static void deinit_readline(void) +{ + rl_callback_handler_remove(); +} +static void resizeMain(menuC* menu) { + clear(); + menu->h = LINES-2; + menu->w = COLS/2-1; + printmenu(menu); + printTagInfoHeader(); + printTagInfo(menu); + printStatus(); + move(1,COLS/2); + vline( ACS_VLINE, LINES-2) ; +} +static void resize(void) +{ + if (LINES >= 3) { + CHECK(wresize, sep_win, 1, COLS); + CHECK(wresize, cmd_win, 1, COLS); + + CHECK(mvwin, sep_win, LINES - 2, 0); + CHECK(mvwin, cmd_win, LINES - 1, 0); + } + + // Batch refreshes and commit them with doupdate() + CHECK(wnoutrefresh, sep_win); + cmd_win_redisplay(true); + CHECK(doupdate); +} +void readline_n(void) { + curs_set(2); + resize(); + while (!should_exit) { + // Using getch() here instead would refresh stdscr, overwriting the + // initial contents of the other windows on startup + int c = wgetch(cmd_win); + + if( c == '\n') + should_exit = 1; + if (c == KEY_RESIZE) + resize(); + else if (c == '\f') { // Ctrl-L -- redraw screen. + // Makes the next refresh repaint the screen from scratch + CHECK(clearok, curscr, TRUE); + // Resize and reposition windows in case that got messed up + // somehow + resize(); + } + else + forward_to_readline(c); + } + should_exit = 0; +} +void edit_rl(menuC* menu,void func(TagLib_Tag *, const char*), int c) { + status[1]=c; + printStatus(); + refresh(); + curs_set(2); + move(LINES-1, 0); + readline_n(); + clear(); + curs_set(0); + itemC* it = menu->list+menu->hl; + if( msg_win_str) { + int selected = 0; + for(int i = 0 ; i < menu->nbElem ; i++) + if( menu->list[i].selected ) + selected = 1; + if( ! selected && ! it->opt ) { + mvprintc(20, 20, "H$1e$2l$3l$4o", 10); + func(it->info.tag, msg_win_str); + taglib_file_save(it->info.file); + }else{ + for(int i = 0 ; i < menu->nbElem ; i++) + if( menu->list[i].selected && !menu->list[i].opt ) { + func(menu->list[i].info.tag, msg_win_str); + taglib_file_save(menu->list[i].info.file); + } + } + } +} + +#define MAX_ERROR_MSG 0x1000 + +/* Compile the regular expression described by "regex_text" into + "r". */ + +static int compile_regex (regex_t * r, const char * regex_text) +{ + int status = regcomp (r, regex_text, REG_EXTENDED|REG_NEWLINE); + if (status != 0) { + char error_message[MAX_ERROR_MSG]; + regerror (status, r, error_message, MAX_ERROR_MSG); + printf ("Regex error compiling '%s': %s\n", + regex_text, error_message); + return 1; + } + return 0; +} + +/* + Match the string in "to_match" against the compiled regular + expression in "r". + */ +static int match_regex (const char* rS, const char * to_match, char* m2[], int nbR) +{ + regex_t* r = malloc(sizeof *r); + compile_regex(r, rS); + + fprintf(stderr, "%d - %d\n", nbR, r->re_nsub); + + if( nbR != r->re_nsub ) + return 0; + regmatch_t m[r->re_nsub]; + + /* "P" is a pointer into the string which points to the end of the + previous match. */ + /* "N_matches" is the maximum number of matches allowed. */ + /* "M" contains the matches found. */ + int rs = regexec (r, to_match /* if only 1 match, set it to to_match */, + r->re_nsub+1 /* nbMatch Max */, m /* res */, 0); + + // regexec(&re, line, 2, rm, 0) + fprintf(stderr,"<<%s>>\n", to_match); + fprintf(stderr,"Line: <<%.*s>>\n", (int)(m[0].rm_eo - m[0].rm_so), to_match + m[0].rm_so); + for(int i = 1 ; i < (r->re_nsub +1) ; i++) { + m2[i-1] = malloc( (unsigned int)(m[i].rm_eo - m[i].rm_so) + 1); + m2[i-1][m[i].rm_eo - m[i].rm_so] = 0; + strncpy(m2[i-1], to_match+m[i].rm_so, m[i].rm_eo - m[i].rm_so); + fprintf(stderr,"Text: <<%.*s>>\n", (int)(m[i].rm_eo - m[i].rm_so), to_match + m[i].rm_so); + } + + /* + { + if( !rs ) + free(r); + } + */ + return 1; + + /* + while (1) { + int i = 0; + int nomatch = regexec (r, p, n_matches, m, 0); + if (nomatch) { + printf ("No more matches.\n"); + return nomatch; + } + for (i = 0; i < n_matches; i++) { + int start; + int finish; + if (m[i].rm_so == -1) { + break; + } + start = m[i].rm_so + (p - to_match); + finish = m[i].rm_eo + (p - to_match); + if (i == 0) { + printf ("$& is "); + } + else { + printf ("$%d is ", i); + } + printf ("'%.*s' (bytes %d:%d)\n", (finish - start), + to_match + start, start, finish); + } + p += m[0].rm_eo; + } + return 0; + */ +} +void regexSelection(menuC* menu) { + status[1]='s'; +} +void regexXtract(itemC* it) { + status[1]='x'; + + readline_n(); + clear(); + curs_set(0); + char* tmp = strrchr( msg_win_str , '/' ); + if( !msg_win_str || !*msg_win_str || !tmp) { + return; + } + + char *regexS = malloc(tmp-msg_win_str+1); + + strncpy( regexS, msg_win_str, tmp-msg_win_str); + regexS[tmp - msg_win_str] = 0; + char* const line = it->cstr; + + char** tab = NULL; + tmp++; + int nbR = strlen(tmp); + tab = malloc( sizeof *tab * (nbR+1)); + if( match_regex(regexS, line, tab, nbR ) ) { + fprintf(stderr, "Hello"); + for(int i = 0 ; i < nbR ; i++) { + fprintf(stderr, "<<%s>>\n", tab[i]); + switch(tmp[i]) { + case 't': + taglib_tag_set_title(it->info.tag, tab[i]); + break; + case 'a': + taglib_tag_set_artist(it->info.tag, tab[i]); + break; + case 'b': + taglib_tag_set_album(it->info.tag, tab[i]); + break; + case 'y': + break; + case 'n': + break; + case 'g': + taglib_tag_set_genre(it->info.tag, tab[i]); + break; + case 'c': + taglib_tag_set_comment(it->info.tag, tab[i]); + break; + default: + ; + } + taglib_file_save(it->info.file); + } + } +} +void loadMenu(itemC** menuL, int* size) { + +} +int main(int argc, char* argv[]){ + itemC* menuL = NULL; + int size = 0; + int c; + int comp = 0; + + setlocale(LC_ALL, ""); + initscr(); + if (has_colors()) { + CHECK(start_color); + } + CHECK(cbreak); + CHECK(noecho); + CHECK(nonl); + CHECK(intrflush, NULL, FALSE); + visual_mode = true; + taglib_set_strings_unicode(1); + curs_set(0); + + cmd_win = newwin(1, COLS, LINES - 20, 0); + sep_win = newwin(1, COLS, LINES - 2, 0); + + init_pair( 12, COLOR_WHITE, COLOR_BLUE); + CHECK(wbkgd, sep_win, COLOR_PAIR(12)); + CHECK(wrefresh, sep_win); + init_readline(); + + for(int i = 0 ; i < 9 ; i++) { + init_pair( i+1, i, COLOR_BLACK); + } + + if( !argv[1] ) { + listdir(0, &menuL, &size); + } else { + chdir(argv[1]); + listdir(0,&menuL, &size); + puts(argv[1]); + } + qsort(menuL, size, sizeof *menuL, sort_i); + + menuC menu = (menuC) { menuL, size, 0, 0, 0, NULL, NULL, 1, 1, COLS/2-1, LINES-2}; + + + + printmenu(&menu); + printTagInfoHeader(); + move(1,COLS/2); + vline( ACS_VLINE, LINES-2) ; + + + while( c = getch() ) { + if (c == KEY_RESIZE) { + resizeMain(&menu); + continue; + } + switch( comp ) { + case 0: + switch (c) { + case KEY_SF: + case 'j': + if( menu.hl < menu.nbElem-1 ) + menu.hl++; + printTagInfo(&menu); + break; + case KEY_SR: + case 'k': + if( menu.hl > 0) + menu.hl--; + printTagInfo(&menu); + break; + case KEY_SLEFT: + break; + case KEY_SRIGHT: + break; + case 'e': + if( !status[0] ) { + status[0] = 'e'; + comp = 'e'; + }else{ + status[0] = 0; + } + break; + case ' ': + menu.list[menu.hl].selected = !menu.list[menu.hl].selected; + break; + case 's': + regexSelection(&menu); + break; + case 'x': + regexXtract(&menu.list[menu.hl]); + resizeMain(&menu); + break; + case 'q': + goto end; + case '\r': + if( menu.list[menu.hl].opt ) { + int n = strlen(menu.list[menu.hl].cstr+1); + char* s = menu.list[menu.hl].cstr+1; + s[n-1] = 0; + chdir(s); + s[n-1] = ']'; + cleanmenu(&menu); + + listdir(0,&menuL, &size); + qsort(menuL, size, sizeof *menuL, sort_i); + menu.list = menuL; + menu.nbElem = size; + menu.hl = 0; + } + default:; +// fprintf(stderr, "[%c]", c); + } + break; + case 'e': + echo(); + move(LINES-1,1); + switch(c) { + case 't': + edit_rl(&menu,taglib_tag_set_title,'t'); + break; + case 'a': + edit_rl(&menu,taglib_tag_set_artist,'a'); + break; + case 'b': + edit_rl(&menu,taglib_tag_set_album,'b'); + break; + case 'y': + break; + case 'n': + break; + case 'g': + edit_rl(&menu,taglib_tag_set_genre,'g'); + break; + case 'c': + edit_rl(&menu,taglib_tag_set_comment,'c'); + break; + default: + ; + } + comp = 0; + status[0] = status[1] = 0; + + printmenu(&menu); + printTagInfoHeader(); + printTagInfo(&menu); + break; + } + printStatus(); + printmenu(&menu); + move(1,COLS/2); + vline( ACS_VLINE, LINES-2) ; + refresh(); + } + + refresh(); + getch(); +end: + endwin(); + + return 0; +} + + + -- cgit v1.2.3