src/cmd/fsexam/src/file-filter.c
author yz157939@agc105
Fri, 25 Apr 2008 17:02:23 +0800
changeset 147 8c4ef02c14b8
permissions -rw-r--r--
replace new version of fsexam, old version 0.3.1 is not used any more

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
 * Use is subject to license terms.
 */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <strings.h>
#include <string.h>
#include <errno.h>

#include <glib.h>
#include <glib/gi18n.h>

#include "fsexam.h"
#include "fsexam-error.h"
#include "fsexam-helper.h"
#include "file-filter.h"
#include "fsexam-header.h"
#include "fsexam-ui.h"

#define CMD_NAME                "/usr/bin/find"
#define FSEXAM_REFRESH_TIMEOUT  50000

static gchar **
filter_compose_argv (const gchar *params)
{
    gchar *full_cmd = NULL;
    gchar **argv = NULL;

    if (params == NULL) {
        return NULL;
    }

    full_cmd = g_strdup_printf ("%s %s", CMD_NAME, params);
    argv = g_strsplit (full_cmd, " ", -1);
    g_free (full_cmd);

    return argv;
}

/*
 * Run find(1) with given params, and return the result
 */
GList *
filter_cmd_run (const gchar *params)
{
    FILE    *fp = NULL;
    gchar   **argv = NULL;
    gchar   *buf = NULL;
    GList   *list = NULL;
    GError  *error = NULL;
    gint    child_stdout;

    argv = filter_compose_argv (params);
    if (argv == NULL) {
        g_print (_("Parameters of find(1) is empty.\n"));
        return NULL;
    }

    /* create pipe */
    if (!g_spawn_async_with_pipes (NULL, argv,
                NULL,       /* envp */
                0,      /* GSpawnFlags */
                NULL, NULL,
                NULL,   /* pid */
                NULL,
                &child_stdout,
                NULL, 
                &error)) {
        g_print (error->message);
        g_error_free (error);
        g_strfreev (argv);

        return NULL;
    }

    /* create FILE pointer from subprocess's stdout */
    if ((fp = fdopen (child_stdout, "r")) == NULL) {
        g_print (_("Can't open pipe file descriptor.\n"));
        g_strfreev (argv);
        return NULL;
    }
        
    buf = (gchar *) g_malloc (PATH_MAX);
    g_print (_("Searching..."));
    g_print ("\n");

    while (fgets (buf, PATH_MAX, fp) != NULL) {
        gint  len = strlen (buf);

        if (buf[len - 1] == '\n')
            buf[len - 1] = '\0';

        list = g_list_prepend (list, g_strdup (buf));
    }

    g_print (_("Search finished"));
    g_print ("\n");

    g_free (buf);
    g_strfreev (argv);
    fclose (fp);

    return list;
}

/*
 * Run file(1) and append searched files into search result treeview 
 */
