diff --git a/src/libsysprof-capture/sysprof-capture-reader.c b/src/libsysprof-capture/sysprof-capture-reader.c index 12b3f878..1166ae58 100644 --- a/src/libsysprof-capture/sysprof-capture-reader.c +++ b/src/libsysprof-capture/sysprof-capture-reader.c @@ -62,6 +62,7 @@ #include #include #include +#include #include #include #include @@ -1273,20 +1274,60 @@ sysprof_capture_reader_read_file (SysprofCaptureReader *self) return file_chunk; } -char ** +static bool +array_append (const char ***files, + size_t *n_files, + size_t *n_files_allocated, + const char *new_element) +{ + if (*n_files == *n_files_allocated) + { + const char **new_files; + + *n_files_allocated = (*n_files_allocated > 0) ? 2 * *n_files_allocated : 4; + new_files = reallocarray (*files, *n_files_allocated, sizeof (**files)); + if (new_files == NULL) + return false; + *files = new_files; + } + + (*files)[*n_files] = new_element; + *n_files = *n_files + 1; + assert (*n_files <= *n_files_allocated); + + return true; +} + +static void +array_deduplicate (const char **files, + size_t *n_files) +{ + size_t last_written, next_to_read; + + if (*n_files == 0) + return; + + for (last_written = 0, next_to_read = 1; last_written <= next_to_read && next_to_read < *n_files;) + { + if (strcmp (files[next_to_read], files[last_written]) == 0) + next_to_read++; + else + files[++last_written] = files[next_to_read++]; + } + + assert (last_written + 1 <= *n_files); + *n_files = last_written + 1; +} + +const char ** sysprof_capture_reader_list_files (SysprofCaptureReader *self) { - g_autoptr(GHashTable) files = NULL; - g_autoptr(GPtrArray) ar = NULL; + const char **files = NULL; + size_t n_files = 0, n_files_allocated = 0; SysprofCaptureFrameType type; - GHashTableIter iter; - const gchar *key; assert (self != NULL); - ar = g_ptr_array_new_with_free_func (g_free); - files = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - while (sysprof_capture_reader_peek_type (self, &type)) { const SysprofCaptureFileChunk *file; @@ -1300,16 +1341,27 @@ sysprof_capture_reader_list_files (SysprofCaptureReader *self) if (!(file = sysprof_capture_reader_read_file (self))) break; - if (!g_hash_table_contains (files, file->path)) - g_hash_table_insert (files, g_strdup (file->path), NULL); + if (!array_append (&files, &n_files, &n_files_allocated, file->path)) + { + free (files); + errno = ENOMEM; + return NULL; + } } - g_hash_table_iter_init (&iter, files); - while (g_hash_table_iter_next (&iter, (gpointer *)&key, NULL)) - g_ptr_array_add (ar, g_strdup (key)); - g_ptr_array_add (ar, NULL); + /* Sort and deduplicate the files array. */ + qsort (files, n_files, sizeof (*files), (int (*)(const void *, const void *)) strcmp); + array_deduplicate (files, &n_files); - return (char **)g_ptr_array_free (sysprof_steal_pointer (&ar), FALSE); + /* Add a null terminator */ + if (!array_append (&files, &n_files, &n_files_allocated, NULL)) + { + free (files); + errno = ENOMEM; + return NULL; + } + + return sysprof_steal_pointer (&files); } bool diff --git a/src/libsysprof-capture/sysprof-capture-reader.h b/src/libsysprof-capture/sysprof-capture-reader.h index c417f9b6..0fffa6a4 100644 --- a/src/libsysprof-capture/sysprof-capture-reader.h +++ b/src/libsysprof-capture/sysprof-capture-reader.h @@ -144,7 +144,7 @@ SYSPROF_AVAILABLE_IN_ALL const SysprofCaptureFileChunk *sysprof_capture_reader_find_file (SysprofCaptureReader *self, const char *path); SYSPROF_AVAILABLE_IN_ALL -char **sysprof_capture_reader_list_files (SysprofCaptureReader *self); +const char **sysprof_capture_reader_list_files (SysprofCaptureReader *self); SYSPROF_AVAILABLE_IN_ALL bool sysprof_capture_reader_read_file_fd (SysprofCaptureReader *self, const char *path, diff --git a/src/tests/test-capture.c b/src/tests/test-capture.c index 895fdfcb..dda2ab19 100644 --- a/src/tests/test-capture.c +++ b/src/tests/test-capture.c @@ -747,7 +747,7 @@ test_reader_writer_file (void) { g_autofree gchar *data = NULL; GByteArray *buf = g_byte_array_new (); - g_auto(GStrv) files = NULL; + g_autofree const gchar **files = NULL; SysprofCaptureWriter *writer; SysprofCaptureReader *reader; SysprofCaptureFrameType type; diff --git a/src/tools/sysprof-dump.c b/src/tools/sysprof-dump.c index 24394909..17bd3a9f 100644 --- a/src/tools/sysprof-dump.c +++ b/src/tools/sysprof-dump.c @@ -64,9 +64,9 @@ main (gint argc, if (list_files) { - g_auto(GStrv) files = sysprof_capture_reader_list_files (reader); + g_autofree const gchar **files = sysprof_capture_reader_list_files (reader); - for (guint i = 0; files[i]; i++) + for (gsize i = 0; files[i]; i++) g_print ("%s\n", files[i]); return EXIT_SUCCESS;