Commit 89fda8c3 authored by Christian Hergert's avatar Christian Hergert

format C function parameters in GNOME-style

parent 7a7a2b10
......@@ -108,7 +108,7 @@ girst_sources = [
mapfile = 'src/girst.map'
vflag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), mapfile)
gir2rst = executable('gir2rst', girst_sources + [girst_resources[0]],
gir2rst = executable('gir2rst', girst_sources + ['src/c-parse-helper.c'] + [girst_resources[0]],
dependencies: [ glib_dep, gir_dep, tmpl_dep, xml_dep, cc.find_library('dl') ],
link_args: ['-Wl,--no-undefined', '-rdynamic', vflag],
link_depends: mapfile,
......
/* c-parse-helper.c
*
* Copyright © 2014 Christian Hergert <christian@hergert.me>
*
* 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/>.
*/
#define G_LOG_DOMAIN "c-parser"
#include <string.h>
#include "c-parse-helper.h"
void
parameter_free (Parameter *p)
{
if (p)
{
g_free (p->name);
g_free (p->type);
g_free (p);
}
}
Parameter *
parameter_copy (const Parameter *src)
{
Parameter *copy;
copy = g_new0 (Parameter, 1);
copy->name = g_strdup (src->name);
copy->type = g_strdup (src->type);
copy->ellipsis = src->ellipsis;
copy->n_star = src->n_star;
return copy;
}
gboolean
parameter_validate (Parameter *param)
{
const gchar *tmp;
if (param->ellipsis)
return TRUE;
if (!param->name || !param->type)
return FALSE;
for (tmp = param->name; *tmp; tmp = g_utf8_next_char (tmp))
{
gunichar ch = g_utf8_get_char (tmp);
switch (ch) {
case '_':
case '[':
case ']':
continue;
default:
if (g_unichar_isalnum (ch))
continue;
break;
}
return FALSE;
}
for (tmp = param->type; *tmp; tmp = g_utf8_next_char (tmp))
{
gunichar ch = g_utf8_get_char (tmp);
switch (ch) {
case '*':
case ' ':
case '_':
continue;
default:
if (g_unichar_isalnum (ch))
continue;
break;
}
return FALSE;
}
return TRUE;
}
static void
parameter_compute (Parameter *param)
{
const gchar *tmp;
gchar *rev;
guint n_star = 0;
rev = g_utf8_strreverse (param->type, -1);
for (tmp = rev; tmp; tmp = g_utf8_next_char (tmp))
{
switch (g_utf8_get_char (tmp))
{
case ' ':
break;
case '*':
n_star++;
break;
default:
if (n_star)
{
gchar *cleaned;
cleaned = g_strstrip (g_utf8_strreverse (tmp, -1));
g_free (param->type);
param->type = cleaned;
}
goto finish;
}
}
finish:
param->n_star = n_star;
g_free (rev);
}
GSList *
parse_parameters (const gchar *text)
{
GSList *ret = NULL;
gchar **parts = NULL;
guint i;
parts = g_strsplit (text, ",", 0);
for (i = 0; parts [i]; i++)
{
const gchar *tmp;
const gchar *word;
word = g_strstrip (parts [i]);
if (!*word)
goto failure;
if (g_strcmp0 (word, "...") == 0)
{
Parameter param = { NULL, NULL, TRUE };
ret = g_slist_append (ret, parameter_copy (&param));
continue;
}
/*
* Check that each word only contains valid characters for a
* parameter list.
*/
for (tmp = word; *tmp; tmp = g_utf8_next_char (tmp))
{
gunichar ch;
ch = g_utf8_get_char (tmp);
switch (ch)
{
case '\t':
case ' ':
case '*':
case '_':
case '[':
case ']':
break;
default:
if (g_unichar_isalnum (ch))
break;
goto failure;
}
}
if (strchr (word, '[') && strchr (word, ']'))
{
/*
* TODO: Special case parsing of parameters that have [] after the
* name. Such as "char foo[12]" or "char foo[static 12]".
*/
}
else
{
const gchar *name_sep;
Parameter param = { 0 };
gboolean success = FALSE;
gchar *reversed = NULL;
gchar *name_rev = NULL;
reversed = g_utf8_strreverse (word, -1);
name_sep = strpbrk (reversed, "\t\n *");
if (name_sep && *name_sep && *(name_sep + 1))
{
name_rev = g_strndup (reversed, name_sep - reversed);
param.name = g_strstrip (g_utf8_strreverse (name_rev, -1));
param.type = g_strstrip (g_utf8_strreverse (name_sep, -1));
parameter_compute (&param);
if (parameter_validate (&param))
{
ret = g_slist_append (ret, parameter_copy (&param));
success = TRUE;
}
g_free (param.name);
g_free (param.type);
g_free (name_rev);
}
g_free (reversed);
if (success)
continue;
}
goto failure;
}
goto cleanup;
failure:
g_slist_foreach (ret, (GFunc)parameter_free, NULL);
g_clear_pointer (&ret, g_slist_free);
cleanup:
g_strfreev (parts);
return ret;
}
/* c-parse-helper.h
*
* Copyright © 2014 Christian Hergert <christian@hergert.me>
*
* 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/>.
*/
#pragma once
#include <glib.h>
G_BEGIN_DECLS
typedef struct
{
gchar *type;
gchar *name;
guint ellipsis : 1;
guint n_star : 4;
} Parameter;
gboolean parameter_validate (Parameter *param);
void parameter_free (Parameter *p);
Parameter *parameter_copy (const Parameter *src);
GSList *parse_parameters (const gchar *text);
G_END_DECLS
......@@ -20,6 +20,8 @@
#include <string.h>
#include "c-parse-helper.h"
#include "girst-cache.h"
#include "girst-signature.h"
#include "girst-util.h"
......@@ -1084,14 +1086,90 @@ girst_parser_object_short_cdoc (GirstParserObject *self)
return NULL;
}
static gchar *
format_parameter (const Parameter *param,
guint max_type,
guint max_star)
{
GString *str;
guint i;
if (param->ellipsis)
return g_strdup ("...");
str = g_string_new (param->type);
for (i = str->len; i < max_type; i++)
g_string_append_c (str, ' ');
g_string_append_c (str, ' ');
for (i = max_star; i > 0; i--)
{
if (i <= param->n_star)
g_string_append_c (str, '*');
else
g_string_append_c (str, ' ');
}
g_string_append (str, param->name);
return g_string_free (str, FALSE);
}
static gchar *
reformat_parameters (const gchar *input,
guint prefix)
{
GSList *params = parse_parameters (input);
g_autoptr(GString) join = g_string_new (",\n");
GString *str = g_string_new (NULL);
guint max_star = 0;
guint max_type = 0;
if (girst_str_empty0 (input) || girst_str_equal0 (input, "void"))
{
g_string_append (str, "void");
goto finish;
}
for (guint i = 0; i < prefix; i++)
g_string_append_c (join, ' ');
for (const GSList *iter = params; iter; iter = iter->next)
{
Parameter *p = iter->data;
if (p->n_star)
max_star = MAX (max_star, p->n_star);
if (p->type)
max_type = MAX (max_type, strlen (p->type));
}
for (const GSList *iter = params; iter; iter = iter->next)
{
g_autofree gchar *param_str = NULL;
if (iter != params)
g_string_append_len (str, join->str, join->len);
param_str = format_parameter (iter->data, max_type, max_star);
g_string_append (str, param_str);
}
finish:
g_slist_free_full (params, (GDestroyNotify)parameter_free);
return g_string_free (str, FALSE);
}
gchar *
girst_parser_object_get_signature (GirstParserObject *self)
{
g_autoptr(GString) str = NULL;
g_autoptr(GString) param_str = NULL;
g_autofree gchar *formatted = NULL;
GirstParserObject *return_value;
GirstParserObject *params;
GPtrArray *children;
guint pcount = 0;
guint space = 0;
guint begin;
......@@ -1105,6 +1183,7 @@ girst_parser_object_get_signature (GirstParserObject *self)
return NULL;
str = g_string_new (NULL);
param_str = g_string_new (NULL);
/* Add our return type on a single line */
......@@ -1155,8 +1234,12 @@ girst_parser_object_get_signature (GirstParserObject *self)
else if (GIRST_IS_VIRTUAL_METHOD (self))
{
const gchar *c_identifier = girst_virtual_method_get_c_identifier (GIRST_VIRTUAL_METHOD (self));
const gchar *name = girst_virtual_method_get_name (GIRST_VIRTUAL_METHOD (self));
g_string_append_printf (str, "%s ", c_identifier);
if (c_identifier != NULL)
g_string_append_printf (str, "%s ", c_identifier);
else
g_string_append_printf (str, "(*%s) ", name);
}
else
g_return_val_if_reached (NULL);
......@@ -1191,27 +1274,25 @@ girst_parser_object_get_signature (GirstParserObject *self)
!GIRST_IS_VARARGS (child))
continue;
if (pcount != 0)
{
for (guint j = 0; j < space; j++)
g_string_append_c (str, ' ');
}
g_string_append_c (param_str, ' ');
if (GIRST_IS_VARARGS (child))
{
g_string_append (str, "...,\n");
g_string_append (param_str, "...");
break;
}
g_object_get (child, "name", &name, NULL);
c_type = girst_parser_object_get_lhs_ctype (child);
g_string_append_printf (str, "%s %s,\n", c_type, name);
pcount++;
g_string_append_printf (param_str, "%s %s, ", c_type, name);
}
g_string_truncate (str, str->len - 2);
if (param_str->len > 2)
g_string_truncate (param_str, param_str->len - 2);
formatted = reformat_parameters (param_str->str, space);
g_string_append (str, formatted);
cleanup:
g_string_append (str, ");");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment