From 118880912438aa219d100a85ec54ac461741b3ba Mon Sep 17 00:00:00 2001 From: Johannes Schauer Date: Wed, 29 Apr 2015 18:43:22 +0200 Subject: ldraw-parts (1402+ds-1) unstable; urgency=medium * New upstream release * Replace my email address in Maintainer field by josch@debian.org * bump standards version to 3.9.6 # imported from the archive --- mklist.c | 597 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 597 insertions(+) create mode 100644 mklist.c (limited to 'mklist.c') diff --git a/mklist.c b/mklist.c new file mode 100644 index 000000000..09531c64c --- /dev/null +++ b/mklist.c @@ -0,0 +1,597 @@ +/* + * mklist.c, a replacement for James Jessiman's makelist + * Copyright (C) 1999 Lars C. Hassing + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/***************************************************************************** + Please do not edit this file. In stead contact Lars C. Hassing (lch@cci.dk) + to get your changes integrated in a future release. +******************************************************************************/ + +/* +990214 lch Release v1.0 +990316 lch Release v1.1: added options + minor changes to sort algorithms +990518 lch Release v1.2: Skip "~Moved to xxx" by default +20000703 lch Release v1.3: Added -i and -o +20030625 dmh Release v1.4: Ported to gcc. +200????? ??? Release v1.5: ??? Lost track of this one... +20090928 dmh Release v1.6beta1: Added -f -q -v -8 and allow 25 chars in filenames. +20100706 dmh Release v1.6: Added -l and made long format the default. + */ + +/* Compile with Borland Turbo C 2.0: tcc -mc -d -f -k- -N -v- -y- -wrvl -wstv +-wucp -wnod -wpro -wuse -wsig -ncmdsrel -M src\mklist.c */ + + +#include "stdio.h" +#include "stdlib.h" +#include "ctype.h" +#include "string.h" +#include "alloc.h" +#include "dir.h" +#include "conio.h" +#include + +char *ProgVer = "mklist v1.6 20100706 (C) 1999-2010 Lars C. Hassing lch@ccieurope.com"; + +int forceit = 0; +int quiet = 0; + + /*****************************************************************/ +/* Filename length compatibility stuff */ +/*****************************************************************/ +#ifndef MAX_PATH +#define MAX_PATH 256 +#endif +char shortfilepath[MAX_PATH]; +char shortfilename[MAX_PATH]; + + +#ifdef __BORLANDC__ +#define LACKS_BASENAME 1 +int numlines = 1000; /* Use small chunks for DOS */ +int namelen = 12; /* Set to 12 for 8.3 DOS compatibility. */ +#else +#ifdef __TURBOC__ +#define LACKS_BASENAME 1 +int numlines = 1000; /* Use small chunks for DOS */ +int namelen = 12; /* Set to 12 for 8.3 DOS compatibility. */ +#else +int numlines = 16384; /* Allocate lines in bigger chunks if not DOS. */ +int namelen = 25; /* LSC specs allow 25 chars in filename. */ +#endif +#endif + + +#ifdef _WIN32 +#include +#define LACKS_BASENAME 1 + +#else +int GetShortPathName(char *longpath, char * shortpath, int psize) +{ + strncpy(shortpath, longpath, psize); + return(strlen(shortpath)); +} +#endif + + +#if LACKS_BASENAME +char *basename( const char *filepath ) +{ + char *tmpstr, *ptr; + + if (filepath == NULL) + { + return NULL; + } + if ( (ptr = strrchr(filepath, '\\')) || (ptr = strrchr(filepath, '/')) ) + { + /* If there isn't anything after the last separator, the result is a 0-length string */ + tmpstr = strdup(ptr+1); + } + else + { + /* dup the string, so caller can safely free whatever we return */ + tmpstr = strdup(filepath); + } + return tmpstr; +} +#endif + + /*****************************************************************/ +int CmpNumber(const void *p1, const void *p2) +{ + char *s1 = *((char **) p1); + char *s2 = *((char **) p2); + long l1; + long l2; + + if (isdigit(*s1) && isdigit(*s2)) + { + l1 = atol(s1); + l2 = atol(s2); + if (l1 != l2) + return (l1 < l2 ? -1 : 1); + /* Numbers are equal. Be sure to make 3005.dat come before 3005-1.dat */ + do + { + l1 = (unsigned char) *s1++; + if ('A' <= l1 && l1 <= 'Z') + l1 -= ('A' - 'a'); + else if (l1 == '.') + l1 = '\0'; /* Sort dot very first */ + l2 = (unsigned char) *s2++; + if ('A' <= l2 && l2 <= 'Z') + l2 -= ('A' - 'a'); + else if (l2 == '.') + l2 = '\0'; /* Sort dot very first */ + } while (l1 && (l1 == l2)); + + return ((int) (l1 - l2)); + } + return (stricmp(s1, s2)); +} + +/*****************************************************************/ +int CmpDescription(const void *p1, const void *p2) +{ + char *s1 = *((char **) p1); + char *s2 = *((char **) p2); + int Res; + +#if 0 + Res = stricmp(s1 + (namelen+2), s2 + (namelen+2)); +#else + s1 += strcspn(s1, " \t"); /* Find the beginning of whitespace. */ + s1 += strspn(s1, " \t"); /* Skip to end of whitespace (start of description). */ + s2 += strcspn(s2, " \t"); /* Find the beginning of whitespace. */ + s2 += strspn(s2, " \t"); /* Skip to end of whitespace (start of description). */ + Res = stricmp(s1, s2); +#endif + + return (Res ? Res : CmpNumber(p1, p2)); +} + +/*****************************************************************/ +void PressAnyKey(void) +{ + if (forceit) + return; + if (quiet) + return; + printf(" Press any key to continue"); + getch(); + printf("\n"); +} + +/*****************************************************************/ +void PrintUsage(void) +{ + printf("Options:\n"); + printf(" -h You already figured this one out :-)\n"); + printf(" -n Sort by Number\n"); + printf(" -d Sort by Description\n"); + printf(" -c Check for duplicate descriptions. \"parts.lst\" unchanged.\n"); + printf(" -m Don't skip parts with \"~Moved to xxx\" description\n"); + printf(" -~ Skip parts with ~ description, e.g. \"~Winch 2 x 4 x 2 Top\"\n"); + printf(" -i input directory, default is \"PARTS\" in current directory\n"); + printf(" -o output filename, default is \"parts.lst\" in current directory\n"); + printf(" -f Force it to finish. No prompts.\n"); + printf(" -q Quiet mode. No warnings, and no prompts.\n"); + printf(" -8 Use 8.3 names for compatibility.\n"); + printf(" -t Truncating descriptions to fit in an 80 char terminal window.\n"); + printf(" -r Ragged filename column. Size it to fit short filenames.\n"); + printf(" -l Truncate Long descriptions at 64 chars.\n"); + printf(" -v Print verbose info. Useful for debugging.\n"); +} + + /*****************************************************************/ +int main(int argc, char **argv) +{ + int CheckDuplicateDescriptions; + int SortBy; + int SkipTilde; + int SkipMovedto; + char *arg; + int c; + int i; + int j; + FILE *fp; + struct ffblk ffb; + int done; + int Len; + char **Lines; + int maxLines; + int nLines; + int pathlen; + char Line[200]; + char Dirname[MAX_PATH]; + char Filename[MAX_PATH]; + char OutFilename[MAX_PATH]; + char *s; + char *Description; + char *FormattedLine; + unsigned long farcoreleftStart; + unsigned long farcoreleftEnd; + long FileSize; + struct stat statbuf; + int verbose; + int ragged; + int terminalsized; + int longDescriptions; + + printf("%s\n", ProgVer); + printf("Replacement for James Jessiman's makelist\n"); + printf("Call with -h to see a list of options.\n\n"); + + strcpy(Dirname, "PARTS"); /* Default input directory path */ + strcpy(OutFilename, "parts.lst"); /* Default output filename */ + + verbose = 0; + ragged = 0; /* Steve wanted it ragged (1) by default */ + terminalsized = 0; /* Steve wanted it (1) to fit in 80 chars by default */ + longDescriptions = 1; /* Do not truncate descriptions at 64 chars by default */ + + CheckDuplicateDescriptions = 0; + SortBy = 0; + SkipTilde = 0; + SkipMovedto = 1; + while (--argc > 0) + { + arg = *++argv; + if (arg[0] == '-') + { + switch (arg[1]) + { + case '?': + case 'h': + PrintUsage(); + exit(1); + break; + case '8': + namelen = 12; + break; + case 'c': + CheckDuplicateDescriptions = 1; + break; + case 'n': + case 'd': + SortBy = arg[1]; + break; + case 'm': + SkipMovedto = 0; + break; + case '~': + SkipTilde = 1; + break; + case 'i': + if (--argc > 0) + strcpy(Dirname, *++argv); + else + { + PrintUsage(); + printf("*** input directory expected as next argument after -i.\n"); + exit(1); + } + break; + case 'o': + if (--argc > 0) + strcpy(OutFilename, *++argv); + else + { + PrintUsage(); + printf("*** output filename expected as next argument after -o.\n"); + exit(1); + } + break; + case 'q': + quiet = 1; + case 'f': + forceit = 1; + break; + case 'r': + ragged = ragged ^ 1; + break; + case 't': + terminalsized = terminalsized ^ 1; + break; + case 'l': + longDescriptions = longDescriptions ^ 1; + break; + case 'v': + verbose = 1; + break; + default: + PrintUsage(); + printf("*** Unknown option '%s'.\n", arg); + exit(1); + break; + } + } + else + { + PrintUsage(); + exit(1); + } + } + + /* Do a stat to see if Dirname exists and is a directory. */ + if (stat(Dirname, &statbuf) < 0) + { + printf("*** Could not stat input directory \"%s\".\n", Dirname); + exit(1); + } + + if ((statbuf.st_mode & S_IFDIR) == 0) + { + printf("*** Input directory \"%s\" is not a directory.\n", Dirname); + exit(1); + } + + if (CheckDuplicateDescriptions) + SortBy = 'd'; + if (!SortBy) + { + if (forceit) + SortBy = 'd'; + if (!quiet) + printf("Sorting by [D]escription.\n"); + } + + if (!SortBy) + { + printf("Sort by [N]umber or [D]escription: "); + c = getch(); + printf("%c\n", c); + + if (c == 'N' || c == 'n') + SortBy = 'n'; + else if (c == 'D' || c == 'd') + SortBy = 'd'; + else + { + printf("Nothing done.\n"); + exit(0); + } + } + + farcoreleftStart = farcoreleft(); + + nLines = 0; + maxLines = numlines; + Lines = farmalloc(maxLines * sizeof(char *)); + if (!Lines) + { + printf("Out of memory after %d parts\n", nLines); + printf("Memory available at beginning: %ld kBytes\n", + (farcoreleftStart + 1023) / 1024); + exit(1); + } + strcpy(Filename, Dirname); + strcat(Filename, "\\"); + pathlen = strlen(Filename); + strcat(Filename, "*.*"); + for (done = findfirst(Filename, &ffb, 0); !done; done = findnext(&ffb)) + { + if (verbose) + { + printf("Processing file: \"%s\"\n", ffb.ff_name); + } + strcpy(Filename + pathlen, ffb.ff_name); + fp = fopen(Filename, "rt"); + if (!fp) + { + if (!quiet) printf("Cannot open \"%s\"", ffb.ff_name); + PressAnyKey(); + continue; + } + fgets(Line, sizeof(Line), fp); + fclose(fp); + + s = Line + strlen(Line) - 1; + while (s >= Line && (*s == '\n' || *s == '\r' || *s == '\t' || *s == ' ')) + *s-- = '\0'; /* clear newline and trailing tabs + and spaces */ + s = Line; + while (*s == '\t' || *s == ' ') + *s++; + if (*s++ != '0') + { + if (!quiet) printf("Line type 0 expected in \"%s\", skipping...", ffb.ff_name); + PressAnyKey(); + continue; + } + while (*s == '\t' || *s == ' ') + *s++; + Description = s; + if (SkipTilde && Description[0] == '~') + continue; + if (SkipMovedto && strncmp(Description, "~Moved to", 9) == 0) + continue; + Len = strlen(Description); + if (Len == 0) + { + if (!quiet) printf("Empty description in \"%s\"", ffb.ff_name); + PressAnyKey(); + } + if ((Len > 64) && !longDescriptions) + { + /* Original makelist truncates to 64 characters. */ + if (!quiet) + { + printf("Description in \"%s\" will be truncated to 64 characters:\n", + ffb.ff_name); + printf("Before: \"%s\"\n", Description); + printf("After: \"%-64.64s\"\n", Description); + } + PressAnyKey(); + } + if (namelen == 12) + FormattedLine = farmalloc(79); + else + FormattedLine = farmalloc(256); + if (!FormattedLine) + { + printf("Out of memory after %d parts\n", nLines); + printf("Memory available at beginning: %ld kBytes\n", + (farcoreleftStart + 1023) / 1024); + exit(1); + } + + + if (namelen > 12) + strcpy(shortfilename, ffb.ff_name); + else + { + GetShortPathName(Filename, shortfilepath, MAX_PATH); + s = basename(shortfilepath); + strcpy(shortfilename, s); + if (s != NULL) + free(s); + if (strcmp(ffb.ff_name, shortfilename)) + { + if (!quiet) + printf("Filename \"%s\" will be shortened to %s\n", + ffb.ff_name, shortfilename); + PressAnyKey(); + } + } + + Len = strlen(shortfilename); + if (Len > namelen) + { + if (!quiet) + printf("Filename \"%s\" will be truncated to %d characters.\n", + shortfilename, namelen); + PressAnyKey(); + } + shortfilename[namelen] = 0; + if (namelen == 12) + sprintf(FormattedLine, "%-12s %-64.64s", shortfilename, Description); + else if (ragged && terminalsized) + { + if (Len > 14) /* Squeeze every last char out of the 80. */ + sprintf(FormattedLine, "%s %-64.64s", shortfilename, Description); + else + sprintf(FormattedLine, "%-14s %-64.64s", shortfilename, Description); + } + else if (ragged && longDescriptions) + { + if (Len > 12) + sprintf(FormattedLine, "%s %s", shortfilename, Description); + else + sprintf(FormattedLine, "%-12s %s", shortfilename, Description); + } + else if (ragged) + { + if (Len > 12) + sprintf(FormattedLine, "%s %-64.64s", shortfilename, Description); + else + sprintf(FormattedLine, "%-12s %-64.64s", shortfilename, Description); + } + else if (longDescriptions) + sprintf(FormattedLine, "%-25s %s", shortfilename, Description); + else + sprintf(FormattedLine, "%-25s %s", shortfilename, Description); + + if (terminalsized) + { + if (namelen == 12) + FormattedLine[78] = 0; + else + FormattedLine[80] = 0; + } + + if (verbose) + { + printf("%d:\t%s\n", nLines, FormattedLine); + } + if (nLines >= maxLines) + { + /* Let's have another 1000 pointers */ + maxLines += numlines; + Lines = farrealloc(Lines, maxLines * sizeof(char *)); + if (!Lines) + { + printf("Out of memory after %d parts\n", nLines); + printf("Memory available at beginning: %ld kBytes\n", + (farcoreleftStart + 1023) / 1024); + exit(1); + } + } + Lines[nLines++] = FormattedLine; + if (nLines % 100 == 0) + printf("%d parts so far...\r", nLines); + } + printf("%d parts found in %s.\n", nLines, Dirname); + if (nLines == 0) + { + printf("No parts found, nothing done.\n"); + exit(0); + } + + printf("Sorting...\n"); + qsort(Lines, nLines, sizeof(Lines[0]), + (SortBy == 'n') ? CmpNumber : CmpDescription); + + if (CheckDuplicateDescriptions) + { + printf("Checking for duplicate descriptions. \"%s\" unchanged.\n", OutFilename); + for (i = 0; i < nLines; i += j) + { + for (j = 1; i + j < nLines; j++) + { + if (stricmp(Lines[i] + (namelen+2), Lines[i + j] + (namelen+2)) != 0) + break; /* OK to break, lines are sorted */ + if (j == 1) /* First duplicate */ + printf("%s\n", Lines[i]); + printf("%s\n", Lines[i + j]); + } + if (j > 1) /* Duplicates found */ + PressAnyKey(); + } + } + else + { + fp = fopen(OutFilename, "wt"); + if (!fp) + { + printf("Cannot open \"%s\" for writing.\n", OutFilename); + exit(1); + } + for (i = 0; i < nLines; i++) + fprintf(fp, "%s\n", Lines[i]); + FileSize = ftell(fp); + fclose(fp); + printf("\"%s\" successfully written, %ld kBytes\n", OutFilename, + (FileSize + 1023) / 1024); + } + + if (numlines > 1000) /* if not Borland DOS compiler then skip the mem msg. */ + { + return (0); + } + + farcoreleftEnd = farcoreleft(); + + printf("Maximum memory usage: %ld kBytes of %ld kBytes available\n", + (farcoreleftStart - farcoreleftEnd + 1023) / 1024, + (farcoreleftStart + 1023) / 1024); + + return (0); +} -- cgit v1.2.3