diff options
Diffstat (limited to 'data')
-rw-r--r-- | data/Makefile.am | 21 | ||||
-rw-r--r-- | data/lineup-parameters.c | 482 | ||||
-rwxr-xr-x | data/run-uncrustify.sh | 16 | ||||
-rw-r--r-- | data/uncrustify.cfg | 126 |
4 files changed, 643 insertions, 2 deletions
diff --git a/data/Makefile.am b/data/Makefile.am index f2cfb7d3e..470ee039e 100644 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -1,7 +1,24 @@ -NULL= +include $(top_srcdir)/Makefile.shared SUBDIRS = icons +AM_CPPFLAGS=\ + $(COMMON_CFLAGS) \ + $(NULL) + +noinst_PROGRAMS= \ + lineup-parameters \ + $(NULL) + +lineup_parameters_SOURCES= \ + lineup-parameters.c \ + $(NULL) + +lineup_parameters_LDADD= \ + $(CORE_LIBS) \ + $(COMMON_LIBS) \ + $(NULL) + desktopdir = $(datadir)/applications desktop_in_files = \ org.gnome.Nautilus.desktop.in \ @@ -66,11 +83,11 @@ CLEANFILES = \ $(desktop_DATA) \ $(service_DATA) \ $(appdata_DATA) \ + $(noinst_PROGRAMS) \ $(NULL) if ENABLE_DESKTOP CLEANFILES += $(autostart_DATA) endif - -include $(top_srcdir)/git.mk diff --git a/data/lineup-parameters.c b/data/lineup-parameters.c new file mode 100644 index 000000000..c1db2a726 --- /dev/null +++ b/data/lineup-parameters.c @@ -0,0 +1,482 @@ +/* + * This file is part of gnome-c-utils. + * + * Copyright © 2013 Sébastien Wilmet <swilmet@gnome.org> + * + * gnome-c-utils 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 3 of the License, or + * (at your option) any later version. + * + * gnome-c-utils 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 gnome-c-utils. If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * Line up parameters of function declarations. + * + * Usage: lineup-parameters [file] + * If the file is not given, stdin is read. + * The result is printed to stdout. + * + * The restrictions: + * - The function name must be at column 0, followed by a space and an opening + * parenthesis; + * - One parameter per line; + * - A paramater must follow certain rules (see the regex in the code), but it + * doesn't accept all possibilities of the C language. + * - The opening curly brace ("{") of the function must also be at column 0. + * + * If one restriction is missing, the function declaration is not modified. + * + * Example: + * + * gboolean + * frobnitz (Frobnitz *frobnitz, + * gint magic_number, + * GError **error) + * { + * ... + * } + * + * Becomes: + * + * gboolean + * frobnitz (Frobnitz *frobnitz, + * gint magic_number, + * GError **error) + * { + * ... + * } + */ + +/* + * Use with Vim: + * + * Although this script can be used in Vim (or other text editors), a Vim plugin + * exists: + * http://damien.lespiau.name/blog/2009/12/07/aligning-c-function-parameters-with-vim/ + * + * You can use a selection: + * - place the cursor at the function's name; + * - press V to start the line selection; + * - press ]] to go to the "{"; + * - type ":" followed by "!lineup-parameters". + * + * Note: the "{" is required in the selection, to detect that we are in a + * function declaration. + * + * You can easily map these steps with a keybinding (F8 in the example below). + * Note that I'm not a Vim expert, so there is maybe a better way to configure + * this stuff. + * + * function! LineupParameters() + * let l:winview = winsaveview() + * execute "normal {V]]:!lineup-parameters\<CR>" + * call winrestview(l:winview) + * endfunction + * + * autocmd Filetype c map <F8> :call LineupParameters()<CR> + */ + +/* TODO support "..." vararg parameter. */ + +#include <gio/gio.h> +#include <gio/gunixinputstream.h> +#include <stdlib.h> +#include <string.h> +#include <locale.h> +#include <unistd.h> + +#define USE_TABS FALSE + +typedef struct +{ + gchar *type; + guint nb_stars; + gchar *name; +} ParameterInfo; + +static void +parameter_info_free (ParameterInfo *param_info) +{ + g_free (param_info->type); + g_free (param_info->name); + g_slice_free (ParameterInfo, param_info); +} + +static gboolean +match_function_name (const gchar *line, + gchar **function_name, + gint *first_param_pos) +{ + static GRegex *regex = NULL; + GMatchInfo *match_info; + gint end_pos; + gboolean match = FALSE; + + if (G_UNLIKELY (regex == NULL)) + regex = g_regex_new ("^(\\w+) ?\\(", G_REGEX_OPTIMIZE, 0, NULL); + + g_regex_match (regex, line, 0, &match_info); + + if (g_match_info_matches (match_info) && + g_match_info_fetch_pos (match_info, 1, NULL, &end_pos) && + g_match_info_fetch_pos (match_info, 0, NULL, first_param_pos)) + { + match = TRUE; + + if (function_name != NULL) + *function_name = g_strndup (line, end_pos); + } + + g_match_info_free (match_info); + return match; +} + +static gboolean +match_parameter (gchar *line, + ParameterInfo **info, + gboolean *is_last_parameter) +{ + static GRegex *regex = NULL; + GMatchInfo *match_info; + gboolean first_param; + gint start_pos = 0; + + if (G_UNLIKELY (regex == NULL)) + regex = g_regex_new ("^\\s*(?<type>(const\\s+)?\\w+)\\s+(?<stars>\\**)\\s*(?<name>\\w+)\\s*(?<end>,|\\))\\s*$", + G_REGEX_OPTIMIZE, + 0, + NULL); + + if (is_last_parameter != NULL) + *is_last_parameter = FALSE; + + match_function_name (line, NULL, &start_pos); + + g_regex_match (regex, line + start_pos, 0, &match_info); + + if (!g_match_info_matches (match_info)) + { + g_match_info_free (match_info); + return FALSE; + } + + if (info != NULL) + { + gchar *stars; + + *info = g_slice_new0 (ParameterInfo); + + (*info)->type = g_match_info_fetch_named (match_info, "type"); + (*info)->name = g_match_info_fetch_named (match_info, "name"); + g_assert ((*info)->type != NULL); + g_assert ((*info)->name != NULL); + + stars = g_match_info_fetch_named (match_info, "stars"); + (*info)->nb_stars = strlen (stars); + g_free (stars); + } + + if (is_last_parameter != NULL) + { + gchar *end = g_match_info_fetch_named (match_info, "end"); + *is_last_parameter = g_str_equal (end, ")"); + g_free (end); + } + + g_match_info_free (match_info); + return TRUE; +} + +static gboolean +match_opening_curly_brace (const gchar *line) +{ + static GRegex *regex = NULL; + + if (G_UNLIKELY (regex == NULL)) + regex = g_regex_new ("^{\\s*$", G_REGEX_OPTIMIZE, 0, NULL); + + return g_regex_match (regex, line, 0, NULL); +} + +/* Returns the number of lines that take the function declaration. + * Returns 0 if not a function declaration. */ +static guint +get_function_declaration_length (gchar **lines) +{ + guint nb_lines = 1; + gchar **cur_line = lines; + + while (*cur_line != NULL) + { + gboolean match_param; + gboolean is_last_param; + + match_param = match_parameter (*cur_line, NULL, &is_last_param); + + if (is_last_param) + { + gchar *next_line = *(cur_line + 1); + + if (next_line == NULL || + !match_opening_curly_brace (next_line)) + return 0; + + return nb_lines; + } + + if (!match_param) + return 0; + + nb_lines++; + cur_line++; + } +} + +static GSList * +get_list_parameter_infos (gchar **lines, + guint length) +{ + GSList *list = NULL; + gint i; + + for (i = length - 1; i >= 0; i--) + { + ParameterInfo *info = NULL; + + match_parameter (lines[i], &info, NULL); + g_assert (info != NULL); + + list = g_slist_prepend (list, info); + } + + return list; +} + +static void +compute_spacing (GSList *parameter_infos, + guint *max_type_length, + guint *max_stars_length) +{ + GSList *l; + *max_type_length = 0; + *max_stars_length = 0; + + for (l = parameter_infos; l != NULL; l = l->next) + { + ParameterInfo *info = l->data; + guint type_length = strlen (info->type); + + if (type_length > *max_type_length) + *max_type_length = type_length; + + if (info->nb_stars > *max_stars_length) + *max_stars_length = info->nb_stars; + } +} + +static void +print_parameter (ParameterInfo *info, + guint max_type_length, + guint max_stars_length) +{ + gint type_length; + gint nb_spaces; + gchar *spaces; + gchar *stars; + + g_print ("%s", info->type); + + type_length = strlen (info->type); + nb_spaces = max_type_length - type_length; + g_assert (nb_spaces >= 0); + + spaces = g_strnfill (nb_spaces, ' '); + g_print ("%s ", spaces); + g_free (spaces); + + nb_spaces = max_stars_length - info->nb_stars; + g_assert (nb_spaces >= 0); + spaces = g_strnfill (nb_spaces, ' '); + g_print ("%s", spaces); + g_free (spaces); + + stars = g_strnfill (info->nb_stars, '*'); + g_print ("%s", stars); + g_free (stars); + + g_print ("%s", info->name); +} + +static void +print_function_declaration (gchar **lines, + guint length) +{ + gchar **cur_line = lines; + gchar *function_name; + gint nb_spaces_to_parenthesis; + GSList *parameter_infos; + GSList *l; + guint max_type_length; + guint max_stars_length; + gchar *spaces; + + if (!match_function_name (*cur_line, &function_name, NULL)) + g_error ("The line doesn't match a function name."); + + g_print ("%s (", function_name); + + nb_spaces_to_parenthesis = strlen (function_name) + 2; + + if (USE_TABS) + { + gchar *tabs = g_strnfill (nb_spaces_to_parenthesis / 8, '\t'); + gchar *spaces_after_tabs = g_strnfill (nb_spaces_to_parenthesis % 8, ' '); + + spaces = g_strdup_printf ("%s%s", tabs, spaces_after_tabs); + + g_free (tabs); + g_free (spaces_after_tabs); + } + else + { + spaces = g_strnfill (nb_spaces_to_parenthesis, ' '); + } + + parameter_infos = get_list_parameter_infos (lines, length); + compute_spacing (parameter_infos, &max_type_length, &max_stars_length); + + for (l = parameter_infos; l != NULL; l = l->next) + { + ParameterInfo *info = l->data; + + if (l != parameter_infos) + g_print ("%s", spaces); + + print_parameter (info, max_type_length, max_stars_length); + + if (l->next != NULL) + g_print (",\n"); + } + + g_print (")\n"); + + g_free (function_name); + g_free (spaces); + g_slist_free_full (parameter_infos, (GDestroyNotify)parameter_info_free); +} + +static void +parse_contents (gchar **lines) +{ + gchar **cur_line = lines; + + /* Skip the empty last line, to avoid adding an extra \n. */ + for (cur_line = lines; cur_line[0] != NULL && cur_line[1] != NULL; cur_line++) + { + guint length; + + if (!match_function_name (*cur_line, NULL, NULL)) + { + g_print ("%s\n", *cur_line); + continue; + } + + length = get_function_declaration_length (cur_line); + + if (length == 0) + { + g_print ("%s\n", *cur_line); + continue; + } + + print_function_declaration (cur_line, length); + + cur_line += length - 1; + } +} + +static gchar * +get_file_contents (gchar *arg) +{ + GFile *file; + gchar *path; + gchar *contents; + GError *error = NULL; + + file = g_file_new_for_commandline_arg (arg); + path = g_file_get_path (file); + g_file_get_contents (path, &contents, NULL, &error); + + if (error != NULL) + g_error ("Impossible to get file contents: %s", error->message); + + g_object_unref (file); + g_free (path); + return contents; +} + +static gchar * +get_stdin_contents (void) +{ + GInputStream *stream; + GString *string; + GError *error = NULL; + + stream = g_unix_input_stream_new (STDIN_FILENO, FALSE); + string = g_string_new (""); + + while (TRUE) + { + gchar buffer[4097] = { '\0' }; + gssize nb_bytes_read = g_input_stream_read (stream, buffer, 4096, NULL, &error); + + if (nb_bytes_read == 0) + break; + + if (error != NULL) + g_error ("Impossible to read stdin: %s", error->message); + + g_string_append (string, buffer); + } + + g_input_stream_close (stream, NULL, NULL); + g_object_unref (stream); + + return g_string_free (string, FALSE); +} + +gint +main (gint argc, + gchar *argv[]) +{ + gchar *contents; + gchar **contents_lines; + + setlocale (LC_ALL, ""); + + if (argc > 2) + { + g_printerr ("Usage: %s [file]\n", argv[0]); + return EXIT_FAILURE; + } + + if (argc == 2) + contents = get_file_contents (argv[1]); + else + contents = get_stdin_contents (); + + contents_lines = g_strsplit (contents, "\n", 0); + g_free (contents); + + parse_contents (contents_lines); + + return EXIT_SUCCESS; +} diff --git a/data/run-uncrustify.sh b/data/run-uncrustify.sh new file mode 100755 index 000000000..3114f557d --- /dev/null +++ b/data/run-uncrustify.sh @@ -0,0 +1,16 @@ +#!/bin/bash +if [ -x "lineup-parameters" ]; +then + for DIR in ../src ../nautilus-desktop ../test ../libnautilus-extension ../eel ../nautilus-sendto-extension + do + for FILE in $(find $DIR -name "*.c") + do + # Aligning prototypes is not working yet, so avoid headers + uncrustify -c uncrustify.cfg --no-backup $FILE + ./lineup-parameters $FILE > $FILE.temp && mv $FILE.temp $FILE + done + done +else + echo "Script lineup-parameters does not exists here in (source directory)/data, probably because Nautilus was built in a different directory than the source directory. +Copy the program in the (build directory)/data/lineup-parameters here in (source directory)/data and run again run-uncrustify.sh." +fi diff --git a/data/uncrustify.cfg b/data/uncrustify.cfg new file mode 100644 index 000000000..61277c528 --- /dev/null +++ b/data/uncrustify.cfg @@ -0,0 +1,126 @@ +# +# 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, 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. +# +# Allman style +# + +# indent using tabs +output_tab_size = 4 +indent_columns = output_tab_size +indent_with_tabs = 0 + +# indent case +indent_switch_case = indent_columns +indent_case_brace = 0 + +# newlines +newlines = lf +nl_after_semicolon = true +nl_start_of_file = remove +nl_end_of_file = force +nl_end_of_file_min = 1 + +# spaces +sp_return_paren = force # "return (1);" vs "return(1);" +sp_sizeof_paren = force # "sizeof (int)" vs "sizeof(int)" +sp_assign = force +sp_arith = force +sp_bool = force +sp_compare = force +sp_after_comma = force +sp_case_label = force +sp_else_brace = force +sp_brace_else = force +sp_func_call_paren = force # "foo (" vs "foo(" +sp_func_proto_paren = force # "int foo ();" vs "int foo();" +sp_before_ptr_star = force +sp_after_ptr_star_qualifier = force # "const char * const" vs. "const char *const" +sp_after_ptr_star = remove +sp_between_ptr_star = remove # "**var" vs "* *var" +sp_inside_paren = remove # "( 1 )" vs "(1)" +sp_inside_fparen = remove # "( 1 )" vs "(1)" - functions +sp_inside_sparen = remove # "( 1 )" vs "(1)" - if/for/etc +sp_after_cast = force # "(int) a" vs "(int)a" +sp_func_call_user_paren = remove # For gettext, "_()" vs. "_ ()" +set func_call_user _ N_ C_ # Needed for sp_after_cast +sp_before_semi = remove +sp_paren_paren = remove # Space between (( and )) + +eat_blanks_before_close_brace = true +eat_blanks_after_open_brace = true + +# Allman style for curly braces +nl_assign_brace = force +nl_enum_brace = force +nl_union_brace = force +nl_struct_brace = force +nl_class_brace = force +nl_do_brace = force +nl_if_brace = force +nl_for_brace = force +nl_else_brace = force +nl_elseif_brace = force +nl_while_brace = force +nl_switch_brace = force +nl_before_case = true +nl_fcall_brace = force +nl_fdef_brace = force +nl_brace_else = force +nl_brace_while = force +nl_case_colon_brace = force +nl_after_brace_open = true + +# Function calls and parameters +nl_func_paren = remove +nl_func_def_paren = remove +nl_func_decl_start = remove +nl_func_def_start = remove +nl_func_decl_args = force +nl_func_def_args = force +nl_func_decl_end = remove +nl_func_def_end = remove + +# Code modifying options (non-whitespace) +mod_full_brace_do = force +mod_full_brace_for = force +mod_full_brace_function = force +mod_full_brace_if = force +mod_full_brace_while = force +mod_case_brace = add + +# Align +align_func_params = true +align_single_line_func = true +align_var_def_star_style = 2 + +# one liners +nl_func_leave_one_liners = true +nl_enum_leave_one_liners = true +nl_assign_leave_one_liners = true + +# Comments +cmt_cpp_to_c = true # "/* */" vs. "//" +cmt_convert_tab_to_spaces = true +#cmt_reflow_mode = 2 # Full reflow (seems doesn't work quite well, it doesn't reorder the comments) +#cmt_width = 80 # Line width +cmt_star_cont = true # Whether to put a star on subsequent comment lines +cmt_sp_after_star_cont = 1 # The number of spaces to insert after the star on subsequent comment lines +cmt_c_nl_start = false # false/true +cmt_c_nl_end = true # false/true + +# Encoding +utf8_bom = remove +utf8_force = true + |