mirror of
https://github.com/jart/cosmopolitan.git
synced 2024-05-02 11:48:44 +00:00
256 lines
6.2 KiB
C
256 lines
6.2 KiB
C
// 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: */
|