void
filter_gui_run (const gchar *folder, const gchar *params)
{
    FILE    *fp = NULL;
    gchar   **argv = NULL;
    GError  *error = NULL;
    gint    child_stdout;
    gint    file_count = 0;
    gchar   *buf = NULL;
    gchar   *msg = NULL;
    GTimer  *timer = NULL;
    gulong  duration;
    GtkWidget *menu_stop = NULL;
    GtkWidget *menu_search = NULL;
    GtkWidget *menu_clear = NULL;
    GtkWidget *label_result = NULL;

    argv = filter_compose_argv (params);
    if (argv == NULL) {
        g_print (_("Parameters of find(1) is empty.\n"));
        return;
    }

    /* create pipe */
    if (!g_spawn_async_with_pipes (NULL, argv, 
                NULL,       /* envp */
                0,          /* GSpawnFlags */
                NULL, NULL, 
                &view->pid, 
                NULL,
                &child_stdout,
                NULL,
                &error)) {
        GtkWidget *dialog = NULL;

        dialog = gtk_message_dialog_new (GTK_WINDOW (view->mainwin),
                GTK_DIALOG_DESTROY_WITH_PARENT,
                GTK_MESSAGE_ERROR,
                GTK_BUTTONS_OK,
                _("Error occurs during executing the search command."));
        gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
                error->message);

        gtk_dialog_run (GTK_DIALOG (dialog));
        
        gtk_widget_destroy (dialog);
        g_error_free (error);
        g_strfreev (argv);
        
        return;
    }

    /* create FILE pointer from subprocess's stdout */
    if ((fp = fdopen (child_stdout, "r")) == NULL) {
        GtkWidget *dialog = NULL;

        dialog = gtk_message_dialog_new (GTK_WINDOW (view->mainwin),
                GTK_DIALOG_DESTROY_WITH_PARENT,
                GTK_MESSAGE_ERROR,
                GTK_BUTTONS_OK,
                _("Error occurs when open fd."));
        gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
                g_strerror (errno));

        gtk_dialog_run (GTK_DIALOG (dialog));
        
        gtk_widget_destroy (dialog);
        g_strfreev (argv);

        return;
    }

    /*
     * Prepare for searching 
     */
    menu_clear = g_object_get_data (G_OBJECT (view->mainwin), 
                                    "menu_clear_search");
    menu_search = g_object_get_data (G_OBJECT (view->mainwin), "menu_search");
    menu_stop = g_object_get_data (G_OBJECT (view->mainwin), 
                                    "menu_stop_search");
    gtk_widget_set_sensitive (menu_clear, FALSE);
    gtk_widget_hide (menu_search);
    gtk_widget_show (menu_stop);
    
    label_result = g_object_get_data (G_OBJECT (view->mainwin), "label_result");
    fsexam_statusbar_update (_("Searching..."));

    /* show result pane and clear previous result */
    fsexam_search_treeview_append_file (NULL, TRUE);
    g_free (view->basedir);

    /* resolve possible symlink in folder path */
    if (g_file_test (folder, G_FILE_TEST_IS_SYMLINK))
        view->basedir = get_abs_path_for_symlink_target (folder);
    else
        view->basedir = get_abs_path (folder);

    stop_search = FALSE;
    buf = (gchar *) g_malloc (PATH_MAX);
    memset (buf, 0, PATH_MAX);

    timer = g_timer_new ();
    g_timer_start (timer);

    /* Read data from child's stdout async */
    while (fgets (buf, PATH_MAX, fp) != NULL) {
        gint  len = strlen (buf);

        if (buf[len - 1] == '\n')
            buf[len - 1] = '\0';

        fsexam_search_treeview_append_file (buf, FALSE);
        file_count ++;

        g_timer_elapsed (timer, &duration);

        if (duration > FSEXAM_REFRESH_TIMEOUT) {
            msg = g_strdup_printf (_("%d files found"), file_count);
            gtk_label_set_text (GTK_LABEL (label_result), msg);
            g_free (msg);

            while (gtk_events_pending ()) {
                gtk_main_iteration ();
            }

            g_timer_reset (timer);
        }

        if (force_quit) /* user quit application */
            break;
    }

    g_timer_destroy (timer);

    if (!force_quit) {  /* Quit the whole app, mainwin has been destroyed */
        g_spawn_close_pid (view->pid);
        view->pid = -1;

        msg = g_strdup_printf (_("%d files found"), file_count);
        gtk_label_set_text (GTK_LABEL (label_result), msg);
        g_free (msg);

        if (file_count != 0)
            gtk_widget_set_sensitive (menu_clear, TRUE);

        gtk_widget_hide (menu_stop);
        gtk_widget_show (menu_search);
    
        fsexam_statusbar_update (stop_search ? _("Search stopped") 
                                             : _("Search finished"));
    }

    fclose (fp);
    g_free (buf);
    g_strfreev (argv);

    return;
}