Commit 7b469dfa authored by Ondrej Holy's avatar Ondrej Holy
Browse files

ci: Use lineup-parameters python script

The lineup-parameters.c is hard to use with meson. Let's use the python
rewrite from
https://gitlab.gnome.org/GNOME/epiphany/-/blob/master/data/lineup-parameters
instead.
parent 44d574e1
......@@ -34,7 +34,6 @@ style check:
- 'uncrustify.diff'
expire_in: 14 days
script:
- gcc data/lineup-parameters.c `pkg-config --cflags --libs gio-2.0 gio-unix-2.0` -o data/lineup-parameters
- LANG=C.utf8 data/run-uncrustify.sh
- git diff --exit-code | tee uncrustify.diff
except:
......
/lineup-parameters
/nautilus-autorun-software.desktop
/org.freedesktop.FileManager1.service
/org.gnome.Nautilus.appdata.xml
......
#!/usr/bin/env python3
#
# Copyright © 2019 Michael Catanzaro <mcatanzaro@gnome.org>
#
# 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 3 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, see <http://www.gnu.org/licenses/>.
# Based on original C lineup-parameters by Sébastien Wilmet <swilmet@gnome.org>
# Rewritten in Python to allow simple execution from source directory.
#
# 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 parameter 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)
# {
# ...
# }
#
# TODO: support "..." vararg parameter
import argparse
import re
import sys
from typing import NamedTuple
# https://regexr.com/ is your friend.
functionNameRegex = re.compile(r'^(\w+) ?\(')
parameterRegex = re.compile(
r'^\s*(?P<type>(const\s+)?\w+)'
r'\s+(?P<stars>\**)'
r'\s*(?P<name>\w+)'
r'\s*(?P<end>,|\))'
r'\s*$')
openingCurlyBraceRegex = re.compile(r'^{\s*$')
def matchFunctionName(line):
match = functionNameRegex.match(line)
if match:
functionName = match.group(1)
firstParamPosition = match.end(0)
return (functionName, firstParamPosition)
return (None, 0)
class ParameterInfo(NamedTuple):
paramType: str
name: str
numStars: int
isLastParameter: bool
def matchParameter(line):
_, firstParamPosition = matchFunctionName(line)
match = parameterRegex.match(line[firstParamPosition:])
if match is None:
return None
paramType = match.group('type')
assert(paramType is not None)
name = match.group('name')
assert(name is not None)
stars = match.group('stars')
numStars = len(stars) if stars is not None else 0
end = match.group('end')
isLastParameter = True if end is not None and end == ')' else False
return ParameterInfo(paramType, name, numStars, isLastParameter)
def matchOpeningCurlyBrace(line):
return True if openingCurlyBraceRegex.match(line) is not None else False
# Length returned is number of lines the declaration takes up
def getFunctionDeclarationLength(remainingLines):
for i in range(len(remainingLines)):
currentLine = remainingLines[i]
parameterInfo = matchParameter(currentLine)
if parameterInfo is None:
return 0
if parameterInfo.isLastParameter:
if i + 1 == len(remainingLines):
return 0
nextLine = remainingLines[i + 1]
if not matchOpeningCurlyBrace(nextLine):
return 0
return i + 1
return 0
def getParameterInfos(remainingLines, length):
parameterInfos = []
for i in range(length):
parameterInfos.append(matchParameter(remainingLines[i]))
return parameterInfos
def computeSpacing(parameterInfos):
maxTypeLength = 0
maxStarsLength = 0
for parameterInfo in parameterInfos:
maxTypeLength = max(maxTypeLength, len(parameterInfo.paramType))
maxStarsLength = max(maxStarsLength, parameterInfo.numStars)
return (maxTypeLength, maxStarsLength)
def printParameter(parameterInfo, maxTypeLength, maxStarsLength, outfile):
outfile.write(f'{parameterInfo.paramType:<{maxTypeLength + 1}}')
paramNamePaddedWithStars = f'{parameterInfo.name:*>{parameterInfo.numStars + len(parameterInfo.name)}}'
outfile.write(f'{paramNamePaddedWithStars:>{maxStarsLength + len(parameterInfo.name)}}')
def printFunctionDeclaration(remainingLines, length, useTabs, outfile):
functionName, _ = matchFunctionName(remainingLines[0])
assert(functionName is not None)
outfile.write(f'{functionName} (')
numSpacesToParenthesis = len(functionName) + 2
whitespace = ''
if useTabs:
tabs = ''.ljust(numSpacesToParenthesis // 8, '\t')
spaces = ''.ljust(numSpacesToParenthesis % 8)
whitespace = tabs + spaces
else:
whitespace = ''.ljust(numSpacesToParenthesis)
parameterInfos = getParameterInfos(remainingLines, length)
maxTypeLength, maxStarsLength = computeSpacing(parameterInfos)
numParameters = len(parameterInfos)
for i in range(numParameters):
parameterInfo = parameterInfos[i]
if i != 0:
outfile.write(whitespace)
printParameter(parameterInfo, maxTypeLength, maxStarsLength, outfile)
if i + 1 != numParameters:
outfile.write(',\n')
outfile.write(')\n')
def parseContents(infile, useTabs, outfile):
lines = infile.readlines()
i = 0
while i < len(lines):
line = lines[i]
functionName, _ = matchFunctionName(line)
if functionName is None:
outfile.write(line)
i += 1
continue
remainingLines = lines[i:]
length = getFunctionDeclarationLength(remainingLines)
if length == 0:
outfile.write(line)
i += 1
continue
printFunctionDeclaration(remainingLines, length, useTabs, outfile)
i += length
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description='Line up parameters of C functions')
parser.add_argument('infile', nargs='?',
type=argparse.FileType('r'),
default=sys.stdin,
help='input C source file')
parser.add_argument('-o', metavar='outfile', nargs='?',
type=argparse.FileType('w'),
default=sys.stdout,
help='where to output modified file')
parser.add_argument('--tabs', action='store_true',
help='whether use tab characters in the output')
args = parser.parse_args()
parseContents(args.infile, args.tabs, args.o)
args.infile.close()
args.o.close()
/*
* 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;
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++;
}
/* should not be reachable - but silences a compiler warning */
return 0;
}
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;
}