[nautilus] general: add uncrustify script



commit 4cafccd82859a4ee0bdfad3e31a310f2d94c0485
Author: Carlos Soriano <csoriano gnome org>
Date:   Mon Apr 18 18:57:12 2016 +0200

    general: add uncrustify script
    
    The current style of nautilus is rather poor and mixes at least 3
    different code styles.
    
    Specific issues that affect the most common contributors to Nautilus
    performance are:
    - tabs for multiline alignment.
    - mix of tabs and spaces.
    - errors on no braced one liners conditionals.
    - errors on non braced case statements with variable declarations.
    
    So I would say requirements for the style is to address the previous
    issues and also be a well known style. I don't want new contributors
    to see a new style completely different from C books authors.
    
    So far, I found Allman (aka BSD) style which seems the choice of most C
    books authors as far as I can see on internet, and it address the
    previous mentioned issues.
    
    Since uncrustify doesn't support the aligment of parameters we do for
    multiple stars "**", we also added a script made by Sebastian Wilmet
    to align those.
    
    As a matter of practicity I'm going to convert all Nautilus style to
    this one, and if the next person who contributes most on Nautilus has
    a different choice, please feel free to change it to whatever makes your
    performance and your contributors performance the best.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=770564

 data/Makefile.am         |   21 ++-
 data/lineup-parameters.c |  482 ++++++++++++++++++++++++++++++++++++++++++++++
 data/run-uncrustify.sh   |   16 ++
 data/uncrustify.cfg      |  126 ++++++++++++
 test/uncrustify-sample.c |   63 ++++++
 5 files changed, 706 insertions(+), 2 deletions(-)
---
diff --git a/data/Makefile.am b/data/Makefile.am
index f2cfb7d..470ee03 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 0000000..c1db2a7
--- /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 0000000..3114f55
--- /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 0000000..61277c5
--- /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
+
diff --git a/test/uncrustify-sample.c b/test/uncrustify-sample.c
new file mode 100644
index 0000000..2ed14be
--- /dev/null
+++ b/test/uncrustify-sample.c
@@ -0,0 +1,63 @@
+/*
+Extremely poorly formatted code to test uncrustify.cfg against the contiki code style
+ */
+
+#if defined (FOO)
+ # define BAR 3
+#else
+ # define BAR 3
+# endif
+
+/* Aligment of parameters doesn't work as completely expected. Should align the
+ * stars themselves. */
+static int    some_function ( int  *f  , char **c, LongTypeException a)      {
+
+       /* This is indented with a tab. Should become spaces */
+       int a = 5;      // This should become a C comment
+       int d= - 10;    /* Space around assignment, No space between - and 10 */
+       int* b;         /* no space before the *, yes space between * and variable name */
+
+  some_function(
+               a,
+               b
+       )
+
+/* Should indent the for correctly and sort out spacing mess:
+ - for(i = 0; i < 10; ++i)
+ - Should pull the opening brace up to the same line as the for
+*/
+for(  i=0  ;i<10; ++ i ) {     if (a < 0) {
+         a= ! c ; /* Should add space after a and remove space before and after c */
+
+         /* } else { always in the same line */
+       }
+       else
+       {
+           /* incorrect indentation here */
+
+           f();
+       }
+       }
+
+  b = & c;   /* 'address of' adjacent to variable */
+  * b = 3;    /* dereference: no space */
+
+  /* Should automatically add braces below */
+  if(a == 0)
+    printf ( "a\n") ;
+
+  while(1)  ; /* This needs fixed */
+
+  switch(a) {
+  case    3  :
+4;
+5;
+  break;
+  }
+
+  /* No blank lines before the closing brace */
+
+  return (-1); /* No parenthesis around return values */
+
+
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]