/* 2004.02.01 first released source code for IOMP */ #include #include #include #include #include #include #include #include #include #include #include "../config.h" #include "../m_struct.h" #include "../m_option.h" #include "img_format.h" #include "mp_image.h" #include "menu.h" #include "menu_list.h" #include "../input/input.h" #include "../linux/keycodes.h" #define DEBUG0(x) printf x static char *THIS_PARTITION = "This Partition"; static char *ROOT = NULL; // Mode 0: MP3 & directory selection // Mode 1: mpg, mpeg, avi file selection #define MP3_MODE 0 #define MPGAVI_MODE 1 static int Avamax_Mode = MP3_MODE; #define FILE_SEL_ONLY 0 #define FOLDER_SEL_ONLY 1 #define BOTH_SEL_ONLY 2 static int Selection_Mode = FILE_SEL_ONLY; struct list_entry_s { struct list_entry p; int d; int child; }; struct menu_priv_s { menu_list_priv_t p; char* dir; // current dir /// Cfg fields char* path; char* title; char* file_action; char* dir_action; int auto_close; int mode; }; static struct menu_priv_s cfg_dflt = { MENU_LIST_PRIV_DFLT, NULL, NULL, "Select a directory: %p", "loadfile '%p'", NULL, 0 }; #define ST_OFF(m) M_ST_OFF(struct menu_priv_s,m) static m_option_t cfg_fields[] = { MENU_LIST_PRIV_FIELDS, { "path", ST_OFF(path), CONF_TYPE_STRING, 0, 0, 0, NULL }, { "title", ST_OFF(title), CONF_TYPE_STRING, 0, 0, 0, NULL }, { "file-action", ST_OFF(file_action), CONF_TYPE_STRING, 0, 0, 0, NULL }, { "dir-action", ST_OFF(dir_action), CONF_TYPE_STRING, 0, 0, 0, NULL }, { "auto-close", ST_OFF(auto_close), CONF_TYPE_FLAG, 0, 0, 1, NULL }, { "mode", ST_OFF(mode), CONF_TYPE_INT, 0, 10, 0, NULL }, { NULL, NULL, NULL, 0,0,0,NULL } }; #define mpriv (menu->priv) static void free_entry(list_entry_t* entry) { free(entry->p.txt); free(entry); } static char* replace_path(char* title , char* dir) { char *p = strstr(title,"%p"); if(p) { int tl = strlen(title); int dl = strlen(dir); int t1l = p-title; int l = tl - 2 + dl; char*r = malloc(l + 1); memcpy(r,title,t1l); memcpy(r+t1l,dir,dl); if(tl - t1l - 2 > 0) memcpy(r+t1l+dl,p+2,tl - t1l - 2); r[l] = '\0'; return r; } else return title; } typedef int (*kill_warn)(const void*, const void*); static int mylstat(char *dir, char *file,struct stat* st) { int l = strlen(dir) + strlen(file); char s[l+2]; sprintf(s,"%s/%s",dir,file); printf("mylstat %s\n",s); return lstat(s,st); } static int compare(char **a, char **b){ int la,lb; la = strlen(*a); lb = strlen(*b); if((*a)[strlen(*a) - 1] == '/') { if((*b)[strlen(*b) - 1] == '/') return strcmp(*b, *a) ; else return 1; } else { if((*b)[strlen(*b) - 1] == '/') return -1; else return strcmp(*b, *a); } } static int MatchExtName(char *ptr) { if (ptr) { switch (Avamax_Mode) { case 0: { if (strcasecmp(ptr,".mp3") == 0) { return 1; } } break; case 1: { if ((strcasecmp(ptr,".mpg") == 0) || (strcasecmp(ptr,".avi") == 0) || (strcasecmp(ptr,".mpeg") == 0)) { return 1; } } break; } } return 0; } static int NumberOfSubdir(char *path,int mode) // mode=1:anthing,0:dir-only { struct dirent *dp; DIR *dirp; struct stat st; int n = 0; char *tempdir; DEBUG0(("Number of Subdir [%s] mode=%d\n",path,mode)); if (ROOT) { tempdir = (char *) malloc(strlen(ROOT) + strlen(path) + 2); sprintf(tempdir,"%s%s",ROOT,path); } else { tempdir = strdup(path); } if ((dirp = opendir (tempdir)) == NULL){ DEBUG0(("opendir error: %s", strerror(errno))); return 0; } while ((dp = readdir(dirp)) != NULL) { if(dp->d_name[0] == '.') continue; if (strcmp(dp->d_name,"..") == 0) continue; if (mode == 1) { n++; break; } mylstat(tempdir,dp->d_name,&st); if(S_ISDIR(st.st_mode)) { n++; break; } } free(tempdir); closedir(dirp); return n; } static void AppendTail(char *src,char *ptr) { int len,flag; char *chtr; flag = 0; len = strlen(src); chtr = strrchr(src,'/'); if (chtr && (*(chtr+1) == 0)) { // Is a Directory if (*ptr) { strcpy((char *) ptr,".../"); flag = 1; } } else { chtr = strrchr(src,'.'); if (chtr) { if ((strcasecmp(chtr,".mp3") == 0) || (strcasecmp(chtr,".mpg") == 0) || (strcasecmp(chtr,".avi") == 0)) { if (*ptr) { sprintf((char *) ptr,"...%s",chtr); flag = 1; } } } } if ((*ptr) && (flag == 0)) { strcpy((char *) ptr,"..."); } } static char *TruncateNameTail(char *src) { static unsigned char result[70]; strncpy((char *) result,src,63); unsigned char *ptr = (unsigned char *) result; while (*ptr) { if (*ptr >= 0xa1) ptr++; // Big-5 首碼在 161 (\241, 0xA1) 到 254 (\376,0xFE) 之間. // 次碼在 64 (\100, 0x40) 到 126 (\176, 0x7E) 之間, // 或是與首碼相同的 161 (\241, 0xA1) 到 254 (\376, 0xFE) 之間 ptr++; if (ptr - result > 31) break; } AppendTail(src,ptr); return (char *) result; } static char *TruncateNameMiddle(char *src) { static unsigned char result[70]; if (strlen(src) > 30) { unsigned char *ptr = src; unsigned char *ptr1; unsigned char old; while (*ptr) { if (*ptr >= 0xa1) ptr++; ptr++; if ((ptr - (unsigned char *) src) > 15) break; } ptr1 = ptr; while (*ptr) { if (*ptr >= 0xa1) ptr++; ptr++; if (strlen(ptr) < 15) break; } old = *ptr1; *ptr1 = 0; sprintf(result,"%s...%s",src,ptr); *ptr1 = old; } else { strcpy(result,src); } return (char *) result; } static char *TruncateNameFront(char *src) { static unsigned char result[70]; if (strlen(src) > 30) { unsigned char *ptr = src; while (*ptr) { if (*ptr >= 0xa1) ptr++; ptr++; if (strlen(ptr) < 30) break; } sprintf(result,"...%s",ptr); } else { strcpy(result,src); } return (char *) result; } static char *TruncateName(char *src) { return TruncateNameTail(src); } static int open_dir(menu_t* menu,char* args) { char **namelist, **tp; struct dirent *dp; struct stat st; int n; char* p = NULL; list_entry_t* e; DIR* dirp; int IsTop = 0; char *tempdir = NULL; menu_list_init(menu); if (strcmp(args,"/") == 0) { IsTop = 1; } if(mpriv->dir) free(mpriv->dir); mpriv->dir = strdup(args); if(mpriv->p.title && mpriv->p.title != mpriv->title && mpriv->p.title != cfg_dflt.p.title) free(mpriv->p.title); p = strstr(mpriv->title,"%p"); if (strlen(mpriv->dir) > 30) { char *str1 = strdup(mpriv->dir); char *ptr = strrchr(str1,'/'); char *ptr1; if (*ptr) { *ptr = 0; ptr1 = strrchr(str1,'/'); char *temp = (char *) malloc(strlen(ptr1) + 6); sprintf(temp,"...%s/",TruncateName(ptr1)); mpriv->p.title = replace_path(mpriv->title,temp); free(temp); } else { mpriv->p.title = replace_path(mpriv->title,mpriv->dir); } free(str1); } else { mpriv->p.title = replace_path(mpriv->title,mpriv->dir); } if (ROOT) { tempdir = (char *) malloc(strlen(ROOT) + strlen(mpriv->dir) + 2); sprintf(tempdir,"%s%s",ROOT,mpriv->dir); } else { tempdir = strdup(mpriv->dir); } printf("open_linux_dir [%s]\n",args); if ((dirp = opendir (tempdir)) == NULL){ printf("opendir error: %s", strerror(errno)); return 0; } namelist = (char **) malloc(sizeof(char *)); n=0; while ((dp = readdir(dirp)) != NULL) { if(dp->d_name[0] == '.' && strcmp(dp->d_name,"..") != 0) continue; if(n%20 == 0){ // Get some more mem if((tp = (char **) realloc(namelist, (n+20) * sizeof (char *))) == NULL) { printf("realloc error: %s", strerror(errno)); n--; goto bailout; } namelist=tp; } namelist[n] = (char *) malloc(strlen(dp->d_name) + 2); if(namelist[n] == NULL){ printf("malloc error: %s", strerror(errno)); n--; goto bailout; } strcpy(namelist[n], dp->d_name); mylstat(tempdir,namelist[n],&st); if (S_ISDIR(st.st_mode)) { strcat(namelist[n], "/"); n++; } else if (S_ISREG(st.st_mode)) { char *ptr = strrchr(dp->d_name,'.'); if (MatchExtName(ptr)) { n++; } } } bailout: qsort(namelist, n, sizeof(char *), (kill_warn)compare); free(tempdir); if (n < 0) { printf("readdir error: %s\n",strerror(errno)); return 0; } while(n--) { e = calloc(1,sizeof(list_entry_t)); e->p.dirtxt = NULL; e->d = 0; e->p.next = NULL; if ((strcmp(namelist[n],"../") == 0) && (IsTop == 1)) { e->p.txt = strdup(THIS_PARTITION); e->d = 2; } else { e->p.txt = strdup(TruncateName(namelist[n])); e->p.dirtxt = strdup(namelist[n]); if(strchr(namelist[n], '/') != NULL) e->d = 1; } e->child = -1; menu_list_add_entry(menu,e); free(namelist[n]); } free(namelist); return 1; } static void read_cmd(menu_t* menu,int cmd) { mp_cmd_t* c = NULL; switch(cmd) { case MENU_CMD_CANCEL: { My_SendMessage("OPENDIR_ERROR",150); } break; case MENU_CMD_CHOICE: { char filename[512]; if (mpriv->p.current->d == 1) { if ((Selection_Mode == FOLDER_SEL_ONLY) || (Selection_Mode == BOTH_SEL_ONLY)) { sprintf(filename,"SELECTDIR %s%s", mpriv->dir,mpriv->p.current->p.dirtxt); My_SendMessage(filename,150); } } else if(mpriv->p.current->d == 2) { if ((Selection_Mode == FOLDER_SEL_ONLY) || (Selection_Mode == BOTH_SEL_ONLY)) { strcpy(filename,"SELECTDIR /"); My_SendMessage(filename,150); } } else if (mpriv->p.current->d == 0) { sprintf(filename,"SELECTFILE %s%s", mpriv->dir,mpriv->p.current->p.dirtxt); My_SendMessage(filename,150); } } break; case MENU_CMD_OK: { printf(" MENU_CMD_OK....\n"); // Directory if(mpriv->p.current->d) { if(mpriv->dir_action) { int fname_len = strlen(mpriv->dir) + strlen(mpriv->p.current->p.txt) + 1; char filename[fname_len]; char* str; sprintf(filename,"%s%s",mpriv->dir,mpriv->p.current->p.dirtxt); str = replace_path(mpriv->dir_action,filename); c = mp_input_parse_cmd(str); if(str != mpriv->dir_action) free(str); } else { // Default action : open this dirctory ourself printf(" MENU_CMD_OK....1111111\n"); int l = strlen(mpriv->dir); char *slash = NULL, *p = NULL; if(strcmp(mpriv->p.current->p.txt,THIS_PARTITION) == 0) { char filename[32]; strcpy(filename,"SELECTDIR /"); My_SendMessage(filename,150); } else { printf(" MENU_CMD_OK....222222\n"); if(strcmp(mpriv->p.current->p.txt,"../") == 0) { if(l <= 1) break; mpriv->dir[l-1] = '\0'; slash = strrchr(mpriv->dir,'/'); if(!slash) break; slash[1] = '\0'; p = strdup(mpriv->dir); } else { p = malloc(l + strlen(mpriv->p.current->p.txt) + 1); sprintf(p,"%s%s",mpriv->dir,mpriv->p.current->p.txt); } if (mpriv->p.current->child == -1) { mpriv->p.current->child = NumberOfSubdir(p, (Selection_Mode == FOLDER_SEL_ONLY) ? 0 : 1); } printf(" MENU_CMD_OK....%s child=%d\n",p,mpriv->p.current->child); if (mpriv->p.current->child > 0) { menu_list_uninit(menu,free_entry); printf("Call open_dir\n"); if(!open_dir(menu,p)) { printf("Can't open directory %s\n",p); menu->cl = 1; My_SendMessage("OPENDIR_ERROR",150); } } free(p); } } } else { // Files char *filename; filename = (char *) malloc(strlen(mpriv->dir) + strlen(mpriv->p.current->p.dirtxt) + 20); sprintf(filename,"SELECTFILE %s%s", mpriv->dir,mpriv->p.current->p.dirtxt); My_SendMessage(filename,150); free(filename); } if(c) { mp_input_queue_cmd(c); if(mpriv->auto_close) menu->cl = 1; } } break; default: menu_list_read_cmd(menu,cmd); } } static void read_key(menu_t* menu,int c){ if(c == KEY_BS) { mpriv->p.current = mpriv->p.menu; // Hack : we consider that the first entry is ../ read_cmd(menu,MENU_CMD_OK); } else menu_list_read_key(menu,c,1); } static void clos(menu_t* menu) { menu_list_uninit(menu,free_entry); free(mpriv->dir); } static int open_fs(menu_t* menu, char* args) { char *path = mpriv->path; int r = 0; char wd[PATH_MAX+1]; args = NULL; // Warning kill Avamax_Mode = mpriv->mode; switch (Avamax_Mode) { case 0: { // MP3 + Dir Selection_Mode = BOTH_SEL_ONLY; } break; case 1: { // MPG/AVI Selection_Mode = FILE_SEL_ONLY; } break; } menu->draw = menu_list_draw; menu->read_cmd = read_cmd; menu->read_key = read_key; menu->close = clos; printf("menu_file open_fs:%s\n",path); getcwd(wd,PATH_MAX); if(!path || path[0] == '\0') { int l = strlen(wd) + 2; char b[l]; sprintf(b,"%s/",wd); r = open_dir(menu,b); } else if(path[0] != '/') { int al = strlen(path); int l = strlen(wd) + al + 3; char b[l]; if(b[al-1] != '/') sprintf(b,"%s/%s/",wd,path); else sprintf(b,"%s/%s",wd,path); r = open_dir(menu,b); } else { ROOT = strdup(path); ROOT[strlen(ROOT)-1] = 0; r = open_dir(menu,"/"); } if (r == 0) My_SendMessage("OPENDIR_ERROR",150); return r; } const menu_info_t menu_info_filesel = { "File seletor menu", "filesel", "Albeu", "", { "fs_cfg", sizeof(struct menu_priv_s), &cfg_dflt, cfg_fields }, open_fs };