changeset 2410:bc05bcfc4598

Add a C file with the generic BSD license text and a function for printing it out, for use in the tools.
author Matti Hamalainen <ccr@tnsp.org>
date Mon, 13 Jan 2020 22:26:24 +0200
parents 1f26fd82735a
children 829e3080e0ad
files Makefile.gen src/dmlib.h src/dmlicense.c tools/64vw.c tools/data2inc.c tools/dumpmod.c tools/fanalyze.c tools/fontconv.c tools/gfxconv.c tools/mod2wav.c tools/objlink.c tools/packed.c tools/ppl.c tools/xm2jss.c
diffstat 14 files changed, 272 insertions(+), 148 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile.gen	Mon Jan 13 22:25:21 2020 +0200
+++ b/Makefile.gen	Mon Jan 13 22:26:24 2020 +0200
@@ -318,7 +318,8 @@
 DMLIB_OBJS += \
 	dmfile.o dmlib.o dmcurves.o dmstring.o \
 	dmgrowbuf.o dmargs.o dmvecmat.o dmperlin.o \
-	dmimage.o dmengine.o dmfft.o dmzlib.o
+	dmimage.o dmengine.o dmfft.o dmzlib.o \
+	dmlicense.o
 
 
 TESTS_TARGETS = $(addprefix $(TESTS_BINPATH),$(addsuffix $(BINEXT),$(TESTS_BINARIES)))
--- a/src/dmlib.h	Mon Jan 13 22:25:21 2020 +0200
+++ b/src/dmlib.h	Mon Jan 13 22:26:24 2020 +0200
@@ -124,8 +124,9 @@
 #endif
 
 // Defaults
-#define DM_PROG_AUTHOR      "By Matti 'ccr' Hamalainen (C) Copyright 2020 TNSP"
-#define DM_PROG_LICENSE     "Et all, see README / COPYING for more information."
+#define DM_PROG_AUTHOR      "By Matti 'ccr' Hamalainen (C) Copyright 2002-2020 TNSP"
+#define DM_PROG_LICENSE     "This program is distributed under a 3-clause BSD -style license."
+
 
 /* Error codes
  */
@@ -405,6 +406,7 @@
 extern int dmVerbosity;
 void       dmInitProg(char *name, char *desc, char *version, char *author, char *license);
 void       dmPrintBanner(FILE *outFile, const char *name, const char *usage);
+void       dmPrintLicense(FILE *outFile);
 
 void       dmMsgVA(int level, const char *fmt, va_list ap);
 void       dmMsg(int level, const char *fmt, ...)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmlicense.c	Mon Jan 13 22:26:24 2020 +0200
