/* 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;
}



syntax highlighted by Code2HTML, v. 0.9.1