/*
* This file contains a function, get_dir_list() that will get a directory
* listing and put all the names into a table (an array of char *'s table)
* and return it to you (along with the number of entries in the directory
* if desired). The table is NULL terminated (i.e. the entry after the last
* one is a NULL), and is just like an argv style array.
*
* If an error occurs (memory allocation, bad directory name, etc), you
* will get a NULL back.
*
* Each entry of the returned table points to a NULL-terminated string
* that contains the name of a file in the directory. If the name is
* a directory, it has a slash appended to it.
*
* When you are done with the table, you should free it manually, or you
* can call the function free_table() provided down below.
*
* See the sample main() down below for how to use it. Ignore (or steal
* if you'd like) the other code that isn't particularly relevant (i.e.
* the support functions).
*
* Dominic Giampaolo
* dbg@sgi.com
*/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <dirent.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <X11/keysymdef.h>
#include <X11/keysym.h>
#include "xrmap.h"
#include "numdefs.h"
extern Display * dpy;
extern int scr;
extern GC gc;
extern Window cmdwin, explwin;
extern int char_width;
extern XFontStruct * xfont[6];
extern int fonth[6], fontasc[6];
extern unsigned int explwin_width0, explwin_width, explwin_height, explwin_on;
extern int explwin_x, explwin_y;
extern Pixmap explpix;
extern int expl_table_entries;
extern int expl_lines;
extern int expl_shift;
extern int expl_output;
extern int caret_pos;
extern int line_clicked;
extern char expl_currdir[256];
extern char *expl_implicit;
extern char **expl_dirtable;
extern char *file_filter;
extern char *cmd_string;
extern char **msg;
extern char *editor_cmd, *im_viewer, *ps_viewer, *svg_viewer,
*html_viewer, *midi_cmd;
extern char *prog_cmd[7];
extern void
draw_win_string(ImageLayout *scene, Window win, char *s, int position);
extern void do_activate(ImageLayout * scene, KeySym keysym);
void free_table(char **table, int n)
{
char **orig = table;
for (; n > 0; n--, table++) {
if (*table)
free(*table);
}
free(orig);
}
void free_dirlist(char **table)
{
char **orig = table;
while(*table) {
free(*table);
table++;
}
free(orig);
}
int
dup_strcmp(char **a, char **b)
{
return strcmp(*a, *b);
}
char *get_file_name(struct dirent *d)
{
struct stat s;
char *name;
if (d == NULL) {
fprintf(stderr, "BUG (got a NULL in get_file_name()).\n");
return NULL;
}
if (stat(d->d_name, &s) < 0) {
perror(d->d_name);
return NULL;
}
if (S_ISDIR(s.st_mode)) {
name = (char *)malloc(strlen(d->d_name)+2);
if (name == NULL)
return NULL;
sprintf(name, "%s/", d->d_name);
} else {
name = (char *)strdup(d->d_name);
}
return name;
}
int file_filter_check(char *scanit)
{
struct stat buf;
if (scanit == NULL) return 1;
if (!strcmp(scanit, "./")) return 1;
stat(scanit, &buf);
if (S_ISDIR(buf.st_mode)) return 0;
if (file_filter==NULL) return 0;
if (*file_filter==0) return 0;
if (strstr(scanit, file_filter))
return 0;
else
return 1;
}
#define CHUNK 100
char **get_dir_list(char *dirname, int *num_entries)
{
int i,size=CHUNK;
char **table, old_dir[MAXPATHLEN];
DIR *dir;
struct dirent *dirent;
getcwd(old_dir, MAXPATHLEN);
if (dirname && chdir(dirname) < 0)
return NULL;
dir = opendir(".");
if (dir == NULL) {
chdir(old_dir);
return NULL;
}
table = (char **)calloc(size, sizeof(char *));
if (table == NULL) {
closedir(dir);
chdir(old_dir);
return NULL;
}
dirent = NULL; i = 0;
for (dirent = readdir(dir); dirent != NULL; dirent = readdir(dir)) {
table[i] = get_file_name(dirent);
if (file_filter_check(table[i])) continue;
/* continue if table[i] is void or doesn't match the filter */
i++;
if (i == size) {
char **table2;
size *= 2;
table2 = (char **)realloc(table, size * sizeof(char *));
if (table2 == NULL) {
free_table(table, i);
closedir(dir);
chdir(old_dir);
return NULL;
}
table = table2;
}
}
table[i] = NULL; /* make sure the table ends with a NULL */
if (num_entries)
*num_entries = i;
closedir(dir);
chdir(old_dir);
return table;
}
void show_explwin(ImageLayout *scene, int x, int y)
{
static int expl_shift_old = -1;
int i, j, b, d, w, p, h, ht, h_skip, hp_skip, char_space;
int activate;
char *s;
char *banner[4] = { "home", "share", " /", " ."};
XSizeHints xsh;
activate = 0;
if (!explwin_on) {
activate = 1;
expl_shift = 0;
explwin_on = 1;
if (explwin_x>-100000) {
xsh.flags = USPosition | PPosition;
xsh.x = explwin_x;
xsh.y = explwin_y;
XSetWMNormalHints(dpy, explwin, &xsh);
}
}
XMapRaised(dpy, explwin);
d = 3*char_width/2;
char_space = char_width * 4;
h_skip = fonth[0]+8;
XSetFont(dpy, gc, xfont[0]->fid);
if (y == 0) {
activate = 1;
XClearArea(dpy, explwin, 0, 0, explwin_width, h_skip, False);
w = 8 * char_space;
XSetForeground(dpy, gc, scene->color[C_BG_TEXT].pix);
XFillRectangle(dpy, explwin, gc, 0, 0, w, h_skip);
w = explwin_width - 2*char_space;
XSetForeground(dpy, gc, scene->color[C_BG_ESCAPE].pix);
XFillRectangle(dpy, explwin, gc,
w, 0, explwin_width, h_skip);
XSetForeground(dpy, gc, scene->color[C_FG_TEXT].pix);
for (i=0; i<=4; i++) {
w = 2*i*char_space;
s = banner[i];
if (i<=3)
XDrawString(dpy, explwin, gc, d+w, fontasc[0]+4, s, strlen(s));
if (i>=1)
XDrawLine(dpy, explwin, gc, w, 0, w, h_skip);
}
w = explwin_width - 2*char_space;
s = msg[ESCAPE];
XDrawString(dpy, explwin, gc, d+w, fontasc[0]+4, s, strlen(s));
XDrawLine(dpy, explwin, gc, w, 0, w, h_skip);
XDrawLine(dpy, explwin, gc, 0, h_skip, explwin_width, h_skip);
}
parse_again:
if (y <= 1) {
activate = 1;
XClearArea(dpy, explwin, 0, h_skip+1,
explwin_width, explwin_height, False);
XSetForeground(dpy, gc, scene->color[C_FG_TEXT].pix);
XDrawString(dpy, explwin, gc, d, fontasc[0] + h_skip + 4,
expl_currdir, strlen(expl_currdir));
h = 2*h_skip;
XDrawLine(dpy, explwin, gc, 0, h, explwin_width, h);
}
if (!expl_dirtable) {
activate = 1;
expl_dirtable = get_dir_list(expl_currdir, &expl_table_entries);
if (expl_dirtable)
qsort(expl_dirtable, expl_table_entries, sizeof(char *),
(int (*)(const void *, const void *))dup_strcmp);
}
if (!expl_dirtable) {
char *error = msg[DIRECTORY_INEXISTENT_OR_INACCESSIBLE];
XClearArea(dpy, explwin, 0, 2 * h_skip + 1, explwin_width,
explwin_height, False);
XSetForeground(dpy, gc, scene->color[C_FG_IMAGE].pix);
XDrawString(dpy, explwin, gc, d, 3*h_skip, error, strlen(error));
expl_shift_old = -1;
return;
}
hp_skip = (5*h_skip)/6;
expl_lines = (explwin_height-2*h_skip)/hp_skip;
if (y <= 2) {
if (!activate && expl_shift_old == expl_shift) return;
expl_shift_old = expl_shift;
XClearArea(dpy, explwin, 0, 2 * h_skip + 1, explwin_width - 13,
explwin_height, False);
XSetForeground(dpy, gc, scene->color[C_BG_TEXT].pix);
XFillRectangle(dpy, explwin, gc,
explwin_width - 12, 2 * h_skip + 12, 12,
explwin_height - 2*h_skip - 24);
XSetForeground(dpy, gc, scene->color[C_FG_TEXT].pix);
XDrawLine(dpy, explwin, gc, explwin_width - 13, 2*h_skip,
explwin_width - 13, explwin_height);
/* Drawing small triangular icons */
w = explwin_width - 6;
h = 2 * h_skip + 1;
for (i=0; i<=10; i++)
XDrawLine(dpy,explwin, gc, w-i/2, h+i, w+i/2, h+i);
h = explwin_height-1;
for (i=0; i<=10; i++)
XDrawLine(dpy, explwin, gc, w-i/2, h-i, w+i/2, h-i);
/* drawing the thumb */
w = explwin_width - 10;
p = explwin_height - 2 * h_skip - 28;
ht = p * (expl_lines+1) / (expl_table_entries+1);
if (ht<20) ht = 20;
if (ht>p/2) ht = p/2;
p = p - ht;
h = 2 * h_skip + 14;
if (expl_table_entries>2)
h += (expl_shift * p)/(expl_table_entries-2);
XDrawRectangle(dpy, explwin, gc, w, h, 7, ht);
} else
XClearArea(dpy, explwin, 2, 2 * h_skip + 1, 3,
explwin_height, False);
for (i=0; i<expl_table_entries-expl_shift; i++)
if (i<expl_lines) {
s = expl_dirtable[i+expl_shift];
b = -(s[strlen(s)-1]=='/');
/* simple heuristics to decide file type from suffix */
if (b==0) {
if (strstr(s,".xpm") || strstr(s,".ppm") ||
strstr(s,".png") || strstr(s,".jpg") ||
strstr(s,".gif") || strstr(s,".tif")) b = 1;
else
if (strstr(s,".ps") || strstr(s,".eps") || strstr(s,".pdf")) b = 2;
else
if (strstr(s,".svg")) b = 3;
else
if (strstr(s,".htm")) b = 4;
else
if (strstr(s,".mid") || strstr(s,".midi")) b = 5;
else
if (strstr(s,".rc")) b = 6;
}
j = fontasc[0] + 2 * h_skip + i*hp_skip + 3;
if (y>=3) {
p = (y-2*h_skip)/hp_skip;
if (p==i && x<=XTextWidth(xfont[0], s, strlen(s))+8) {
if (b==-1) {
if (!strcmp(s, "../")) {
i = strlen(expl_currdir)-1;
if (expl_currdir[i]=='/' && i>0) {
expl_currdir[i] = '\0';
--i;
s = rindex(expl_currdir, '/');
if (s) s[1] = '\0';
}
} else
strcat(expl_currdir, s);
free_dirlist(expl_dirtable);
expl_dirtable = NULL;
expl_shift = 0;
y = 1;
goto parse_again;
}
XSetForeground(dpy, gc,
scene->color[C_FG_TICKS].pix);
XFillRectangle(dpy, explwin, gc, d/4, j-5, 3, 4);
if (expl_output) {
char *cmd_old;
cmd_old = cmd_string;
cmd_string = malloc(strlen(expl_currdir)+strlen(s)+4);
if (!strncmp(expl_currdir, expl_implicit,
strlen(expl_implicit))) {
sprintf(cmd_string, "%s%s",
expl_currdir+strlen(expl_implicit), s);
} else
sprintf(cmd_string, "%s%s", expl_currdir, s);
caret_pos = strlen(cmd_string);
draw_win_string(scene, cmdwin, cmd_string, BOTTOM);
if (!strcmp(cmd_old, cmd_string) && line_clicked>=1) {
str2value(scene, line_clicked, cmd_string);
draw_win_cmd(scene, 2);
}
if (cmd_old) free(cmd_old);
} else {
char cmd[512];
prog_cmd[0] = editor_cmd;
prog_cmd[1] = im_viewer;
prog_cmd[2] = ps_viewer;
prog_cmd[3] = svg_viewer;
prog_cmd[4] = html_viewer;
prog_cmd[5] = midi_cmd;
prog_cmd[6] = "xrmap -rcfile";
sprintf(cmd, "%s %s%s &", prog_cmd[b], expl_currdir, s);
system(cmd);
}
}
}
if (b==-1)
XSetForeground(dpy, gc, scene->color[C_FG_DIR].pix);
else
if (b==1)
XSetForeground(dpy, gc, scene->color[C_FG_IMAGE].pix);
else
XSetForeground(dpy, gc, scene->color[C_FG_TEXT].pix);
XDrawString(dpy, explwin, gc, d, j, s, strlen(s));
}
}
void close_explwin()
{
get_window_placement(explwin, &explwin_x, &explwin_y,
&explwin_width, &explwin_height);
XUnmapWindow(dpy, explwin);
explwin_on = 0;
}
syntax highlighted by Code2HTML, v. 0.9.1