@@ -0,0 +1,44 @@
+/*
+ * DMLib
+ * -- Functionality for tool programs
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2012-2020 Tecnic Software productions (TNSP)
+ */
+#include "dmlib.h"
+
+
+void dmPrintLicense(FILE *outFile)
+{
+    fprintf(outFile, "%s - %s\n%s\n", dmProgName, dmProgDesc, dmProgAuthor);
+    fputs(
+    "\n"
+    "Redistribution and use in source and binary forms, with or without\n"
+    "modification, are permitted provided that the following conditions\n"
+    "are met:\n"
+    "\n"
+    " 1. Redistributions of source code must retain the above copyright\n"
+    "    notice, this list of conditions and the following disclaimer.\n"
+    "\n"
+    " 2. Redistributions in binary form must reproduce the above copyright\n"
+    "    notice, this list of conditions and the following disclaimer in\n"
+    "    the documentation and/or other materials provided with the\n"
+    "    distribution.\n"
+    "\n"
+    " 3. The name of the author may not be used to endorse or promote\n"
+    "    products derived from this software without specific prior written\n"
+    "    permission.\n"
+    "\n"
+    "THIS SOFTWARE IS PROVIDED BY THE AUTHOR \"AS IS\" AND ANY EXPRESS OR\n"
+    "IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n"
+    "WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
+    "ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,\n"
+    "INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n"
+    "(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n"
+    "SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n"
+    "HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n"
+    "STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n"
+    "IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n"
+    "POSSIBILITY OF SUCH DAMAGE.\n",
+    outFile
+    );
+}
--- a/tools/64vw.c	Mon Jan 13 22:25:21 2020 +0200
+++ b/tools/64vw.c	Mon Jan 13 22:26:24 2020 +0200
@@ -35,6 +35,7 @@
 static const DMOptArg optList[] =
 {
     {  0, '?', "help"            , "Show this help", OPT_NONE },
+    {  1,   0, "license"         , "Print out this program's license agreement", OPT_NONE },
     {  2, 'v', "verbose"         , "Be more verbose", OPT_NONE },
 
     { 10,   0, "fs"              , "Fullscreen", OPT_NONE },
@@ -91,6 +92,11 @@
             exit(0);
             break;
 
+        case 1:
+            dmPrintLicense(stdout);
+            exit(0);
+            break;
+
         case 2:
             dmVerbosity++;
             break;
--- a/tools/data2inc.c	Mon Jan 13 22:25:21 2020 +0200
+++ b/tools/data2inc.c	Mon Jan 13 22:26:24 2020 +0200
@@ -54,6 +54,7 @@
 static const DMOptArg optList[] =
 {
     {  0, '?', "help"            , "Show this help", OPT_NONE },
+    {  1,   0, "license"         , "Print out this program's license agreement", OPT_NONE },
 
     { 10, 'n', "name"            , "Set object name", OPT_ARGREQ },
     { 12, 't', "type"            , "Set datatype (unsigned char/byte)", OPT_ARGREQ },
@@ -119,6 +120,11 @@
             exit(0);
             break;
 
+        case 1:
+            dmPrintLicense(stdout);
+            exit(0);
+            break;
+
         case 10:
             optObjName = optArg;
             break;
--- a/tools/dumpmod.c	Mon Jan 13 22:25:21 2020 +0200
+++ b/tools/dumpmod.c	Mon Jan 13 22:26:24 2020 +0200
@@ -23,6 +23,7 @@
 static const DMOptArg optList[] =
 {
     {  0, '?', "help"            , "Show this help", OPT_NONE },
+    {  1,   0, "license"         , "Print out this program's license agreement", OPT_NONE },
     {  2, 'v', "verbose"         , "Be more verbose", OPT_NONE },
 
     { 10, 'p', "patterns"        , "View patterns", OPT_NONE },
@@ -54,6 +55,11 @@
             exit(0);
             break;
 
+        case 1:
+            dmPrintLicense(stdout);
+            exit(0);
+            break;
+
         case 2:
             dmVerbosity++;
             break;
--- a/tools/fanalyze.c	Mon Jan 13 22:25:21 2020 +0200
+++ b/tools/fanalyze.c	Mon Jan 13 22:26:24 2020 +0200
@@ -165,6 +165,7 @@
 static const DMOptArg optList[] =
 {
     {  0, '?', "help"            , "Show this help", OPT_NONE },
+    {  1,   0, "license"         , "Print out this program's license agreement", OPT_NONE },
     {  2, 'v', "verbose"         , "Be more verbose", OPT_NONE },
 
     { 10, 'g', "grep"            , "Binary grep <val>[,<val2>...][:<le|be>[8|16|32]]", OPT_ARGREQ },
@@ -492,6 +493,11 @@
             break;
 
         case 1:
+            dmPrintLicense(stdout);
+            exit(0);
+            break;
+
+        case 2:
             dmVerbosity++;
             break;
 
--- a/tools/fontconv.c	Mon Jan 13 22:25:21 2020 +0200
+++ b/tools/fontconv.c	Mon Jan 13 22:26:24 2020 +0200
@@ -25,6 +25,7 @@
 static const DMOptArg optList[] =
 {
     {  0, '?', "help"            , "Show this help", OPT_NONE },
+    {  1,   0, "license"         , "Print out this program's license agreement", OPT_NONE },
     {  2, 'v', "verbose"         , "Be more verbose", OPT_NONE },
 
     { 10, 's', "size"            , "Set glyph dimensions (-s W:H or -s N) for image->font conversion", OPT_ARGREQ },
@@ -61,6 +62,11 @@
             break;
 
         case 1:
+            dmPrintLicense(stdout);
+            exit(0);
+            break;
+
+        case 2:
             dmVerbosity++;
             break;
 
--- a/tools/gfxconv.c	Mon Jan 13 22:25:21 2020 +0200
+++ b/tools/gfxconv.c	Mon Jan 13 22:26:24 2020 +0200
@@ -160,6 +160,7 @@
 static const DMOptArg optList[] =
 {
     {  0, '?', "help"            , "Show this help", OPT_NONE },
+    {  1,   0, "license"         , "Print out this program's license agreement", OPT_NONE },
     {  2, 'v', "verbose"         , "Be more verbose", OPT_NONE },
 
     { 10, 'o', "output"          , "Output filename", OPT_ARGREQ },
@@ -682,6 +683,11 @@
             exit(0);
             break;
 
+        case 1:
+            dmPrintLicense(stdout);
+            exit(0);
+            break;
+
         case 2:
             dmVerbosity++;
             break;
--- a/tools/mod2wav.c	Mon Jan 13 22:25:21 2020 +0200
+++ b/tools/mod2wav.c	Mon Jan 13 22:26:24 2020 +0200
@@ -65,6 +65,7 @@
 static const DMOptArg optList[] =
 {
     {  0, '?', "help"            , "Show this help", OPT_NONE },
+    {  1,   0, "license"         , "Print out this program's license agreement", OPT_NONE },
     {  2, 'v', "verbose"         , "Be more verbose", OPT_NONE },
 
     { 10, '1', "16bit"           , "16-bit output", OPT_NONE },
@@ -99,6 +100,11 @@
             exit(0);
             break;
 
+        case 1:
+            dmPrintLicense(stdout);
+            exit(0);
+            break;
+
         case 2:
             dmVerbosity++;
             break;
--- a/tools/objlink.c	Mon Jan 13 22:25:21 2020 +0200
+++ b/tools/objlink.c	Mon Jan 13 22:26:24 2020 +0200
@@ -149,19 +149,22 @@
  */
 static const DMOptArg optList[] =
 {
-    {  0, '?', "help",        "Show this help", OPT_NONE },
-    {  1, 'r', "input-raw",   "RAW input: -r <file>:<addr>", OPT_ARGREQ },
-    {  2, 'p', "input-prg",   "PRG input: -p <file>[:<addr>]", OPT_ARGREQ },
-    { 12, 's', "section",     "Reserved section: -s <start>-<end>[,name] or <start>:<len>[,name]", OPT_ARGREQ },
-    {  5, 'o', "output",      "Specify output file, -o <file>", OPT_ARGREQ },
-    {  6, 'O', "overlap",     "Allow overlapping memory areas", OPT_NONE },
-    {  7, 'm', "model",       "Set memory model", OPT_ARGREQ },
-    {  8, 'l', "link-file",   "Output addresses and labels into file", OPT_ARGREQ },
-    {  9, 'f', "format",      "Format of link-file: (g)eneric, (p)lain, (d)ecimal", OPT_ARGREQ },
-    { 10, 'i', "initvalue",   "Initialize memory with: -i <byte/word/dword>:[bwd]", OPT_ARGREQ },
-    { 11, 'd', "describe",    "Output ASCII memory map description", OPT_NONE },
-    { 13, 'c', "crop",        "Crop output file to: -c <start>-<end> or <start>:<len>", OPT_ARGREQ },
-    { 14, 'L', "load-address","Set output file load address (or 'none' for 'raw' output)", OPT_ARGREQ },
+    {  0, '?', "help"            , "Show this help", OPT_NONE },
+    {  1,   0, "license"         , "Print out this program's license agreement", OPT_NONE },
+    {  2, 'v', "verbose"         , "Be more verbose", OPT_NONE },
+
+    { 10, 'r', "input-raw"       , "RAW input: -r <file>:<addr>", OPT_ARGREQ },
+    { 12, 'p', "input-prg"       , "PRG input: -p <file>[:<addr>]", OPT_ARGREQ },
+    { 14, 's', "section"         , "Reserved section: -s <start>-<end>[,name] or <start>:<len>[,name]", OPT_ARGREQ },
+    { 16, 'o', "output"          , "Specify output file, -o <file>", OPT_ARGREQ },
+    { 18, 'O', "overlap"         , "Allow overlapping memory areas", OPT_NONE },
+    { 20, 'm', "model"           , "Set memory model", OPT_ARGREQ },
+    { 22, 'l', "link-file"       , "Output addresses and labels into file", OPT_ARGREQ },
+    { 24, 'f', "format"          , "Format of link-file: (g)eneric, (p)lain, (d)ecimal", OPT_ARGREQ },
+    { 26, 'i', "init-value"      , "Initialize memory with: -i <byte/word/dword>:[bwd]", OPT_ARGREQ },
+    { 28, 'd', "describe"        , "Output ASCII memory map description", OPT_NONE },
+    { 30, 'c', "crop"            , "Crop output file to: -c <start>-<end> or <start>:<len>", OPT_ARGREQ },
+    { 32, 'L', "load-address"    , "Set output file load address (or 'none' for 'raw' output)", OPT_ARGREQ },
 };
 
 static const int optListN = sizeof(optList) / sizeof(optList[0]);
@@ -356,158 +359,169 @@
     char *p;
     unsigned int tmpi;
 
-    switch (optN) {
-    case 0:
-        argShowHelp();
-        exit(0);
-        break;
-
-    case 1:
-        // Add RAW
-        if (!dmParseInputFile(optArg, STYPE_RAW, STYPE_RAW, "RAW", TRUE))
-            return FALSE;
-        break;
-
-    case 2:
-        // Add PRG
-        if (!dmParseInputFile(optArg, STYPE_PRGA, STYPE_PRG, "PRG", FALSE))
-            return FALSE;
-        break;
+    switch (optN)
+    {
+        case 0:
+            argShowHelp();
+            exit(0);
+            break;
 
-    case 5:
-        // Set output file name
-        optDestName = optArg;
-        break;
+        case 1:
+            dmPrintLicense(stdout);
+            exit(0);
+            break;
 
-    case 6:
-        // Allow overlapping segments
-        optAllowOverlap = TRUE;
-        dmErrorMsg("Warning, allowing overlapping data.\n");
-        break;
-
-    case 7:
-        // Set memory model
-        optMemModel = atoi(optArg);
-        if (optMemModel < 0 || optMemModel >= nmemoryModels)
-        {
-            dmErrorMsg("Invalid memory model number %i!\n", optMemModel);
-            return FALSE;
-        }
-        break;
+        case 2:
+            dmVerbosity++;
+            break;
 
-    case 8:
-        // Linker file
-        optLinkFileName = optArg;
-        break;
+        case 10:
+            // Add RAW
+            if (!dmParseInputFile(optArg, STYPE_RAW, STYPE_RAW, "RAW", TRUE))
+                return FALSE;
+            break;
 
-    case 9:
-        // Linker file format
-        switch (tolower(optArg[0]))
-        {
-            case 'g':
-                optLinkFileFormat = FMT_GENERIC;
-                break;
-            case 'p':
-                optLinkFileFormat = FMT_PLAIN;
-                break;
-            case 'd':
-                optLinkFileFormat = FMT_DECIMAL;
-                break;
+        case 12:
+            // Add PRG
+            if (!dmParseInputFile(optArg, STYPE_PRGA, STYPE_PRG, "PRG", FALSE))
+                return FALSE;
+            break;
 
-            default:
-                dmErrorMsg("Invalid/unknown linker file format '%s'!\n",
-                    optArg);
-                return FALSE;
-        }
-        break;
+        case 14:
+            {
+                char *sectName = "Clear";
+                unsigned int sectStart, sectEnd, sectLen;
+                if (!dmParseSection(optArg, &sectStart, &sectEnd, &sectName, TRUE))
+                    return FALSE;
 
-    case 10:
-        // Initialization value
-        optInitValueType = 1;
-        if ((p = strrchr(optArg, ':')) != NULL)
-        {
-            *p = 0;
-            switch (tolower(p[1]))
-            {
-                case 'b': optInitValueType = 1; break;
-                case 'w': optInitValueType = 2; break;
-                case 'd': optInitValueType = 4; break;
-                default:
-                    dmErrorMsg("Invalid init value type '%c' specified for '%s'.\n",
-                        p[1], optArg);
+                // Allocate memory block
+                sectLen = sectEnd - sectStart + 1;
+                dmMsg(1, "Reserve $%.4x - $%.4x ($%x, %d bytes) as '%s'\n",
+                    sectStart, sectEnd, sectLen, sectLen, sectName);
+
+                if (!dmReserveMemBlock(sectStart, sectEnd, sectName, MTYPE_RES))
                     return FALSE;
             }
-        }
-        if (!dmGetIntVal(optArg, &tmpi, NULL))
-        {
-            dmErrorMsg("Invalid initvalue '%s'.\n", optArg);
-            return FALSE;
-        }
-        optInitValue = tmpi;
-        break;
+            break;
+
+        case 16:
+            // Set output file name
+            optDestName = optArg;
+            break;
+
+        case 18:
+            // Allow overlapping segments
+            optAllowOverlap = TRUE;
+            break;
 
-    case 11:
-        // Set describe mode
-        optDescribe = TRUE;
-        break;
+        case 20:
+            // Set memory model
+            optMemModel = atoi(optArg);
+            if (optMemModel < 0 || optMemModel >= nmemoryModels)
+            {
+                dmErrorMsg("Invalid memory model number %i!\n", optMemModel);
+                return FALSE;
+            }
+            break;
 
-    case 12:
-        {
-            char *sectName = "Clear";
-            unsigned int sectStart, sectEnd, sectLen;
-            if (!dmParseSection(optArg, &sectStart, &sectEnd, &sectName, TRUE))
-                return FALSE;
-
-            // Allocate memory block
-            sectLen = sectEnd - sectStart + 1;
-            dmMsg(1, "Reserve $%.4x - $%.4x ($%x, %d bytes) as '%s'\n",
-                sectStart, sectEnd, sectLen, sectLen, sectName);
+        case 22:
+            // Linker file
+            optLinkFileName = optArg;
+            break;
 
-            if (!dmReserveMemBlock(sectStart, sectEnd, sectName, MTYPE_RES))
-                return FALSE;
-        }
-        break;
-
-    case 13:
-        {
-            size_t cropLen;
-            if (!dmParseSection(optArg, &optCropStart, &optCropEnd, NULL, FALSE))
-                return FALSE;
+        case 24:
+            // Linker file format
+            switch (tolower(optArg[0]))
+            {
+                case 'g':
+                    optLinkFileFormat = FMT_GENERIC;
+                    break;
+                case 'p':
+                    optLinkFileFormat = FMT_PLAIN;
+                    break;
+                case 'd':
+                    optLinkFileFormat = FMT_DECIMAL;
+                    break;
 
-            cropLen = optCropEnd - optCropStart + 1;
-            dmMsg(1, "Cutting output to $%.4x - $%.4x "
-                "($%" DM_PRIx_SIZE_T ", %" DM_PRIu_SIZE_T " bytes)\n",
-                optCropStart, optCropEnd,
-                cropLen, cropLen);
+                default:
+                    dmErrorMsg("Invalid/unknown linker file format '%s'!\n",
+                        optArg);
+                    return FALSE;
+            }
+            break;
 
-            optCropOutput = TRUE;
-        }
-        break;
-
-    case 14:
-        // Set loading address
-        if (strcasecmp(optArg, "none") == 0)
-            optLoadAddress = LA_NONE;
-        else
-        {
+        case 26:
+            // Initialization value
+            optInitValueType = 1;
+            if ((p = strrchr(optArg, ':')) != NULL)
+            {
+                *p = 0;
+                switch (tolower(p[1]))
+                {
+                    case 'b': optInitValueType = 1; break;
+                    case 'w': optInitValueType = 2; break;
+                    case 'd': optInitValueType = 4; break;
+                    default:
+                        dmErrorMsg("Invalid init value type '%c' specified for '%s'.\n",
+                            p[1], optArg);
+                        return FALSE;
+                }
+            }
             if (!dmGetIntVal(optArg, &tmpi, NULL))
             {
-                dmErrorMsg("Invalid loading address '%s'.\n", optArg);
+                dmErrorMsg("Invalid initvalue '%s'.\n", optArg);
                 return FALSE;
             }
-            if (tmpi >= 64*1024)
+            optInitValue = tmpi;
+            break;
+
+        case 28:
+            // Set describe mode
+            optDescribe = TRUE;
+            break;
+
+        case 30:
             {
-                dmErrorMsg("Invalid or insane loading address %d/$%x!\n",
-                    tmpi, tmpi);
-                return FALSE;
+                size_t cropLen;
+                if (!dmParseSection(optArg, &optCropStart, &optCropEnd, NULL, FALSE))
+                    return FALSE;
+
+                cropLen = optCropEnd - optCropStart + 1;
+                dmMsg(1, "Cutting output to $%.4x - $%.4x "
+                    "($%" DM_PRIx_SIZE_T ", %" DM_PRIu_SIZE_T " bytes)\n",
+                    optCropStart, optCropEnd,
+                    cropLen, cropLen);
+
+                optCropOutput = TRUE;
             }
-            optLoadAddress = tmpi;
-        }
-        break;
+            break;
 
-    default:
-        dmErrorMsg("Unimplemented option argument '%s'.\n", currArg);
-        return FALSE;
+        case 32:
+            // Set loading address
+            if (strcasecmp(optArg, "none") == 0)
+            {
+                optLoadAddress = LA_NONE;
+            }
+            else
+            {
+                if (!dmGetIntVal(optArg, &tmpi, NULL))
+                {
+                    dmErrorMsg("Invalid loading address '%s'.\n", optArg);
+                    return FALSE;
+                }
+                if (tmpi >= 64*1024)
+                {
+                    dmErrorMsg("Invalid or insane loading address %d/$%x!\n",
+                        tmpi, tmpi);
+                    return FALSE;
+                }
+                optLoadAddress = tmpi;
+            }
+            break;
+
+        default:
+            dmErrorMsg("Unimplemented option argument '%s'.\n", currArg);
+            return FALSE;
     }
 
     return TRUE;
@@ -798,6 +812,10 @@
         goto out;
     }
 
+    // Warn about overlaps if enabled
+    if (optAllowOverlap)
+        dmMsg(-1, "WARNING: Overlapping data has been allowed!\n");
+
     // Allocate memory
     memModel = &memoryModels[optMemModel];
     dmMsg(1, "Using memory model #%d '%s', %d bytes.\n",
--- a/tools/packed.c	Mon Jan 13 22:25:21 2020 +0200
+++ b/tools/packed.c	Mon Jan 13 22:26:24 2020 +0200
@@ -54,6 +54,7 @@
 static const DMOptArg optList[] =
 {
     {  0, '?', "help"            , "Show this help", OPT_NONE },
+    {  1,   0, "license"         , "Print out this program's license agreement", OPT_NONE },
     {  2, 'v', "verbose"         , "Be more verbose", OPT_NONE },
 
     {  3, 'n', "nocompress"      , "No compression / decompression", OPT_NONE },
@@ -103,6 +104,11 @@
             exit(0);
             break;
 
+        case 1:
+            dmPrintLicense(stdout);
+            exit(0);
+            break;
+
         case 2:
             dmVerbosity++;
             break;
--- a/tools/ppl.c	Mon Jan 13 22:25:21 2020 +0200
+++ b/tools/ppl.c	Mon Jan 13 22:26:24 2020 +0200
@@ -69,6 +69,7 @@
 static const DMOptArg optList[] =
 {
     {  0, '?', "help"            , "Show this help", OPT_NONE },
+    {  1,   0, "license"         , "Print out this program's license agreement", OPT_NONE },
     {  2, 'v', "verbose"         , "Be more verbose", OPT_NONE },
 
     { 10,   0, "fs"              , "Fullscreen", OPT_NONE },
@@ -105,6 +106,11 @@
             exit(0);
             break;
 
+        case 1:
+            dmPrintLicense(stdout);
+            exit(0);
+            break;
+
         case 2:
             dmVerbosity++;
             break;
--- a/tools/xm2jss.c	Mon Jan 13 22:25:21 2020 +0200
+++ b/tools/xm2jss.c	Mon Jan 13 22:26:24 2020 +0200
@@ -48,6 +48,7 @@
 static const DMOptArg optList[] =
 {
     {  0, '?', "help"            , "Show this help", OPT_NONE },
+    {  1,   0, "license"         , "Print out this program's license agreement", OPT_NONE },
     {  2, 'v', "verbose"         , "Be more verbose", OPT_NONE },
 
     { 10, 'i', "ignore"          , "Ignore errors", OPT_NONE },
@@ -94,6 +95,10 @@
             exit(0);
             break;
 
+        case 1:
+            dmPrintLicense(stdout);
+            exit(0);
+            break;
 
         case 2:
             dmVerbosity++;