From 2298a2d670f3df392f29f97ea9cc82286d869583 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sat, 15 Sep 2007 10:13:31 +0000 Subject: [PATCH] Added target progress --- Makefile | 1 + src/Makefile | 15 +++- src/progress.c | 215 +++++++++++++++++++++++++++++++++++++++++++++++ src/project.conf | 6 +- 4 files changed, 234 insertions(+), 3 deletions(-) create mode 100644 src/progress.c diff --git a/Makefile b/Makefile index 0c76030..c38835f 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,7 @@ dist: @$(TAR) $(PACKAGE)-$(VERSION).tar.gz \ $(PACKAGE)-$(VERSION)/src/calendar.c \ $(PACKAGE)-$(VERSION)/src/fontsel.c \ + $(PACKAGE)-$(VERSION)/src/progress.c \ $(PACKAGE)-$(VERSION)/src/run.c \ $(PACKAGE)-$(VERSION)/src/Makefile \ $(PACKAGE)-$(VERSION)/src/project.conf \ diff --git a/src/Makefile b/src/Makefile index 805e7df..f53e083 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,4 +1,4 @@ -TARGETS = calendar fontsel run +TARGETS = calendar fontsel progress run PREFIX = /usr/local DESTDIR = BINDIR = $(PREFIX)/bin @@ -27,6 +27,12 @@ fontsel_CFLAGS = $(CPPFLAGS) $(CFLAGSF) $(CFLAGS) fontsel: $(fontsel_OBJS) $(CC) -o fontsel $(fontsel_OBJS) $(LDFLAGSF) $(LDFLAGS) +progress_OBJS = progress.o +progress_CFLAGS = $(CPPFLAGS) $(CFLAGSF) $(CFLAGS) + +progress: $(progress_OBJS) + $(CC) -o progress $(progress_OBJS) $(LDFLAGSF) $(LDFLAGS) + run_OBJS = run.o run_CFLAGS = $(CPPFLAGS) $(CFLAGSF) $(CFLAGS) @@ -39,11 +45,14 @@ calendar.o: calendar.c fontsel.o: fontsel.c $(CC) $(fontsel_CFLAGS) -c fontsel.c +progress.o: progress.c + $(CC) $(progress_CFLAGS) -c progress.c + run.o: run.c $(CC) $(run_CFLAGS) -c run.c clean: - $(RM) $(calendar_OBJS) $(fontsel_OBJS) $(run_OBJS) + $(RM) $(calendar_OBJS) $(fontsel_OBJS) $(progress_OBJS) $(run_OBJS) distclean: clean $(RM) $(TARGETS) @@ -52,11 +61,13 @@ install: all $(MKDIR) $(DESTDIR)$(BINDIR) $(INSTALL) -m 0755 calendar $(DESTDIR)$(BINDIR)/calendar $(INSTALL) -m 0755 fontsel $(DESTDIR)$(BINDIR)/fontsel + $(INSTALL) -m 0755 progress $(DESTDIR)$(BINDIR)/progress $(INSTALL) -m 0755 run $(DESTDIR)$(BINDIR)/run uninstall: $(RM) $(DESTDIR)$(BINDIR)/calendar $(RM) $(DESTDIR)$(BINDIR)/fontsel + $(RM) $(DESTDIR)$(BINDIR)/progress $(RM) $(DESTDIR)$(BINDIR)/run .PHONY: all clean distclean install uninstall diff --git a/src/progress.c b/src/progress.c new file mode 100644 index 0000000..07a7e26 --- /dev/null +++ b/src/progress.c @@ -0,0 +1,215 @@ +/* $Id$ */ +/* Copyright (c) 2007 Pierre Pronchery */ +/* This file is part of DeforaOS Desktop Accessories */ +/* Accessories is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the + * Free Software Foundation. + * + * Accessories is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * Accessories; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA */ +/* TODO: + * - speed estimation + * - implement -z + * - separate preferences from internal data */ + + + +#include +#include +#include +#include +#include +#include +#include +#include + + +/* types */ +typedef struct _Prefs +{ + int flags; + char * filename; + size_t length; + /* XXX internal data */ + int fd; + int fds[2]; + pid_t pid; + GtkWidget * progress; +} Prefs; +#define PREFS_z 0x1 + + +/* progress */ +/* functions */ +static int _progress_error(char const * message, int ret); +static int _progress_exec(Prefs * prefs, char * argv[]); + +/* callbacks */ +static gboolean _progress_out(GIOChannel * source, GIOCondition condition, + gpointer data); + +static int _progress(Prefs * prefs, char * argv[]) +{ + struct stat st; + GIOChannel * channel; + GtkWidget * window = NULL; + GtkWidget * vbox; + GtkWidget * widget; + + if(prefs->filename == NULL) + prefs->filename = "Standard input"; + else if((prefs->fd = open(prefs->filename, O_RDONLY)) < 0) + return _progress_error(prefs->filename, 1); + else if(fstat(prefs->fd, &st) == 0) + prefs->length = st.st_size; + if(pipe(prefs->fds) != 0) + { + close(prefs->fd); + return _progress_error("pipe", 1); + } + channel = g_io_channel_unix_new(prefs->fds[1]); + g_io_add_watch(channel, G_IO_OUT, _progress_out, prefs); + if((prefs->pid = fork()) == -1) + { + close(prefs->fd); + close(prefs->fds[0]); + close(prefs->fds[1]); + return _progress_error("fork", 1); + } + if(prefs->pid != 0) + return _progress_exec(prefs, argv); + close(prefs->fds[0]); + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(window), "Progress"); + vbox = gtk_vbox_new(FALSE, 0); + widget = gtk_label_new(prefs->filename); + gtk_box_pack_start(GTK_BOX(vbox), widget, TRUE, TRUE, 4); + prefs->progress = gtk_progress_bar_new(); + gtk_box_pack_start(GTK_BOX(vbox), prefs->progress, TRUE, TRUE, 4); + gtk_container_add(GTK_CONTAINER(window), vbox); + gtk_container_set_border_width(GTK_CONTAINER(window), 4); + gtk_widget_show_all(window); + gtk_main(); + close(prefs->fd); + close(prefs->fds[1]); + return 0; +} + +static int _progress_error(char const * message, int ret) +{ + GtkWidget * dialog; + + dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s: %s", + message, strerror(errno)); + gtk_window_set_title(GTK_WINDOW(dialog), "Error"); + gtk_dialog_run(GTK_DIALOG(dialog)); + return ret; +} + + +static int _progress_exec(Prefs * prefs, char * argv[]) +{ + close(prefs->fds[1]); + if(dup2(prefs->fds[0], 0) == -1) + exit(1); /* FIXME warn user */ + execvp(argv[0], argv); + /* FIXME warn user */ + exit(0); +} + + +/* callbacks */ +static gboolean _progress_out(GIOChannel * source, GIOCondition condition, + gpointer data) +{ + static size_t cnt = 0; + Prefs * prefs = data; + char buf[BUFSIZ]; + ssize_t len; + gsize written; + gdouble fraction; + + /* FIXME use g_io_channel_read too? */ + if(condition != G_IO_OUT + || (len = read(prefs->fd, buf, sizeof(buf))) < 0) + { + gtk_main_quit(); + _progress_error(prefs->filename, 0); + return FALSE; + } + if(g_io_channel_write(source, buf, len, &written) != G_IO_ERROR_NONE + || written != (gsize)len) + { + /* FIXME it may just be that everything was not written + * => put buffer and position in Prefs/Progress */ + gtk_main_quit(); + _progress_error(prefs->filename, 0); + return FALSE; + } + cnt += len; + if(prefs->length == 0 || cnt == 0) + gtk_progress_bar_pulse(GTK_PROGRESS_BAR(prefs->progress)); + else + { + fraction = cnt; + fraction /= prefs->length; + gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(prefs->progress), + fraction); + snprintf(buf, sizeof(buf), "%.1f%%", fraction * 100); + gtk_progress_bar_set_text(GTK_PROGRESS_BAR(prefs->progress), + buf); + } + if(len == 0) + { + gtk_main_quit(); + return FALSE; + } + return TRUE; +} + + +/* usage */ +static int _usage(void) +{ + fputs("Usage: progress [-z][-f file][-l length][-p prefix]" + " cmd [args...]\n", stderr); + return 1; +} + + +/* main */ +int main(int argc, char * argv[]) +{ + Prefs prefs; + int o; + char * p; + + memset(&prefs, 0, sizeof(prefs)); + gtk_init(&argc, &argv); + while((o = getopt(argc, argv, "f:z")) != -1) + switch(o) + { + case 'f': + prefs.filename = optarg; + break; + case 'l': + prefs.length = strtol(optarg, &p, 0); + /* FIXME check input validation */ + break; + case 'z': + prefs.flags |= PREFS_z; /* FIXME implement */ + break; + default: + return _usage(); + } + if(argc - optind < 1) + return _usage(); + return _progress(&prefs, &argv[optind]) == 0 ? 0 : 2; +} diff --git a/src/project.conf b/src/project.conf index 86d831d..29e7484 100644 --- a/src/project.conf +++ b/src/project.conf @@ -1,4 +1,4 @@ -targets=calendar,fontsel,run +targets=calendar,fontsel,progress,run cflags_force=-W -Wall -ansi `pkg-config gtk+-2.0 --cflags` cflags=-g ldflags_force=`pkg-config gtk+-2.0 --libs` @@ -12,6 +12,10 @@ sources=calendar.c type=binary sources=fontsel.c +[progress] +type=binary +sources=progress.c + [run] type=binary sources=run.c