/tagmanager/sort.c

https://github.com/perepechaev/geany · C · 220 lines · 156 code · 30 blank · 34 comment · 43 complexity · 068ebbd000950bb43045d6544803962a MD5 · raw file

  1. /*
  2. *
  3. * Copyright (c) 1996-2001, Darren Hiebert
  4. *
  5. * This source code is released for free distribution under the terms of the
  6. * GNU General Public License.
  7. *
  8. * This module contains functions to sort the tag entries.
  9. */
  10. /*
  11. * INCLUDE FILES
  12. */
  13. #include "general.h" /* must always come first */
  14. #if defined (HAVE_STDLIB_H)
  15. # include <stdlib.h> /* to declare malloc () */
  16. #endif
  17. #include <string.h>
  18. #include <stdio.h>
  19. #include <glib.h>
  20. #include <glib/gstdio.h>
  21. #include "entry.h"
  22. #include "main.h"
  23. #include "options.h"
  24. #include "read.h"
  25. #include "sort.h"
  26. #ifdef TRAP_MEMORY_CALLS
  27. # include "safe_malloc.h"
  28. #endif
  29. /*
  30. * FUNCTION DEFINITIONS
  31. */
  32. extern void catFile (const char *const name)
  33. {
  34. FILE *const fp = g_fopen (name, "r");
  35. if (fp != NULL)
  36. {
  37. int c;
  38. while ((c = getc (fp)) != EOF)
  39. putchar (c);
  40. fflush (stdout);
  41. fclose (fp);
  42. }
  43. }
  44. #ifdef EXTERNAL_SORT
  45. #ifdef NON_CONST_PUTENV_PROTOTYPE
  46. # define PE_CONST
  47. #else
  48. # define PE_CONST const
  49. #endif
  50. extern void externalSortTags (const boolean toStdout)
  51. {
  52. const char *const sortCommand = "sort -u -o";
  53. PE_CONST char *const sortOrder1 = "LC_COLLATE=C";
  54. PE_CONST char *const sortOrder2 = "LC_ALL=C";
  55. const size_t length = 4 + strlen (sortOrder1) + strlen (sortOrder2) +
  56. strlen (sortCommand) + (2 * strlen (tagFileName ()));
  57. char *const cmd = (char *) g_malloc (length + 1);
  58. int ret = -1;
  59. if (cmd != NULL)
  60. {
  61. /* Ensure ASCII value sort order.
  62. */
  63. #ifdef HAVE_SETENV
  64. setenv ("LC_COLLATE", "C", 1);
  65. setenv ("LC_ALL", "C", 1);
  66. sprintf (cmd, "%s %s %s", sortCommand, tagFileName (), tagFileName ());
  67. #else
  68. # ifdef HAVE_PUTENV
  69. putenv (sortOrder1);
  70. putenv (sortOrder2);
  71. sprintf (cmd, "%s %s %s", sortCommand, tagFileName (), tagFileName ());
  72. # else
  73. sprintf (cmd, "%s %s %s %s %s", sortOrder1, sortOrder2, sortCommand,
  74. tagFileName (), tagFileName ());
  75. # endif
  76. #endif
  77. verbose ("system (\"%s\")\n", cmd);
  78. ret = system (cmd);
  79. g_free (cmd);
  80. }
  81. if (ret != 0)
  82. error (FATAL | PERROR, "cannot sort tag file");
  83. else if (toStdout)
  84. catFile (tagFileName ());
  85. }
  86. #else
  87. /*
  88. * These functions provide a basic internal sort. No great memory
  89. * optimization is performed (e.g. recursive subdivided sorts),
  90. * so have lots of memory if you have large tag files.
  91. */
  92. static void failedSort (MIO *const mio, const char* msg)
  93. {
  94. const char* const cannotSort = "cannot sort tag file";
  95. if (mio != NULL)
  96. mio_free (mio);
  97. if (msg == NULL)
  98. error (FATAL | PERROR, "%s", cannotSort);
  99. else
  100. error (FATAL, "%s: %s", msg, cannotSort);
  101. }
  102. static int compareTags (const void *const one, const void *const two)
  103. {
  104. const char *const line1 = *(const char* const*) one;
  105. const char *const line2 = *(const char* const*) two;
  106. return strcmp (line1, line2);
  107. }
  108. static void writeSortedTags (char **const table, const size_t numTags,
  109. const boolean toStdout)
  110. {
  111. MIO *mio;
  112. size_t i;
  113. /* Write the sorted lines back into the tag file.
  114. */
  115. if (toStdout)
  116. mio = mio_new_fp (stdout, NULL);
  117. else
  118. {
  119. mio = mio_new_file_full (tagFileName (), "w", g_fopen, fclose);
  120. if (mio == NULL)
  121. failedSort (mio, NULL);
  122. }
  123. for (i = 0 ; i < numTags ; ++i)
  124. {
  125. /* Here we filter out identical tag *lines* (including search
  126. * pattern) if this is not an xref file.
  127. */
  128. if (i == 0 || Option.xref || strcmp (table [i], table [i-1]) != 0)
  129. if (mio_puts (mio, table [i]) == EOF)
  130. failedSort (mio, NULL);
  131. }
  132. if (toStdout)
  133. fflush (mio_file_get_fp (mio));
  134. mio_free (mio);
  135. }
  136. extern void internalSortTags (const boolean toStdout)
  137. {
  138. vString *vLine = vStringNew ();
  139. MIO *mio = NULL;
  140. const char *line;
  141. size_t i;
  142. /* Allocate a table of line pointers to be sorted.
  143. */
  144. size_t numTags = TagFile.numTags.added + TagFile.numTags.prev;
  145. const size_t tableSize = numTags * sizeof (char *);
  146. char **const table = (char **) g_malloc (tableSize); /* line pointers */
  147. DebugStatement ( size_t mallocSize = tableSize; ) /* cumulative total */
  148. if (table == NULL)
  149. failedSort (mio, "out of memory");
  150. /* Open the tag file and place its lines into allocated buffers.
  151. */
  152. mio = mio_new_file_full (tagFileName (), "r", g_fopen, fclose);
  153. if (mio == NULL)
  154. failedSort (mio, NULL);
  155. for (i = 0 ; i < numTags && ! mio_eof (mio) ; )
  156. {
  157. line = readLine (vLine, mio);
  158. if (line == NULL)
  159. {
  160. if (! mio_eof (mio))
  161. failedSort (mio, NULL);
  162. break;
  163. }
  164. else if (*line == '\0' || strcmp (line, "\n") == 0)
  165. ; /* ignore blank lines */
  166. else
  167. {
  168. const size_t stringSize = strlen (line) + 1;
  169. table [i] = (char *) g_malloc (stringSize);
  170. if (table [i] == NULL)
  171. failedSort (mio, "out of memory");
  172. DebugStatement ( mallocSize += stringSize; )
  173. strcpy (table [i], line);
  174. ++i;
  175. }
  176. }
  177. numTags = i;
  178. mio_free (mio);
  179. vStringDelete (vLine);
  180. /* Sort the lines.
  181. */
  182. qsort (table, numTags, sizeof (*table), compareTags);
  183. writeSortedTags (table, numTags, toStdout);
  184. PrintStatus (("sort memory: %ld bytes\n", (long) mallocSize));
  185. for (i = 0 ; i < numTags ; ++i)
  186. free (table [i]);
  187. free (table);
  188. }
  189. #endif
  190. /* vi:set tabstop=8 shiftwidth=4: */