Skip to content

Commit

Permalink
i.group: fit long names to fancy file listing (#1818)
Browse files Browse the repository at this point in the history
Addresses failure to list files with long names and
-Wformat-overflow= warnings.

There are two ways to list files in a group with i.group, a fancy one
with -l and a raw one with -lg. The fancy one is limited to a 80
character column, with angle bracket format: <mapname@mapset>. Before
this commit, if this "fancy" formatted string would exceed 80 char,
then buffer overflow occurs. With this commit, in the rare (theoretical)
occasion with very long mapname and/or mapset, they may be truncated
if needed (to fit in 80 chars).

Example of truncation in case of long map name:

ifonlythisisalandsatfilewithaveryverylongnameandagainifonlythisisalandsatfilewithaveryverylongnamePERMANENT

becomes:
<ifonlythisisalandsatfilewithaveryverylongnameandagainifonly...@permanent>
  • Loading branch information
nilason committed Aug 26, 2021
1 parent 2586b0e commit 4c7db5b
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 56 deletions.
1 change: 1 addition & 0 deletions include/grass/defs/imagery.h
Expand Up @@ -100,6 +100,7 @@ int I_iclass_write_signatures(struct Signature *, const char *);
/* list_gp.c */
int I_list_group(const char *, const struct Ref *, FILE *);
int I_list_group_simple(const struct Ref *, FILE *);
void I__list_group_name_fit(char *, const char *, const char *);

/* list_subgp.c */
char ** I_list_subgroups(const char *, int *);
Expand Down
92 changes: 64 additions & 28 deletions lib/imagery/list_gp.c
@@ -1,15 +1,15 @@
/*!
\file list_gp.c
\brief Imagery Library - List group
(C) 2001-2008 by the GRASS Development Team
This program is free software under the GNU General Public License
(>=v2). Read the file COPYING that comes with GRASS for details.
\author USA CERL
*/
\file list_gp.c
\brief Imagery Library - List group
(C) 2001-2008 by the GRASS Development Team
This program is free software under the GNU General Public License
(>=v2). Read the file COPYING that comes with GRASS for details.
\author USA CERL
*/

#include <string.h>
#include <grass/imagery.h>
Expand All @@ -31,30 +31,31 @@ int I_list_group(const char *group, const struct Ref *ref, FILE * fd)
int max;

if (ref->nfiles <= 0) {
fprintf(fd, _("group <%s> is empty\n"), group);
return 0;
fprintf(fd, _("group <%s> is empty\n"), group);
return 0;
}
max = 0;
for (i = 0; i < ref->nfiles; i++) {
sprintf(buf, "<%s@%s>", ref->file[i].name, ref->file[i].mapset);
len = strlen(buf) + 4;
if (len > max)
max = len;
I__list_group_name_fit(buf, ref->file[i].name, ref->file[i].mapset);
len = strlen(buf) + 4;
if (len > max)
max = len;
}
fprintf(fd, _("group <%s> references the following raster maps\n"), group);
fprintf(fd, _("group <%s> references the following raster maps\n"),
group);
fprintf(fd, "-------------\n");
tot_len = 0;
for (i = 0; i < ref->nfiles; i++) {
sprintf(buf, "<%s@%s>", ref->file[i].name, ref->file[i].mapset);
tot_len += max;
if (tot_len > 78) {
fprintf(fd, "\n");
tot_len = max;
}
fprintf(fd, "%-*s", max, buf);
I__list_group_name_fit(buf, ref->file[i].name, ref->file[i].mapset);
tot_len += max;
if (tot_len > 78) {
fprintf(fd, "\n");
tot_len = max;
}
fprintf(fd, "%-*s", max, buf);
}
if (tot_len)
fprintf(fd, "\n");
fprintf(fd, "\n");
fprintf(fd, "-------------\n");

return 0;
Expand All @@ -75,10 +76,45 @@ int I_list_group_simple(const struct Ref *ref, FILE * fd)
int i;

if (ref->nfiles <= 0)
return 0;
return 0;

for (i = 0; i < ref->nfiles; i++)
fprintf(fd, "%s@%s\n", ref->file[i].name, ref->file[i].mapset);
fprintf(fd, "%s@%s\n", ref->file[i].name, ref->file[i].mapset);

return 0;
}

