// clang-format off /* * $Id: sort.c 747 2009-11-06 02:33:37Z dhiebert $ * * Copyright (c) 1996-2002, Darren Hiebert * * This source code is released for free distribution under the terms of the * GNU General Public License. * * This module contains functions to sort the tag entries. */ /* * INCLUDE FILES */ #include "libc/mem/mem.h" #include "third_party/ctags/general.h" /* must always come first */ #if defined (HAVE_STDLIB_H) #include "libc/calls/calls.h" #include "libc/calls/dprintf.h" #include "libc/calls/termios.h" #include "libc/fmt/conv.h" #include "libc/limits.h" #include "libc/mem/alg.h" #include "libc/mem/mem.h" #include "libc/runtime/runtime.h" #include "libc/stdio/rand.h" #include "libc/stdio/temp.h" #include "libc/str/str.h" #include "libc/sysv/consts/exit.h" #include "third_party/gdtoa/gdtoa.h" #include "third_party/getopt/getopt.h" #include "third_party/musl/crypt.h" #include "third_party/musl/rand48.h" /* to declare malloc () */ #endif #include "libc/mem/alg.h" #include "libc/str/str.h" #include "libc/calls/calls.h" #include "libc/calls/dprintf.h" #include "libc/calls/weirdtypes.h" #include "libc/fmt/fmt.h" #include "libc/mem/fmt.h" #include "libc/stdio/stdio.h" #include "libc/stdio/temp.h" #include "third_party/musl/tempnam.h" #include "third_party/ctags/debug.h" #include "third_party/ctags/entry.h" #include "third_party/ctags/options.h" #include "third_party/ctags/read.h" #include "third_party/ctags/routines.h" #include "third_party/ctags/sort.h" /* * FUNCTION DEFINITIONS */ extern void catFile (const char *const name) { FILE *const fp = fopen (name, "r"); if (fp != NULL) { int c; while ((c = getc (fp)) != EOF) putchar (c); fflush (stdout); fclose (fp); } } #ifdef EXTERNAL_SORT #ifdef NON_CONST_PUTENV_PROTOTYPE # define PE_CONST #else # define PE_CONST const #endif extern void externalSortTags (const boolean toStdout) { const char *const sortNormalCommand = "sort -u -o"; const char *const sortFoldedCommand = "sort -u -f -o"; const char *sortCommand = Option.sorted == SO_FOLDSORTED ? sortFoldedCommand : sortNormalCommand; PE_CONST char *const sortOrder1 = "LC_COLLATE=C"; PE_CONST char *const sortOrder2 = "LC_ALL=C"; const size_t length = 4 + strlen (sortOrder1) + strlen (sortOrder2) + strlen (sortCommand) + (2 * strlen (tagFileName ())); char *const cmd = (char *) malloc (length + 1); int ret = -1; if (cmd != NULL) { /* Ensure ASCII value sort order. */ #ifdef HAVE_SETENV setenv ("LC_COLLATE", "C", 1); setenv ("LC_ALL", "C", 1); sprintf (cmd, "%s %s %s", sortCommand, tagFileName (), tagFileName ()); #else # ifdef HAVE_PUTENV putenv (sortOrder1); putenv (sortOrder2); sprintf (cmd, "%s %s %s", sortCommand, tagFileName (), tagFileName ()); # else sprintf (cmd, "%s %s %s %s %s", sortOrder1, sortOrder2, sortCommand, tagFileName (), tagFileName ()); # endif #endif verbose ("system (\"%s\")\n", cmd); ret = system (cmd); free (cmd); } if (ret != 0) error (FATAL | PERROR, "cannot sort tag file"); else if (toStdout) catFile (tagFileName ()); } #else /* * These functions provide a basic internal sort. No great memory * optimization is performed (e.g. recursive subdivided sorts), * so have lots of memory if you have large tag files. */ static void failedSort (FILE *const fp, const char* msg) { const char* const cannotSort = "cannot sort tag file"; if (fp != NULL) fclose (fp); if (msg == NULL) error (FATAL | PERROR, "%s", cannotSort); else error (FATAL, "%s: %s", msg, cannotSort); } static int compareTagsFolded(const void *const one, const void *const two) { const char *const line1 = *(const char* const*) one; const char *const line2 = *(const char* const*) two; return struppercmp (line1, line2); } static int compareTags (const void *const one, const void *const two) { const char *const line1 = *(const char* const*) one; const char *const line2 = *(const char* const*) two; return strcmp (line1, line2); } static void writeSortedTags ( char **const table, const size_t numTags, const boolean toStdout) { FILE *fp; size_t i; /* Write the sorted lines back into the tag file. */ if (toStdout) fp = stdout; else { fp = fopen (tagFileName (), "w"); if (fp == NULL) failedSort (fp, NULL); } for (i = 0 ; i < numTags ; ++i) { /* Here we filter out identical tag *lines* (including search * pattern) if this is not an xref file. */ if (i == 0 || Option.xref || strcmp (table [i], table [i-1]) != 0) if (fputs (table [i], fp) == EOF) failedSort (fp, NULL); } if (toStdout) fflush (fp); else fclose (fp); } extern void internalSortTags (const boolean toStdout) { vString *vLine = vStringNew (); FILE *fp = NULL; const char *line; size_t i; int (*cmpFunc)(const void *, const void *); /* Allocate a table of line pointers to be sorted. */ size_t numTags = TagFile.numTags.added + TagFile.numTags.prev; const size_t tableSize = numTags * sizeof (char *); char **const table = (char **) malloc (tableSize); /* line pointers */ DebugStatement ( size_t mallocSize = tableSize; ) /* cumulative total */ cmpFunc = Option.sorted == SO_FOLDSORTED ? compareTagsFolded : compareTags; if (table == NULL) failedSort (fp, "out of memory"); /* Open the tag file and place its lines into allocated buffers. */ fp = fopen (tagFileName (), "r"); if (fp == NULL) failedSort (fp, NULL); for (i = 0 ; i < numTags && ! feof (fp) ; ) { line = readLine (vLine, fp); if (line == NULL) { if (! feof (fp)) failedSort (fp, NULL); break; } else if (*line == '\0' || strcmp (line, "\n") == 0) ; /* ignore blank lines */ else { const size_t stringSize = strlen (line) + 1; table [i] = (char *) malloc (stringSize); if (table [i] == NULL) failedSort (fp, "out of memory"); DebugStatement ( mallocSize += stringSize; ) strcpy (table [i], line); ++i; } } numTags = i; fclose (fp); vStringDelete (vLine); /* Sort the lines. */ qsort (table, numTags, sizeof (*table), cmpFunc); writeSortedTags (table, numTags, toStdout); PrintStatus (("sort memory: %ld bytes\n", (long) mallocSize)); for (i = 0 ; i < numTags ; ++i) free (table [i]); free (table); } #endif /* vi:set tabstop=4 shiftwidth=4: */