From: Omari Stephens Date: Sat, 24 Dec 2016 05:23:02 +0000 (+0000) Subject: Start moving pan view search code to its own module X-Git-Tag: v1.4~139^3~6 X-Git-Url: http://geeqie.org/cgi-bin/gitweb.cgi?p=geeqie.git;a=commitdiff_plain;h=b2335bb939212a413caac77d0ef02bdebb4d7ece Start moving pan view search code to its own module Next step is to pull the construction of the Search UI into the module as well. Ideally, pan-view.c should just instantiate a Search thing, without having to worry about exactly how it's constructed or destructed. --- diff --git a/src/pan-view/Makefile.am b/src/pan-view/Makefile.am index 70c9423f..154149b5 100644 --- a/src/pan-view/Makefile.am +++ b/src/pan-view/Makefile.am @@ -13,4 +13,7 @@ module_pan_view = \ %D%/pan-util.c \ %D%/pan-util.h \ %D%/pan-view.c \ - %D%/pan-view.h + %D%/pan-view.h \ + %D%/pan-view-search.c \ + %D%/pan-view-search.h + diff --git a/src/pan-view/pan-view-search.c b/src/pan-view/pan-view-search.c new file mode 100644 index 00000000..9549cfc3 --- /dev/null +++ b/src/pan-view/pan-view-search.c @@ -0,0 +1,415 @@ +/* + * Copyright (C) 2006 John Ellis + * Copyright (C) 2008 - 2016 The Geeqie Team + * + * Author: John Ellis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "pan-view-search.h" + +#include "image.h" +#include "pan-calendar.h" +#include "pan-item.h" +#include "pan-util.h" +#include "pan-view.h" +#include "ui_tabcomp.h" + +static void pan_search_status(PanWindow *pw, const gchar *text) +{ + gtk_label_set_text(GTK_LABEL(pw->search_label), (text) ? text : ""); +} + +static gint pan_search_by_path(PanWindow *pw, const gchar *path) +{ + PanItem *pi; + GList *list; + GList *found; + PanItemType type; + gchar *buf; + + type = (pw->size > PAN_IMAGE_SIZE_THUMB_LARGE) ? PAN_ITEM_IMAGE : PAN_ITEM_THUMB; + + list = pan_item_find_by_path(pw, type, path, FALSE, FALSE); + if (!list) return FALSE; + + found = g_list_find(list, pw->click_pi); + if (found && found->next) + { + found = found->next; + pi = found->data; + } + else + { + pi = list->data; + } + + pan_info_update(pw, pi); + image_scroll_to_point(pw->imd, pi->x + pi->width / 2, pi->y + pi->height / 2, 0.5, 0.5); + + buf = g_strdup_printf("%s ( %d / %d )", + (path[0] == G_DIR_SEPARATOR) ? _("path found") : _("filename found"), + g_list_index(list, pi) + 1, + g_list_length(list)); + pan_search_status(pw, buf); + g_free(buf); + + g_list_free(list); + + return TRUE; +} + +static gboolean pan_search_by_partial(PanWindow *pw, const gchar *text) +{ + PanItem *pi; + GList *list; + GList *found; + PanItemType type; + gchar *buf; + + type = (pw->size > PAN_IMAGE_SIZE_THUMB_LARGE) ? PAN_ITEM_IMAGE : PAN_ITEM_THUMB; + + list = pan_item_find_by_path(pw, type, text, TRUE, FALSE); + if (!list) list = pan_item_find_by_path(pw, type, text, FALSE, TRUE); + if (!list) + { + gchar *needle; + + needle = g_utf8_strdown(text, -1); + list = pan_item_find_by_path(pw, type, needle, TRUE, TRUE); + g_free(needle); + } + if (!list) return FALSE; + + found = g_list_find(list, pw->click_pi); + if (found && found->next) + { + found = found->next; + pi = found->data; + } + else + { + pi = list->data; + } + + pan_info_update(pw, pi); + image_scroll_to_point(pw->imd, pi->x + pi->width / 2, pi->y + pi->height / 2, 0.5, 0.5); + + buf = g_strdup_printf("%s ( %d / %d )", + _("partial match"), + g_list_index(list, pi) + 1, + g_list_length(list)); + pan_search_status(pw, buf); + g_free(buf); + + g_list_free(list); + + return TRUE; +} + +static gboolean valid_date_separator(gchar c) +{ + return (c == '/' || c == '-' || c == ' ' || c == '.' || c == ','); +} + +static GList *pan_search_by_date_val(PanWindow *pw, PanItemType type, + gint year, gint month, gint day, + const gchar *key) +{ + GList *list = NULL; + GList *work; + + work = g_list_last(pw->list_static); + while (work) + { + PanItem *pi; + + pi = work->data; + work = work->prev; + + if (pi->fd && (pi->type == type || type == PAN_ITEM_NONE) && + ((!key && !pi->key) || (key && pi->key && strcmp(key, pi->key) == 0))) + { + struct tm *tl; + + tl = localtime(&pi->fd->date); + if (tl) + { + gint match; + + match = (tl->tm_year == year - 1900); + if (match && month >= 0) match = (tl->tm_mon == month - 1); + if (match && day > 0) match = (tl->tm_mday == day); + + if (match) list = g_list_prepend(list, pi); + } + } + } + + return g_list_reverse(list); +} + +static gboolean pan_search_by_date(PanWindow *pw, const gchar *text) +{ + PanItem *pi = NULL; + GList *list = NULL; + GList *found; + gint year; + gint month = -1; + gint day = -1; + gchar *ptr; + gchar *mptr; + struct tm *lt; + time_t t; + gchar *message; + gchar *buf; + gchar *buf_count; + + if (!text) return FALSE; + + ptr = (gchar *)text; + while (*ptr != '\0') + { + if (!g_unichar_isdigit(*ptr) && !valid_date_separator(*ptr)) return FALSE; + ptr++; + } + + t = time(NULL); + if (t == -1) return FALSE; + lt = localtime(&t); + if (!lt) return FALSE; + + if (valid_date_separator(*text)) + { + year = -1; + mptr = (gchar *)text; + } + else + { + year = (gint)strtol(text, &mptr, 10); + if (mptr == text) return FALSE; + } + + if (*mptr != '\0' && valid_date_separator(*mptr)) + { + gchar *dptr; + + mptr++; + month = strtol(mptr, &dptr, 10); + if (dptr == mptr) + { + if (valid_date_separator(*dptr)) + { + month = lt->tm_mon + 1; + dptr++; + } + else + { + month = -1; + } + } + if (dptr != mptr && *dptr != '\0' && valid_date_separator(*dptr)) + { + gchar *eptr; + dptr++; + day = strtol(dptr, &eptr, 10); + if (dptr == eptr) + { + day = lt->tm_mday; + } + } + } + + if (year == -1) + { + year = lt->tm_year + 1900; + } + else if (year < 100) + { + if (year > 70) + year+= 1900; + else + year+= 2000; + } + + if (year < 1970 || + month < -1 || month == 0 || month > 12 || + day < -1 || day == 0 || day > 31) return FALSE; + + t = pan_date_to_time(year, month, day); + if (t < 0) return FALSE; + + if (pw->layout == PAN_LAYOUT_CALENDAR) + { + list = pan_search_by_date_val(pw, PAN_ITEM_BOX, year, month, day, "day"); + } + else + { + PanItemType type; + + type = (pw->size > PAN_IMAGE_SIZE_THUMB_LARGE) ? PAN_ITEM_IMAGE : PAN_ITEM_THUMB; + list = pan_search_by_date_val(pw, type, year, month, day, NULL); + } + + if (list) + { + found = g_list_find(list, pw->search_pi); + if (found && found->next) + { + found = found->next; + pi = found->data; + } + else + { + pi = list->data; + } + } + + pw->search_pi = pi; + + if (pw->layout == PAN_LAYOUT_CALENDAR && pi && pi->type == PAN_ITEM_BOX) + { + pan_info_update(pw, NULL); + pan_calendar_update(pw, pi); + image_scroll_to_point(pw->imd, + pi->x + pi->width / 2, + pi->y + pi->height / 2, 0.5, 0.5); + } + else if (pi) + { + pan_info_update(pw, pi); + image_scroll_to_point(pw->imd, + pi->x - PAN_BOX_BORDER * 5 / 2, + pi->y, 0.0, 0.5); + } + + if (month > 0) + { + buf = pan_date_value_string(t, PAN_DATE_LENGTH_MONTH); + if (day > 0) + { + gchar *tmp; + tmp = buf; + buf = g_strdup_printf("%d %s", day, tmp); + g_free(tmp); + } + } + else + { + buf = pan_date_value_string(t, PAN_DATE_LENGTH_YEAR); + } + + if (pi) + { + buf_count = g_strdup_printf("( %d / %d )", + g_list_index(list, pi) + 1, + g_list_length(list)); + } + else + { + buf_count = g_strdup_printf("(%s)", _("no match")); + } + + message = g_strdup_printf("%s %s %s", _("Date:"), buf, buf_count); + g_free(buf); + g_free(buf_count); + pan_search_status(pw, message); + g_free(message); + + g_list_free(list); + + return TRUE; +} + +void pan_search_activate_cb(const gchar *text, gpointer data) +{ + PanWindow *pw = data; + + if (!text) return; + + tab_completion_append_to_history(pw->search_entry, text); + + if (pan_search_by_path(pw, text)) return; + + if ((pw->layout == PAN_LAYOUT_TIMELINE || + pw->layout == PAN_LAYOUT_CALENDAR) && + pan_search_by_date(pw, text)) + { + return; + } + + if (pan_search_by_partial(pw, text)) return; + + pan_search_status(pw, _("no match")); +} + +void pan_search_activate(PanWindow *pw) +{ + gchar *text; + + text = g_strdup(gtk_entry_get_text(GTK_ENTRY(pw->search_entry))); + pan_search_activate_cb(text, pw); + g_free(text); +} + +void pan_search_toggle_cb(GtkWidget *button, gpointer data) +{ + PanWindow *pw = data; + gboolean visible; + + visible = gtk_widget_get_visible(pw->search_box); + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)) == visible) return; + + if (visible) + { + gtk_widget_hide(pw->search_box); + gtk_arrow_set(GTK_ARROW(pw->search_button_arrow), GTK_ARROW_UP, GTK_SHADOW_NONE); + } + else + { + gtk_widget_show(pw->search_box); + gtk_arrow_set(GTK_ARROW(pw->search_button_arrow), GTK_ARROW_DOWN, GTK_SHADOW_NONE); + gtk_widget_grab_focus(pw->search_entry); + } +} + +void pan_search_toggle_visible(PanWindow *pw, gboolean enable) +{ + if (pw->fs) return; + + if (enable) + { + if (gtk_widget_get_visible(pw->search_box)) + { + gtk_widget_grab_focus(pw->search_entry); + } + else + { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pw->search_button), TRUE); + } + } + else + { + if (gtk_widget_get_visible(pw->search_entry)) + { + if (gtk_widget_has_focus(pw->search_entry)) + { + gtk_widget_grab_focus(GTK_WIDGET(pw->imd->widget)); + } + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pw->search_button), FALSE); + } + } +} diff --git a/src/pan-view/pan-view-search.h b/src/pan-view/pan-view-search.h new file mode 100644 index 00000000..c61dd190 --- /dev/null +++ b/src/pan-view/pan-view-search.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2006 John Ellis + * Copyright (C) 2008 - 2016 The Geeqie Team + * + * Author: John Ellis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef PAN_VIEW_PAN_VIEW_SEARCH_H +#define PAN_VIEW_PAN_VIEW_SEARCH_H + +#include "main.h" +#include "pan-types.h" + +void pan_search_toggle_visible(PanWindow *pw, gboolean enable); +void pan_search_activate(PanWindow *pw); +void pan_search_activate_cb(const gchar *text, gpointer data); +void pan_search_toggle_cb(GtkWidget *button, gpointer data); + +#endif +/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */ diff --git a/src/pan-view/pan-view.c b/src/pan-view/pan-view.c index db70b65e..4546778c 100644 --- a/src/pan-view/pan-view.c +++ b/src/pan-view/pan-view.c @@ -38,6 +38,7 @@ #include "pan-item.h" #include "pan-timeline.h" #include "pan-util.h" +#include "pan-view-search.h" #include "pixbuf-renderer.h" #include "pixbuf_util.h" #include "thumb.h" @@ -78,9 +79,6 @@ static void pan_layout_update_idle(PanWindow *pw); static void pan_fullscreen_toggle(PanWindow *pw, gboolean force_off); -static void pan_search_toggle_visible(PanWindow *pw, gboolean enable); -static void pan_search_activate(PanWindow *pw); - static void pan_window_close(PanWindow *pw); static GtkWidget *pan_popup_menu(PanWindow *pw); @@ -1326,7 +1324,7 @@ static void pan_info_add_exif(PanTextAlignment *ta, FileData *fd) } -static void pan_info_update(PanWindow *pw, PanItem *pi) +void pan_info_update(PanWindow *pw, PanItem *pi) { PanTextAlignment *ta; PanItem *pbox; @@ -1450,399 +1448,6 @@ static void pan_info_update(PanWindow *pw, PanItem *pi) } -/* - *----------------------------------------------------------------------------- - * search - *----------------------------------------------------------------------------- - */ - -static void pan_search_status(PanWindow *pw, const gchar *text) -{ - gtk_label_set_text(GTK_LABEL(pw->search_label), (text) ? text : ""); -} - -static gint pan_search_by_path(PanWindow *pw, const gchar *path) -{ - PanItem *pi; - GList *list; - GList *found; - PanItemType type; - gchar *buf; - - type = (pw->size > PAN_IMAGE_SIZE_THUMB_LARGE) ? PAN_ITEM_IMAGE : PAN_ITEM_THUMB; - - list = pan_item_find_by_path(pw, type, path, FALSE, FALSE); - if (!list) return FALSE; - - found = g_list_find(list, pw->click_pi); - if (found && found->next) - { - found = found->next; - pi = found->data; - } - else - { - pi = list->data; - } - - pan_info_update(pw, pi); - image_scroll_to_point(pw->imd, pi->x + pi->width / 2, pi->y + pi->height / 2, 0.5, 0.5); - - buf = g_strdup_printf("%s ( %d / %d )", - (path[0] == G_DIR_SEPARATOR) ? _("path found") : _("filename found"), - g_list_index(list, pi) + 1, - g_list_length(list)); - pan_search_status(pw, buf); - g_free(buf); - - g_list_free(list); - - return TRUE; -} - -static gboolean pan_search_by_partial(PanWindow *pw, const gchar *text) -{ - PanItem *pi; - GList *list; - GList *found; - PanItemType type; - gchar *buf; - - type = (pw->size > PAN_IMAGE_SIZE_THUMB_LARGE) ? PAN_ITEM_IMAGE : PAN_ITEM_THUMB; - - list = pan_item_find_by_path(pw, type, text, TRUE, FALSE); - if (!list) list = pan_item_find_by_path(pw, type, text, FALSE, TRUE); - if (!list) - { - gchar *needle; - - needle = g_utf8_strdown(text, -1); - list = pan_item_find_by_path(pw, type, needle, TRUE, TRUE); - g_free(needle); - } - if (!list) return FALSE; - - found = g_list_find(list, pw->click_pi); - if (found && found->next) - { - found = found->next; - pi = found->data; - } - else - { - pi = list->data; - } - - pan_info_update(pw, pi); - image_scroll_to_point(pw->imd, pi->x + pi->width / 2, pi->y + pi->height / 2, 0.5, 0.5); - - buf = g_strdup_printf("%s ( %d / %d )", - _("partial match"), - g_list_index(list, pi) + 1, - g_list_length(list)); - pan_search_status(pw, buf); - g_free(buf); - - g_list_free(list); - - return TRUE; -} - -static gboolean valid_date_separator(gchar c) -{ - return (c == '/' || c == '-' || c == ' ' || c == '.' || c == ','); -} - -static GList *pan_search_by_date_val(PanWindow *pw, PanItemType type, - gint year, gint month, gint day, - const gchar *key) -{ - GList *list = NULL; - GList *work; - - work = g_list_last(pw->list_static); - while (work) - { - PanItem *pi; - - pi = work->data; - work = work->prev; - - if (pi->fd && (pi->type == type || type == PAN_ITEM_NONE) && - ((!key && !pi->key) || (key && pi->key && strcmp(key, pi->key) == 0))) - { - struct tm *tl; - - tl = localtime(&pi->fd->date); - if (tl) - { - gint match; - - match = (tl->tm_year == year - 1900); - if (match && month >= 0) match = (tl->tm_mon == month - 1); - if (match && day > 0) match = (tl->tm_mday == day); - - if (match) list = g_list_prepend(list, pi); - } - } - } - - return g_list_reverse(list); -} - -static gboolean pan_search_by_date(PanWindow *pw, const gchar *text) -{ - PanItem *pi = NULL; - GList *list = NULL; - GList *found; - gint year; - gint month = -1; - gint day = -1; - gchar *ptr; - gchar *mptr; - struct tm *lt; - time_t t; - gchar *message; - gchar *buf; - gchar *buf_count; - - if (!text) return FALSE; - - ptr = (gchar *)text; - while (*ptr != '\0') - { - if (!g_unichar_isdigit(*ptr) && !valid_date_separator(*ptr)) return FALSE; - ptr++; - } - - t = time(NULL); - if (t == -1) return FALSE; - lt = localtime(&t); - if (!lt) return FALSE; - - if (valid_date_separator(*text)) - { - year = -1; - mptr = (gchar *)text; - } - else - { - year = (gint)strtol(text, &mptr, 10); - if (mptr == text) return FALSE; - } - - if (*mptr != '\0' && valid_date_separator(*mptr)) - { - gchar *dptr; - - mptr++; - month = strtol(mptr, &dptr, 10); - if (dptr == mptr) - { - if (valid_date_separator(*dptr)) - { - month = lt->tm_mon + 1; - dptr++; - } - else - { - month = -1; - } - } - if (dptr != mptr && *dptr != '\0' && valid_date_separator(*dptr)) - { - gchar *eptr; - dptr++; - day = strtol(dptr, &eptr, 10); - if (dptr == eptr) - { - day = lt->tm_mday; - } - } - } - - if (year == -1) - { - year = lt->tm_year + 1900; - } - else if (year < 100) - { - if (year > 70) - year+= 1900; - else - year+= 2000; - } - - if (year < 1970 || - month < -1 || month == 0 || month > 12 || - day < -1 || day == 0 || day > 31) return FALSE; - - t = pan_date_to_time(year, month, day); - if (t < 0) return FALSE; - - if (pw->layout == PAN_LAYOUT_CALENDAR) - { - list = pan_search_by_date_val(pw, PAN_ITEM_BOX, year, month, day, "day"); - } - else - { - PanItemType type; - - type = (pw->size > PAN_IMAGE_SIZE_THUMB_LARGE) ? PAN_ITEM_IMAGE : PAN_ITEM_THUMB; - list = pan_search_by_date_val(pw, type, year, month, day, NULL); - } - - if (list) - { - found = g_list_find(list, pw->search_pi); - if (found && found->next) - { - found = found->next; - pi = found->data; - } - else - { - pi = list->data; - } - } - - pw->search_pi = pi; - - if (pw->layout == PAN_LAYOUT_CALENDAR && pi && pi->type == PAN_ITEM_BOX) - { - pan_info_update(pw, NULL); - pan_calendar_update(pw, pi); - image_scroll_to_point(pw->imd, - pi->x + pi->width / 2, - pi->y + pi->height / 2, 0.5, 0.5); - } - else if (pi) - { - pan_info_update(pw, pi); - image_scroll_to_point(pw->imd, - pi->x - PAN_BOX_BORDER * 5 / 2, - pi->y, 0.0, 0.5); - } - - if (month > 0) - { - buf = pan_date_value_string(t, PAN_DATE_LENGTH_MONTH); - if (day > 0) - { - gchar *tmp; - tmp = buf; - buf = g_strdup_printf("%d %s", day, tmp); - g_free(tmp); - } - } - else - { - buf = pan_date_value_string(t, PAN_DATE_LENGTH_YEAR); - } - - if (pi) - { - buf_count = g_strdup_printf("( %d / %d )", - g_list_index(list, pi) + 1, - g_list_length(list)); - } - else - { - buf_count = g_strdup_printf("(%s)", _("no match")); - } - - message = g_strdup_printf("%s %s %s", _("Date:"), buf, buf_count); - g_free(buf); - g_free(buf_count); - pan_search_status(pw, message); - g_free(message); - - g_list_free(list); - - return TRUE; -} - -static void pan_search_activate_cb(const gchar *text, gpointer data) -{ - PanWindow *pw = data; - - if (!text) return; - - tab_completion_append_to_history(pw->search_entry, text); - - if (pan_search_by_path(pw, text)) return; - - if ((pw->layout == PAN_LAYOUT_TIMELINE || - pw->layout == PAN_LAYOUT_CALENDAR) && - pan_search_by_date(pw, text)) - { - return; - } - - if (pan_search_by_partial(pw, text)) return; - - pan_search_status(pw, _("no match")); -} - -static void pan_search_activate(PanWindow *pw) -{ - gchar *text; - - text = g_strdup(gtk_entry_get_text(GTK_ENTRY(pw->search_entry))); - pan_search_activate_cb(text, pw); - g_free(text); -} - -static void pan_search_toggle_cb(GtkWidget *button, gpointer data) -{ - PanWindow *pw = data; - gboolean visible; - - visible = gtk_widget_get_visible(pw->search_box); - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)) == visible) return; - - if (visible) - { - gtk_widget_hide(pw->search_box); - gtk_arrow_set(GTK_ARROW(pw->search_button_arrow), GTK_ARROW_UP, GTK_SHADOW_NONE); - } - else - { - gtk_widget_show(pw->search_box); - gtk_arrow_set(GTK_ARROW(pw->search_button_arrow), GTK_ARROW_DOWN, GTK_SHADOW_NONE); - gtk_widget_grab_focus(pw->search_entry); - } -} - -static void pan_search_toggle_visible(PanWindow *pw, gboolean enable) -{ - if (pw->fs) return; - - if (enable) - { - if (gtk_widget_get_visible(pw->search_box)) - { - gtk_widget_grab_focus(pw->search_entry); - } - else - { - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pw->search_button), TRUE); - } - } - else - { - if (gtk_widget_get_visible(pw->search_entry)) - { - if (gtk_widget_has_focus(pw->search_entry)) - { - gtk_widget_grab_focus(GTK_WIDGET(pw->imd->widget)); - } - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pw->search_button), FALSE); - } - } -} - - /* *----------------------------------------------------------------------------- * main window diff --git a/src/pan-view/pan-view.h b/src/pan-view/pan-view.h index 7a7ddc7d..586f173e 100644 --- a/src/pan-view/pan-view.h +++ b/src/pan-view/pan-view.h @@ -32,6 +32,7 @@ void pan_cache_sync_date(PanWindow *pw, GList *list); GList *pan_cache_sort(GList *list, SortType method, gboolean ascend); +void pan_info_update(PanWindow *pw, PanItem *pi); #endif /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */