/* files.c */ #include "ml.h" Widget append_shell; Menu dir_option_menu[] = { { NULL, "hide_dot", NUL_TERM, dir_hide_dot, NULL, 0, NULL, NULL, BTN_HIDEDOT }, { NULL, "show_dot", NUL_TERM, dir_show_dot, NULL, 0, NULL, NULL, BTN_NOHIDEDOT }, }; Menu dir_menu[] = { { NULL, "accept", NUL_TERM, dir_accept, NULL, 0, NULL, NULL, BTN_ON }, { NULL, "cancel", NUL_TERM, dir_cancel, NULL, 0, NULL, NULL, BTN_ON }, { NULL, "option_menu", NUL_TERM, NULL, dir_option_menu, XtNumber(dir_option_menu), NULL, NULL, BTN_ON }, { NULL, "dir_HELP", NUL_TERM, dir_help, NULL, 0, NULL, NULL, BTN_ON }, }; Menu append_menu[] = { { NULL, "cancel", NUL_TERM, append_cancel, NULL, 0, NULL, NULL, BTN_ON }, { NULL, "overwrite", NUL_TERM, append_overwrite, NULL, 0, NULL, NULL, BTN_ON }, { NULL, "append", NUL_TERM, append_append, NULL, 0, NULL, NULL, BTN_ON }, { NULL, "append_HELP", NUL_TERM, append_help, NULL, 0, NULL, NULL, BTN_ON }, }; #ifdef __STDC__ Dir_Struct *new_dir_struct(void) #else Dir_Struct *new_dir_struct() #endif { Dir_Struct *dir_struct = (Dir_Struct *) fs_get(sizeof(Dir_Struct)); dir_struct->name = NULL; dir_struct->directory = FALSE; dir_struct->next = NULL; return(dir_struct); } #ifdef __STDC__ void free_dir_structs(Dir_Struct *dir_struct) #else void free_dir_structs(dir_struct) Dir_Struct *dir_struct; #endif { if(dir_struct == NULL) return; free_dir_structs(dir_struct->next); if(dir_struct->name) fs_give((void **) &dir_struct->name); fs_give((void **) &dir_struct); return; } #ifdef __STDC__ char *file_select(Widget w, char *initial_dir, char *initial_pattern, char *initial_file, Boolean op_write, Boolean *op_append) #else char *file_select(w,initial_dir,initial_pattern,initial_file, op_write,op_append) Widget w; char *initial_dir; char *initial_pattern; char *initial_file; Boolean op_write; Boolean *op_append; #endif { Arg args[ARGLISTSIZE]; int n = 0; XtTranslations translations; char *filename = NULL; int append_mode; Dirview *dirview; Widget form, menubar, label1, label2; set_watch_cursors(); dirview = (Dirview *) fs_get(sizeof(Dirview)); dirview->done = 0; dirview->recurse = 0; dirview->ignore_dot = TRUE; dirview->button_state = BTN_HIDEDOT; /* * Preliminary preposterous position. We'll move it later. * We don't want it flashing elsewhere on the screen * because we're gonna' move it soon, and it has to be * realized before we can find out if it will fit where * we want it. Jumping widgets probably aren't Politically Correct. */ XtSetArg(args[n], XmNx, -1000); n ++; XtSetArg(args[n], XmNy, -1000); n ++; XtSetArg (args[n], XmNdeleteResponse, XmDO_NOTHING); n++; dirview->shell = XtCreatePopupShell("fileselect", topLevelShellWidgetClass, w, args, n ); AddDestroyCallback (dirview->shell); n = 0; setup_editres(dirview->shell); if(pirate_icon != (Pixmap) None) XtVaSetValues(dirview->shell, XmNiconPixmap,pirate_icon, NULL); form = XmCreateForm(dirview->shell, "form", args, n); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n ++; menubar = XmCreateMenuBar(form,"menubar", args, n); n = 0; XtManageChild(menubar); create_buttons(NULL, menubar, dir_menu, XtNumber(dir_menu), BTN_ON, (XtPointer) dirview, ROOTMENULEVEL); if(initial_dir) dirview->cwd = cpystr(initial_dir); else { if(session->last_dir != NULL) dirview->cwd = cpystr(session->last_dir); else dirview->cwd = cpystr(local_auth.homedir); } dirview->dir_struct = NULL; dirview->dir_path = create_text_field(form, menubar, "directory", dirview->cwd, 0, (XtPointer) dir_dir_enter, (XtPointer) dirview); dirview->dir_pattern = create_text_field(form, dirview->dir_path, "pattern", (initial_pattern) ? initial_pattern : preferences.default_file_pattern, 0, (XtPointer) dir_select_filter, (XtPointer) dirview); dirview->dir_file = create_text_field(form,dirview->dir_pattern, "filename", initial_file, 0, (XtPointer) dir_accept, (XtPointer) dirview ); XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET ); n ++; XtSetArg(args[n], XmNtopWidget, dirview->dir_file ); n ++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM ); n ++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION ); n ++; XtSetArg(args[n], XmNrightPosition, 50 ); n ++; XtSetArg(args[n], XmNborderWidth, 0 ); n ++; label1 = XmCreateLabel(form, "directories_lbl", args, n); n = 0; XtManageChild(label1); XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET ); n ++; XtSetArg(args[n], XmNtopWidget, dirview->dir_file ); n ++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION ); n ++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM ); n ++; XtSetArg(args[n], XmNleftPosition, 50 ); n ++; XtSetArg(args[n], XmNborderWidth, 0 ); n ++; label2 = XmCreateLabel(form, "files_lbl", args, n); n = 0; XtManageChild(label2); XtSetArg(args[n], XmNscrollBarDisplayPolicy, XmSTATIC); n ++; XtSetArg(args[n], XmNlistSizePolicy,XmCONSTANT); n ++; XtSetArg(args[n], XmNselectionPolicy,XmSINGLE_SELECT); n ++; dirview->dir_dirlist = XmCreateScrolledList(form,"dirlist",args,n); n = 0; XtAddCallback(dirview->dir_dirlist, XmNsingleSelectionCallback, (XtCallbackProc) dir_dir_select, dirview); XtAddCallback(dirview->dir_dirlist, XmNdefaultActionCallback, (XtCallbackProc) dir_dir_select, dirview); translations = XtParseTranslationTable(GLOBAL_modal_list_translations); XtOverrideTranslations(dirview->dir_dirlist,translations); XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n ++; XtSetArg(args[n], XmNtopWidget, label1); n ++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n ++; XtSetArg(args[n], XmNrightPosition, 50); n ++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n ++; XtSetValues(XtParent(dirview->dir_dirlist), args, n); n = 0; XtSetArg(args[n], XmNscrollBarDisplayPolicy, XmSTATIC); n ++; XtSetArg(args[n], XmNlistSizePolicy,XmCONSTANT); n ++; XtSetArg(args[n], XmNselectionPolicy,XmSINGLE_SELECT); n ++; dirview->dir_filelist = XmCreateScrolledList(form,"filelist",args,n); n = 0; XtAddCallback(dirview->dir_filelist, XmNsingleSelectionCallback, (XtCallbackProc) dir_file_select, dirview); XtAddCallback(dirview->dir_filelist, XmNdefaultActionCallback, (XtCallbackProc) dir_accept, dirview); translations = XtParseTranslationTable(GLOBAL_modal_list_translations); XtOverrideTranslations(dirview->dir_filelist,translations); XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n ++; XtSetArg(args[n], XmNtopWidget, label2); n ++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n ++; XtSetArg(args[n], XmNleftPosition, 50); n ++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n ++; XtSetValues(XtParent(dirview->dir_filelist), args, n); n = 0; XtManageChild(dirview->dir_dirlist); XtManageChild(dirview->dir_filelist); check_buttons(dir_menu, XtNumber(dir_menu),NULL, dirview->button_state); XtManageChild(form); XtManageChild(dirview->shell); push_cursor(PIRATE_CURSOR); position_popup_widget(dirview->shell, FALSE); XtPopup(dirview->shell,XtGrabExclusive); XmUpdateDisplay(dirview->shell); dir_stuff(dirview); modal_main_loop(&dirview->done); XtPopdown(dirview->shell); XtDestroyWidget(dirview->shell); XFlush(display); if((dirview->pathname) && (*(dirview->pathname) != NUL_TERM)) { if(*dirview->pathname == PATH_SEPARATOR_CHAR) filename = cpystr(dirview->pathname); else { filename = (char *) fs_get(MAXPATHLEN + 1); strcpy(filename,(dirview->cwd) ? dirview->cwd : PATH_SEPARATOR_STR); if(filename[strlen(filename) - 1] != PATH_SEPARATOR_CHAR) strcat(filename,PATH_SEPARATOR_STR); strcat(filename,dirview->pathname); } } if(session->last_dir != NULL) fs_give((void **) &session->last_dir); if(dirview->cwd != NULL) session->last_dir = cpystr(dirview->cwd); free_dir_structs(dirview->dir_struct); if(dirview->pathname) fs_give((void **) &dirview->pathname); if(dirview->cwd) fs_give((void **) &dirview->cwd); fs_give((void **) &dirview); if(filename != NULL && (op_write == TRUE)) { append_mode = get_append_mode(w,filename); if(append_mode == (-1)) { fs_give((void **) &filename); filename = NULL; } if(append_mode == 1) *op_append = FALSE; if(append_mode == 2) *op_append = TRUE; } pop_cursor(); return(filename); } #ifdef __STDC__ int get_append_mode(Widget w, char *filename) #else int get_append_mode(w,filename) Widget w; char *filename; #endif { Arg args[ARGLISTSIZE]; int n = 0; int append_mode = 0; Widget form, menubar, label; struct stat st; if((stat(filename,&st)) == SYSCALL_FAILURE) return(1); if(! S_ISREG(st.st_mode)) { mm_log(MLGetLocalized(XtNmsgNotRegularFile,MsgNotRegularFile),WARN); return(-1); } append_shell = XtCreatePopupShell("append", topLevelShellWidgetClass, w, args, n ); AddDestroyCallback (append_shell); n = 0; setup_editres(append_shell); if(pirate_icon != (Pixmap) None) XtVaSetValues(append_shell, XmNiconPixmap,pirate_icon, NULL); form = XmCreateForm(append_shell, "form", args, n); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n ++; menubar = XmCreateMenuBar(form,"menubar", args, n); n = 0; XtManageChild(menubar); create_buttons(NULL, menubar, append_menu, XtNumber(append_menu), BTN_ON, (XtPointer) &append_mode, ROOTMENULEVEL); XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n ++; XtSetArg(args[n], XmNtopWidget, menubar); n ++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n ++; label = XmCreateLabel(form, "append_lbl", args,n); n = 0; XtManageChild(label); XtManageChild(form); XtManageChild(append_shell); XtPopup(append_shell, XtGrabExclusive); position_popup_widget(append_shell, TRUE); modal_main_loop(&append_mode); XtPopdown(append_shell); XtDestroyWidget(append_shell); XFlush(display); return(append_mode); } #ifdef __STDC__ void append_cancel(Widget w, int *append_mode, XtPointer xp) #else void append_cancel(w,append_mode,xp) Widget w; int *append_mode; XtPointer xp; #endif { *append_mode = (-1); return; } #ifdef __STDC__ void append_overwrite(Widget w, int *append_mode, XtPointer xp) #else void append_overwrite(w,append_mode,xp) Widget w; int *append_mode; XtPointer xp; #endif { *(append_mode) = 1; return; } #ifdef __STDC__ void append_append(Widget w, int *append_mode, XtPointer xp) #else void append_append(w,append_mode,xp) Widget w; int *append_mode; XtPointer xp; #endif { *(append_mode) = 2; return; } #ifdef __STDC__ void append_help(Widget w, int *append_mode, XtPointer xp) #else void append_help(w,append_mode,xp) Widget w; int *append_mode; XtPointer xp; #endif { help(append_shell,APPENDHELPFILE); return; } #ifdef __STDC__ void dir_set(Dirview *dirview, char *path) #else void dir_set(dirview,path) Dirview *dirview; char *path; #endif { if(dirview->cwd) fs_give((void **) &dirview->cwd); dirview->cwd = cpystr(path); XmTextSetString(dirview->dir_path,path); dir_stuff(dirview); return; } #ifdef __STDC__ void dir_dir_select(Widget w, Dirview *dirview, XmListCallbackStruct *xp) #else void dir_dir_select(w,dirview,xp) Widget w; Dirview *dirview; XmListCallbackStruct *xp; #endif { char *str; char *ptr; char *newdir; XmStringGetLtoR(xp->item,XmSTRING_DEFAULT_CHARSET,&str); if(strcmp(str,MLGetLocalized(XtNmsgFileGoHome,MsgFileGoHome)) == STRMATCH) newdir = cpystr(local_auth.homedir); else { if(strcmp(str,MLGetLocalized(XtNmsgFileGoUp,MsgFileGoUp)) == STRMATCH) { newdir = GetTextField(dirview->dir_path); if(((ptr = strrchr(newdir,PATH_SEPARATOR_CHAR)) != NULL) && (ptr > newdir)) *ptr = NUL_TERM; if(ptr == newdir) *(ptr + 1) = NUL_TERM; } else { AppendText(dirview->dir_path,PATH_SEPARATOR_STR); AppendText(dirview->dir_path,str); newdir = GetTextField(dirview->dir_path); } } fs_give((void **) &str); dir_set(dirview,newdir); fs_give((void **) &newdir); return; } #ifdef __STDC__ void dir_dir_enter(Widget w, Dirview *dirview, XmListCallbackStruct *xp) #else void dir_dir_enter(w,dirview,xp) Widget w; Dirview *dirview; XmListCallbackStruct *xp; #endif { char *newdir = GetTextField(dirview->dir_path); dir_set(dirview,newdir); fs_give((void **) &newdir); XmProcessTraversal(w,XmTRAVERSE_NEXT_TAB_GROUP); return; } #ifdef __STDC__ void dir_file_select(Widget w, Dirview *dirview, XmListCallbackStruct *xp) #else void dir_file_select(w,dirview,xp) Widget w; Dirview *dirview; XmListCallbackStruct *xp; #endif { char *str; XmStringGetLtoR(xp->item,XmSTRING_DEFAULT_CHARSET,&str); XmTextSetString(dirview->dir_file,str); fs_give((void **) &str); XmListDeselectAllItems(dirview->dir_filelist); return; } #ifdef __STDC__ void dir_accept(Widget w, Dirview *dirview, XtPointer xp) #else void dir_accept(w,dirview,xp) Widget w; Dirview *dirview; XtPointer xp; #endif { dirview->pathname = XmTextGetString(dirview->dir_file); if(*dirview->pathname == NUL_TERM) { fs_give((void **) &dirview->pathname); dirview->pathname = NULL; } dirview->done = 1; return; } #ifdef __STDC__ void dir_cancel(Widget w, Dirview *dirview, XtPointer xp) #else void dir_cancel(w,dirview,xp) Widget w; Dirview *dirview; XtPointer xp; #endif { dirview->pathname = NULL; dirview->done = 1; return; } #ifdef __STDC__ void dir_hide_dot(Widget w, Dirview *dirview, XtPointer xp) #else void dir_hide_dot(w,dirview,xp) Widget w; Dirview *dirview; XtPointer xp; #endif { dirview->ignore_dot = TRUE; dirview->button_state |= BTN_HIDEDOT; dirview->button_state &= ~(BTN_NOHIDEDOT); dir_apply_filter(w,dirview,xp); check_buttons(dir_menu, XtNumber(dir_menu),NULL, dirview->button_state); return; } #ifdef __STDC__ void dir_show_dot(Widget w, Dirview *dirview, XtPointer xp) #else void dir_show_dot(w,dirview,xp) Widget w; Dirview *dirview; XtPointer xp; #endif { dirview->ignore_dot = FALSE; dirview->button_state &= ~(BTN_HIDEDOT); dirview->button_state |= BTN_NOHIDEDOT; dir_apply_filter(w,dirview,xp); check_buttons(dir_menu, XtNumber(dir_menu),NULL, dirview->button_state); return; } #ifdef __STDC__ void dir_select_filter(Widget w, Dirview *dirview, XtPointer xp) #else void dir_select_filter(w,dirview,xp) Widget w; Dirview *dirview; XtPointer xp; #endif { dir_apply_filter(w,dirview,xp); XmProcessTraversal(w,XmTRAVERSE_NEXT_TAB_GROUP); return; } #ifdef __STDC__ void dir_help(Widget w, Dirview *dirview, XtPointer xp) #else void dir_help(w,dirview,xp) Widget w; Dirview *dirview; XtPointer xp; #endif { help(dirview->shell,FILEHELPFILE); return; } #ifdef __STDC__ void dir_apply_filter(Widget w, Dirview *dirview, XtPointer xp) #else void dir_apply_filter(w,dirview,xp) Widget w; Dirview *dirview; XtPointer xp; #endif { Dir_Struct *dir_struct; char *pattern; XmString xstr; XmListDeselectAllItems(dirview->dir_dirlist); XmListDeleteAllItems(dirview->dir_dirlist); XmListDeselectAllItems(dirview->dir_filelist); XmListDeleteAllItems(dirview->dir_filelist); pattern = GetTextField(dirview->dir_pattern); xstr = XmStringCreateSimple(MLGetLocalized(XtNmsgFileGoHome,MsgFileGoHome)); XmListAddItemUnselected(dirview->dir_dirlist,xstr,0); XmStringFree(xstr); xstr = XmStringCreateSimple(MLGetLocalized(XtNmsgFileGoUp,MsgFileGoUp)); XmListAddItemUnselected(dirview->dir_dirlist,xstr,0); XmStringFree(xstr); for(dir_struct = dirview->dir_struct; dir_struct; dir_struct = dir_struct->next) { if((dirview->ignore_dot) && (*dir_struct->name == '.')) continue; if((dir_struct->directory == FALSE) && (wildmat(dir_struct->name,pattern) == 0)) continue; xstr = XmStringCreateSimple(dir_struct->name); if(dir_struct->directory) XmListAddItemUnselected(dirview->dir_dirlist,xstr,0); else XmListAddItemUnselected(dirview->dir_filelist,xstr,0); XmStringFree(xstr); } return; } #ifdef __STDC__ void dir_stuff(Dirview *dirview) #else void dir_stuff(dirview) Dirview *dirview; #endif { DIR *d; Dir_Struct *dir_struct; char filename[MAXPATHLEN]; struct stat st; #ifdef STRICT_BSD struct direct *e = NULL; #else struct dirent *e = NULL; #endif XDefineCursor(display,XtWindow(dirview->shell), clock_cursor); XFlush(display); /* * A few precautions. Since the dirview->cwd string and dir_path window * have already been updated, we don't know where we came from if this fails. * So we default to going home on failure. BUT, we need to also make * sure we can do THAT. That's why the recursion counter. If we can't * go home, no sense going on, so we hardwire a "cancel" operation. * In any event, let the user know something wierd is going on. */ if((d = opendir(dirview->cwd)) == NULL) { mm_log(MLGetLocalized(XtNmsgChdirFailed,MsgChdirFailed),WARN); if(dirview->recurse < 2) { dirview->recurse ++; dir_set(dirview,local_auth.homedir); } else { mm_log(MLGetLocalized(XtNmsgChdirHomeFailed,MsgChdirHomeFailed),ERROR); dirview->pathname = NULL; dirview->done = TRUE; } XBell(display,1000); XUndefineCursor(display,XtWindow(dirview->shell)); XFlush(display); return; } dirview->recurse = 0; free_dir_structs(dirview->dir_struct); dirview->dir_struct = NULL; while((e = readdir(d)) != NULL) { if((strcmp(e->d_name,THISDIR_STR) == STRMATCH) || (strcmp(e->d_name,PARENTDIR_STR) == STRMATCH)) continue; sprintf(filename,"%s/%s",dirview->cwd,e->d_name); if(stat(filename,&st) != SYSCALL_SUCCESS) continue; dir_struct = new_dir_struct(); dir_struct->name = cpystr(e->d_name); dir_struct->directory = (S_ISDIR(st.st_mode)) ? TRUE : FALSE; dir_struct->next = dirview->dir_struct; dirview->dir_struct = dir_struct; } closedir(d); dir_sort(dirview); dir_apply_filter(dirview->shell,dirview,NULL); XUndefineCursor(display,XtWindow(dirview->shell)); XFlush(display); return; } #ifdef __STDC__ int dir_compare(const void *n1, const void *n2) #else int dir_compare(n1,n2) const void *n1; const void *n2; #endif { Dir_Struct **name1 = (Dir_Struct **) n1; Dir_Struct **name2 = (Dir_Struct **) n2; return(strcmp((*(name1))->name,(*(name2))->name)); } #ifdef __STDC__ void dir_sort(Dirview *dirview) #else void dir_sort(dirview) Dirview *dirview; #endif { Dir_Struct **sort; Dir_Struct *dir_struct; int n = 0; int total = 0; for(dir_struct = dirview->dir_struct; dir_struct; dir_struct = dir_struct->next) total ++; if(total < 2) return; sort = (Dir_Struct **) fs_get(total * sizeof(Dir_Struct *)); for(dir_struct = dirview->dir_struct; dir_struct; dir_struct = dir_struct->next) { sort[n] = dir_struct; n ++; } qsort((char *) sort, total, sizeof(Dir_Struct **), dir_compare); for(n = 0; n < total; n ++) { dir_struct = sort[n]; if(n == 0) dirview->dir_struct = dir_struct; if(n < (total - 1)) dir_struct->next = sort[n + 1]; else dir_struct->next = NULL; } fs_give((void **) &sort); return; }