/*!
* \brief Formats map name to fit in a 80 column layout
*
* Results in a map name in the "<map@mapset>" form.
* If necessary truncates relevant part(s) and denotes
* with ellipsis, e.g. "<verylongmapname...@mapset>".
*
* \param[out] buf formatted map name
* \param name map name
* \param mapset mapset name
*/
void I__list_group_name_fit(char *buf, const char *name, const char *mapset)
{
char *frmt;
char fr[32];
int name_length = (int)strlen(name);
int mapset_length = (int)strlen(mapset);

if (name_length + mapset_length + 3 < 75) {
frmt = "<%s@%s>";
}
else if (name_length > 35 && mapset_length > 35) {
frmt = "<%.33s...@%.32s...>";
}
else if (name_length > 35) {
sprintf(fr, "<%%.%ds...@%%s>", 68 - mapset_length);
frmt = fr;
}
else {
sprintf(fr, "<%%s@%%.%ds...>", 68 - name_length);
frmt = fr;
}
snprintf(buf, 75, frmt, name, mapset);
}
56 changes: 28 additions & 28 deletions lib/imagery/list_subgp.c
Expand Up @@ -17,8 +17,8 @@

char **list_subgroups(const char *group, const char *mapset, int *subgs_num)
{
/* Unlike I_list_subgroup and I_list_subgroup_simple this function
returns array of subgroup names, it does not use fprintf.
/* Unlike I_list_subgroup and I_list_subgroup_simple this function
returns array of subgroup names, it does not use fprintf.
This approach should make the function usable in more cases. */

char **subgs;
Expand All @@ -29,42 +29,43 @@ char **list_subgroups(const char *group, const char *mapset, int *subgs_num)
*subgs_num = 0;

if (I_find_group2(group, mapset) == 0)
return NULL;
return NULL;

sprintf(buf, "group/%s/subgroup", group);
G_file_name(path, buf, "", mapset);

if (G_lstat(path, &sb) || !S_ISDIR(sb.st_mode))
return NULL;
return NULL;

subgs = G_ls2(path, subgs_num);
return subgs;
}

/*!
* \brief Get list of subgroups which a group contatins.
*
*
* \param group group name
* \param[out] subgs_num number of subgroups which the group contains
* \return array of subgroup names
*/

char **I_list_subgroups(const char *group, int *subgs_num)
{

return list_subgroups(group, G_mapset(), subgs_num);
}

/*!
* \brief Get list of subgroups which a group contatins.
*
*
* \param group group name
* \param mapset mapset name
* \param[out] subgs_num number of subgroups which the group contains
* \return array of subgroup names
*/

char **I_list_subgroups2(const char *group, const char *mapset, int *subgs_num)
char **I_list_subgroups2(const char *group, const char *mapset,
int *subgs_num)
{
return list_subgroups(group, mapset, subgs_num);
}
Expand All @@ -78,43 +79,42 @@ char **I_list_subgroups2(const char *group, const char *mapset, int *subgs_num)
* \param fd where to print (typically stdout)
* \return 0
*/
int I_list_subgroup(const char *group,
const char *subgroup, const struct Ref *ref, FILE * fd)
int I_list_subgroup(const char *group, const char *subgroup,
const struct Ref *ref, FILE * fd)
{
char buf[80];
int i;
int len, tot_len;
int max;

if (ref->nfiles <= 0) {
fprintf(fd, _("subgroup <%s> of group <%s> is empty\n"),
subgroup, group);
return 0;
fprintf(fd, _("subgroup <%s> of group <%s> is empty\n"),
subgroup, group);
return 0;
}
max = 0;
for (i = 0; i < ref->nfiles; i++) {
sprintf(buf, "<%s@%s>", ref->file[i].name, ref->file[i].mapset);
len = strlen(buf) + 4;
if (len > max)
max = len;
I__list_group_name_fit(buf, ref->file[i].name, ref->file[i].mapset);
len = strlen(buf) + 4;
if (len > max)
max = len;
}
fprintf(fd,
_
("subgroup <%s> of group <%s> references the following raster maps\n"),
subgroup, group);
_("subgroup <%s> of group <%s> references the following raster maps\n"),
subgroup, group);
fprintf(fd, "-------------\n");
tot_len = 0;
for (i = 0; i < ref->nfiles; i++) {
sprintf(buf, "<%s@%s>", ref->file[i].name, ref->file[i].mapset);
tot_len += max;
if (tot_len > 78) {
fprintf(fd, "\n");
tot_len = max;
}
fprintf(fd, "%-*s", max, buf);
I__list_group_name_fit(buf, ref->file[i].name, ref->file[i].mapset);
tot_len += max;
if (tot_len > 78) {
fprintf(fd, "\n");
tot_len = max;
}
fprintf(fd, "%-*s", max, buf);
}
if (tot_len)
fprintf(fd, "\n");
fprintf(fd, "\n");
fprintf(fd, "-------------\n");

return 0;
Expand Down

0 comments on commit 4c7db5b

Please sign in to comment.