aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorache <ache@ache.one>2017-05-27 18:38:45 +0200
committerache <ache@ache.one>2017-05-27 18:38:45 +0200
commit3889e10610da7915544d8ad865b2f9385c6dc383 (patch)
tree87a8ec3fb8b7b999d52a4a491e6b31a48ab09f14
parentInit commit (diff)
New files
-rw-r--r--basic_curses.c132
-rw-r--r--basic_curses.h15
-rwxr-xr-xh.c760
-rw-r--r--item.c101
-rw-r--r--item.h13
-rw-r--r--main.h79
-rw-r--r--readline.c198
-rw-r--r--readline.h27
-rw-r--r--regex.c151
-rw-r--r--regex.h17
-rw-r--r--wind.c147
-rw-r--r--wind.h24
12 files changed, 928 insertions, 736 deletions
diff --git a/basic_curses.c b/basic_curses.c
new file mode 100644
index 0000000..ce6a338
--- /dev/null
+++ b/basic_curses.c
@@ -0,0 +1,132 @@
+#include "basic_curses.h"
+
+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);
+}
+
+
diff --git a/basic_curses.h b/basic_curses.h
new file mode 100644
index 0000000..00be967
--- /dev/null
+++ b/basic_curses.h
@@ -0,0 +1,15 @@
+
+#ifndef BASIC_CURSES_H
+#define BASIC_CURSES_H
+
+#include "main.h"
+
+void printfc(char* fstrc, int max_length, ...);
+
+void printc(char* fstrc, int max_length);
+void mvprintc(int x, int y, char* fstrc, int max_length);
+
+
+#define mvprintfc( x, y, fstrc, max, ...) (move((y),(x)),printfc(fstrc, max, __VA_ARGS__ ))
+
+#endif
diff --git a/h.c b/h.c
index c40af47..bf7f9e4 100755
--- a/h.c
+++ b/h.c
@@ -1,21 +1,18 @@
-#define _DEFAULT_SOURCE
-#define _XOPEN_SOURCE 700 // For strnlen()
-#include<stdio.h>
-#include<stdlib.h>
-#include<string.h>
-#include<ctype.h>
-#include <ncurses.h>
+
+
+#include "main.h"
+#include "regex.h"
+#include "readline.h"
+
#include <dirent.h>
-#include <locale.h>
-#include <taglib/tag_c.h>
-#include <readline/history.h>
-#include <readline/readline.h>
#include <stdnoreturn.h>
#include <wchar.h>
#include <wctype.h>
-#include <regex.h>
#include <unistd.h>
+#include "item.h"
+#include "wind.h"
+
#ifdef DEBUG
@@ -23,604 +20,37 @@
#endif
+const int color[] = {
+ COLOR_BLACK, COLOR_RED,
+ COLOR_GREEN, COLOR_YELLOW, COLOR_BLUE,
+ COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE};
-#define MAX_PATH 1024
-
-#define max(a, b) \
- ({ typeof(a) _a = a; \
- typeof(b) _b = b; \
- _a > _b ? _a : _b; })
+#define MAX_PATH 1024
+extern char* msg_win_str;
-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;
-
+WINDOW *cmd_win;
+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 ~<letter> 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.
+void fail_exit(const char *msg) {
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();
@@ -650,152 +80,6 @@ void edit_rl(menuC* menu,void func(TagLib_Tag *, const char*), int c) {
}
}
-#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;
@@ -882,10 +166,13 @@ int main(int argc, char* argv[]){
menu.list[menu.hl].selected = !menu.list[menu.hl].selected;
break;
case 's':
- regexSelection(&menu);
+ prepare("xs");
+ regexSelection(&menu,msg_win_str);
+ resizeMain(&menu);
break;
case 'x':
- regexXtract(&menu.list[menu.hl]);
+ prepare("x");
+ regexXtract(&menu.list[menu.hl], msg_win_str);
resizeMain(&menu);
break;
case 'q':
@@ -899,6 +186,7 @@ int main(int argc, char* argv[]){
s[n-1] = ']';
cleanmenu(&menu);
+ freelitem(menuL, size);
listdir(0,&menuL, &size);
qsort(menuL, size, sizeof *menuL, sort_i);
menu.list = menuL;
diff --git a/item.c b/item.c
new file mode 100644
index 0000000..b7dc18e
--- /dev/null
+++ b/item.c
@@ -0,0 +1,101 @@
+#include "item.h"
+
+
+
+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 freelitem( itemC* m, int s) {
+ for(int i = 0 ; i < s ; i++) {
+ free(m[i].cstr);
+ if( !m[i].opt) {
+ taglib_file_free(m[i].info.file);
+ }
+ }
+
+ taglib_tag_free_strings();
+ free(m);
+}
+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;
+
+// QUICK FIX OF TAGLIB
+ if( strchr(entry->d_name, '#') )
+ continue;
+#ifdef DEBUG
+ mvprintc(1,1,entry->d_name,COLS/2-5);
+#endif
+
+ refresh();
+
+// fprintf(stderr, "%s\n", entry->d_name);
+ 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].opt = 2;
+ }else{
+ menu[nbitem-1].opt = 0;
+ }
+ menu[nbitem-1].cstr = strdup(entry->d_name);
+ 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;
+}
+
+
diff --git a/item.h b/item.h
new file mode 100644
index 0000000..b27714f
--- /dev/null
+++ b/item.h
@@ -0,0 +1,13 @@
+
+#ifndef ITEM_METAG_H
+#define ITEM_METAG_H
+
+#include "main.h"
+#include <dirent.h>
+
+
+int sort_i(const void* A, const void* B);
+void freelitem( itemC* m, int s);
+void listdir(int option, itemC** m, int* s);
+
+#endif
diff --git a/main.h b/main.h
new file mode 100644
index 0000000..9f272ec
--- /dev/null
+++ b/main.h
@@ -0,0 +1,79 @@
+
+#ifndef MAIN_METAG_H
+#define MAIN_METAG_H
+
+#ifndef _DEFAULT_SOURCE
+#define _DEFAULT_SOURCE
+#endif
+
+#ifndef _XOPEN_SOURCE
+#define _XOPEN_SOURCE 700 // For strnlen()
+#endif
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <ncurses.h>
+#include <taglib/tag_c.h>
+
+
+
+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
+
+void printStatus(void);
+
+void resize(void);
+
+
+void fail_exit(const char *msg);
+
+
+
+// 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)
+
+
+#define max(a, b) \
+ ({ typeof(a) _a = a; \
+ typeof(b) _b = b; \
+ _a > _b ? _a : _b; })
+
+
+
+
+#endif
diff --git a/readline.c b/readline.c
new file mode 100644
index 0000000..176657d
--- /dev/null
+++ b/readline.c
@@ -0,0 +1,198 @@
+
+#include "readline.h"
+
+
+
+static bool input_avail = false;
+static unsigned char input;
+static bool should_exit = false;
+char *msg_win_str = NULL;
+extern WINDOW *cmd_win;
+
+
+// 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 ~<letter> 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);
+}
+
+
+// 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;
+}
+
+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 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);
+}
+
+
+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;
+}
+
+
+
diff --git a/readline.h b/readline.h
new file mode 100644
index 0000000..cf96e11
--- /dev/null
+++ b/readline.h
@@ -0,0 +1,27 @@
+
+#ifndef READLINE_METAG_H
+#define READLINE_METAG_H
+
+#include "main.h"
+#include <stdio.h>
+#include <wchar.h>
+#include <locale.h>
+#include <wctype.h>
+#include <unistd.h>
+#include <readline/history.h>
+#include <readline/readline.h>
+
+
+
+
+
+void readline_n(void);
+
+void init_readline(void);
+
+void cmd_win_redisplay(bool for_resize);
+
+void deinit_readline(void);
+
+#endif
+
diff --git a/regex.c b/regex.c
new file mode 100644
index 0000000..b7f19aa
--- /dev/null
+++ b/regex.c
@@ -0,0 +1,151 @@
+#include "regex.h"
+
+
+#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 && nbR > 0)
+ return 0;
+ regmatch_t m[r->re_nsub+1];
+
+ /* "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 */,
+ nbR > 0 ? r->re_nsub+1: 0 /* nbMatch Max */, m /* res */, 0);
+
+ // regexec(&re, line, 2, rm, 0)
+ if( !rs ) {
+ 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);
+ }
+
+ if( m2 )
+ 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);
+ }
+ return !rs;
+
+ /*
+ {
+ 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, const char* msg) {
+ for(int i = 0 ; i < menu->nbElem ; i++ ) {
+ if( match_regex(msg, menu->list[i].cstr, NULL, -1 ) ) {
+ menu->list[i].selected = 1;
+ }
+ }
+}
+void regexXtract(itemC* it, const char* msg) {
+ char* tmp = strrchr( msg , '/' );
+ if( !msg || !*msg || !tmp) {
+ return;
+ }
+
+ char *regexS = malloc(tmp-msg+1);
+
+ strncpy( regexS, msg, tmp-msg);
+ regexS[tmp - msg] = 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);
+ }
+ }
+}
+
diff --git a/regex.h b/regex.h
new file mode 100644
index 0000000..752f17b
--- /dev/null
+++ b/regex.h
@@ -0,0 +1,17 @@
+
+#ifndef REGEX_METAG_H
+#define REGEX_METAG_H
+
+
+#include <regex.h>
+#include "main.h"
+
+static int compile_regex (regex_t * r, const char * regex_text);
+static int match_regex (const char* rS, const char * to_match, char* m2[], int nbR);
+
+
+void regexXtract(itemC* it, const char* str);
+void regexSelection(menuC* menu, const char* msg);
+
+#endif
+
diff --git a/wind.c b/wind.c
new file mode 100644
index 0000000..a09fdce
--- /dev/null
+++ b/wind.c
@@ -0,0 +1,147 @@
+
+#include "wind.h"
+
+
+
+static short my_fg = COLOR_WHITE;
+static short my_bg = COLOR_BLACK;
+extern char status[10];
+extern WINDOW *cmd_win;
+extern WINDOW *sep_win;
+
+
+void prepare(char* s) {
+ refresh();
+ strcpy(status, s);
+ printStatus();
+ readline_n();
+ clear();
+ curs_set(0);
+}
+
+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) ) {
+ menu->firstElem-=menu->h/2;
+ if( menu->firstElem < 0 )
+ menu->firstElem = 0;
+
+ cleanmenu(menu);
+ }
+
+ if( menu->hl >= (menu->firstElem+menu->h ) ) {
+ attrset(0 | A_NORMAL );
+ menu->firstElem+=menu->h/2;
+ if( menu-> firstElem > menu->nbElem )
+ menu-> firstElem = menu->nbElem;
+ cleanmenu(menu);
+ }
+
+
+ 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);
+}
+
+
+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 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) ;
+}
+
diff --git a/wind.h b/wind.h
new file mode 100644
index 0000000..63fed9c
--- /dev/null
+++ b/wind.h
@@ -0,0 +1,24 @@
+
+#ifndef WIND_METAG_H
+#define WIND_METAG_H
+
+#include "main.h"
+#include "readline.h"
+#include "basic_curses.h"
+
+
+void printTagInfoHeader();
+
+void printTagInfo(menuC* menu);
+
+void cleanmenu(menuC* menu);
+
+void printmenu(menuC* menu);
+
+void printStatus(void);
+
+void prepare(char* s);
+
+void resize(void);
+void resizeMain(menuC* menu);
+#endif