Coverage Report

Created: 2026-03-07 06:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/igraph/src/io/edgelist.c
Line
Count
Source
1
/*
2
   igraph library.
3
   Copyright (C) 2005-2020  The igraph development team
4
5
   This program is free software; you can redistribute it and/or modify
6
   it under the terms of the GNU General Public License as published by
7
   the Free Software Foundation; either version 2 of the License, or
8
   (at your option) any later version.
9
10
   This program is distributed in the hope that it will be useful,
11
   but WITHOUT ANY WARRANTY; without even the implied warranty of
12
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
   GNU General Public License for more details.
14
15
   You should have received a copy of the GNU General Public License
16
   along with this program; if not, write to the Free Software
17
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18
   02110-1301 USA
19
20
*/
21
22
#include "igraph_foreign.h"
23
24
#include "igraph_constructors.h"
25
#include "igraph_interface.h"
26
#include "igraph_iterators.h"
27
28
#include "core/interruption.h"
29
#include "io/parse_utils.h"
30
31
/**
32
 * \section about_loadsave
33
 *
34
 * <para>These functions can write a graph to a file, or read a graph
35
 * from a file.</para>
36
 *
37
 * <para>They assume that the current locale uses a decimal point and not
38
 * a decimal comma. See \ref igraph_enter_safelocale() and
39
 * \ref igraph_exit_safelocale() for more information.</para>
40
 *
41
 * <para>Note that as \a igraph uses the traditional C streams, it is
42
 * possible to read/write files from/to memory, at least on GNU
43
 * operating systems supporting \quote non-standard\endquote streams.</para>
44
 */
45
46
/**
47
 * \ingroup loadsave
48
 * \function igraph_read_graph_edgelist
49
 * \brief Reads an edge list from a file and creates a graph.
50
 *
51
 * This format is simply a series of an even number of non-negative integers separated by
52
 * whitespace. The integers represent vertex IDs. Placing each edge (i.e. pair of integers)
53
 * on a separate line is not required, but it is recommended for readability.
54
 * Edges of directed graphs are assumed to be in "from, to" order.
55
 *
56
 * </para><para>
57
 * The largest vertex ID plus one, or the parameter \p n determines the vertex count,
58
 * whichever is larger. See \ref igraph_read_graph_ncol() for reading files where
59
 * vertices are specified by name instead of by a numerical vertex ID.
60
 *
61
 * \param graph Pointer to an uninitialized graph object.
62
 * \param instream Pointer to a stream, it should be readable.
63
 * \param n The number of vertices in the graph. If smaller than the
64
 *        largest integer in the file it will be ignored. It is thus
65
 *        safe to supply zero here.
66
 * \param directed If true the graph is directed, if false it
67
 *        will be undirected.
68
 * \return Error code:
69
 *         \c IGRAPH_PARSEERROR: if there is a
70
 *         problem reading the file, or the file is syntactically
71
 *         incorrect.
72
 *
73
 * Time complexity: O(|V|+|E|), the
74
 * number of vertices plus the number of edges. It is assumed that
75
 * reading an integer requires O(1) time.
76
 */
77
igraph_error_t igraph_read_graph_edgelist(igraph_t *graph, FILE *instream,
78
545
                               igraph_int_t n, igraph_bool_t directed) {
79
80
545
    igraph_vector_int_t edges = IGRAPH_VECTOR_NULL;
81
545
    igraph_int_t from, to;
82
83
545
    IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0);
84
545
    IGRAPH_CHECK(igraph_vector_int_reserve(&edges, 100));
85
86
856k
    for (;;) {
87
856k
        IGRAPH_ALLOW_INTERRUPTION();
88
89
856k
        IGRAPH_CHECK(igraph_i_fskip_whitespace(instream));
90
91
856k
        if (feof(instream)) break;
92
93
855k
        IGRAPH_CHECK(igraph_i_fget_integer(instream, &from));
94
855k
        IGRAPH_CHECK(igraph_i_fget_integer(instream, &to));
95
96
855k
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
97
        /* Protect from very large memory allocations when fuzzing. */
98
2.56M
#define IGRAPH_EDGELIST_MAX_VERTEX_COUNT (1L << 20)
99
855k
        if (from > IGRAPH_EDGELIST_MAX_VERTEX_COUNT || to > IGRAPH_EDGELIST_MAX_VERTEX_COUNT) {
100
24
            IGRAPH_ERROR("Vertex count too large in edgelist file.", IGRAPH_EINVAL);
101
24
        }
102
855k
#endif
103
104
855k
        IGRAPH_CHECK(igraph_vector_int_push_back(&edges, from));
105
855k
        IGRAPH_CHECK(igraph_vector_int_push_back(&edges, to));
106
855k
    }
107
108
471
    IGRAPH_CHECK(igraph_create(graph, &edges, n, directed));
109
267
    igraph_vector_int_destroy(&edges);
110
267
    IGRAPH_FINALLY_CLEAN(1);
111
112
267
    return IGRAPH_SUCCESS;
113
471
}
114
115
/**
116
 * \ingroup loadsave
117
 * \function igraph_write_graph_edgelist
118
 * \brief Writes the edge list of a graph to a file.
119
 *
120
 * </para><para>
121
 * Edges are represented as pairs of 0-based vertex indices.
122
 * One edge is written per line, separated by a single space.
123
 * For directed graphs edges are written in from, to order.
124
 *
125
 * \param graph The graph object to write.
126
 * \param outstream Pointer to a stream, it should be writable.
127
 * \return Error code:
128
 *         \c IGRAPH_EFILE if there is an error writing the
129
 *         file.
130
 *
131
 * Time complexity: O(|E|), the
132
 * number of edges in the  graph. It is assumed that writing an
133
 * integer to the file requires O(1)
134
 * time.
135
 */
136
267
igraph_error_t igraph_write_graph_edgelist(const igraph_t *graph, FILE *outstream) {
137
138
267
    igraph_eit_t it;
139
140
267
    IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(IGRAPH_EDGEORDER_FROM),
141
267
                                   &it));
142
267
    IGRAPH_FINALLY(igraph_eit_destroy, &it);
143
144
855k
    while (!IGRAPH_EIT_END(it)) {
145
855k
        igraph_int_t from, to;
146
855k
        int ret;
147
855k
        igraph_edge(graph, IGRAPH_EIT_GET(it), &from, &to);
148
855k
        ret = fprintf(outstream, "%" IGRAPH_PRId " %" IGRAPH_PRId "\n",
149
855k
                      from,
150
855k
                      to);
151
855k
        if (ret < 0) {
152
0
            IGRAPH_ERROR("Failed writing edgelist.", IGRAPH_EFILE);
153
0
        }
154
855k
        IGRAPH_EIT_NEXT(it);
155
855k
    }
156
157
267
    igraph_eit_destroy(&it);
158
267
    IGRAPH_FINALLY_CLEAN(1);
159
267
    return IGRAPH_SUCCESS;
160
267
}