home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1999 February / PCO_0299.ISO / filesbbs / dos / indigo01.exe / CONFIG.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-26  |  25.9 KB  |  679 lines

  1. // This program is free software; you can redistribute it and/or modify it
  2. // under the terms of the GNU General Public License as published by the Free
  3. // Software Foundation; either version 2 of the License, or (at your option)
  4. // any later version.
  5.  
  6. // You should have received a copy of the GNU General Public License along
  7. // with this program; if not, write to the Free Software Foundation, Inc., 675
  8. // Mass Ave, Cambridge, MA 02139, USA.
  9.  
  10. // config.cpp
  11. // Routines for reading Indigo's configuration file.
  12.  
  13. #include "config.h"
  14. #include "fido.h"
  15. #include "debug.h"
  16. #include <string.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19.  
  20. #ifdef __LINUX__
  21. #define stricmp strcasecmp
  22. #endif
  23.  
  24. enum cfgsection_t { none, global, uplinks, areas };
  25.  
  26. // Some typedefs to make life easier.
  27. typedef char *charP;
  28. typedef FidoAddress *FidoAddressP;
  29. typedef BlueWaveArea *BlueWaveAreaP;
  30. typedef Uplink *UplinkP;
  31.  
  32. // Prototypes
  33. void split3(charP start_p, charP &pt2_p, charP &pt3_p);
  34. void split2(charP start_p, charP &pt2_p);
  35. int checkCommandString(char *);
  36.  
  37. // constructor
  38. // Reads the specified configuration file.
  39. Configuration::Configuration(char *fileName, direction_t direction)
  40. {
  41.     doDEBUG(printf("Configuration::Configuration(\"%s\", diretion_t(%d))\n",
  42.                    fileName, (int) direction));
  43.  
  44.     // Try to open the configuration file. If we can't do it, exit the
  45.     // program with an errorlevel.
  46.     FILE *cfg;
  47.     if (NULL == (cfg = fopen(fileName, "rt"))) {
  48.         fprintf(stderr, "* Configuration file not found: %s\n", fileName);
  49.         exit(1);
  50.     }
  51.  
  52.     // Initialize data
  53.     numareas = numuplinks = 0;
  54.     arealist_pp = NULL;
  55.     myAddress_pp = NULL;
  56.     uplink_pp = NULL;
  57.     myName_p = NULL;
  58.     uplinklist_pp = NULL;
  59.     compresscmd_p = decompresscmd_p = base_p = myName_p = NULL;
  60.  
  61.     // The Origin line is originally empty.
  62.     char *origin = strdup("");
  63.  
  64.     // Initialize standard strings.
  65.     char netmail[50], badmail[50];
  66.     strcpy(netmail, "NetMail");
  67.     strcpy(badmail, "Bad mail");
  68.  
  69.     // Set the temporary path from the environment variable TEMP.
  70.     if (NULL != (temppath_p = getenv("TEMP")))
  71.         temppath_p = strdup(temppath_p); // Reallocate it.
  72.     else
  73.         temppath_p = strdup("."); // Use the current directory.
  74.  
  75.     // Set up the Blue Wave path default value.
  76.     bwpath_p = strdup(".");
  77.  
  78.     // Now read the configuration.
  79.     char configline[256];
  80.     char outboundpath[256] = "";
  81.     cfgsection_t section = none;
  82.     unsigned areacounter = 0, uplinkcounter = 0, defaultzone = 0;
  83.     char *ch_p;
  84.     while (NULL != fgets(configline, sizeof(configline), cfg)) {
  85.         // For each line.
  86.  
  87.         // Remove the trailing newline character.
  88.         configline[strlen(configline) - 1] = 0;
  89.         doDEBUG(printf("%d \"%s\"", (int) section, configline));
  90.  
  91.         // Does the current line indicate a section change?
  92.         if (!stricmp(configline, "[GLOBAL]"))
  93.             section = global;
  94.         else if (!stricmp(configline, "[UPLINKS]"))
  95.             section = uplinks;
  96.         else if (!stricmp(configline, "[AREAS]"))
  97.             section = areas;
  98.  
  99.         // This checks whether the current line is on the form
  100.         // keyword=value[,value...]
  101.         if (section != none && NULL != (ch_p = strchr(configline, '=')) &&
  102.             ';' != configline[0]) {
  103.             *ch_p = 0;      // Split the string at the '=' sign.
  104.             ch_p ++;        // ch_p points to the next part.
  105.  
  106.             doDEBUG(printf(" => \"%s\"-\"%s\"", configline, ch_p));
  107.  
  108.             switch (section) {
  109.             case global: // Global settings.
  110.                 if (!stricmp(configline, "NAME")) {
  111.                     // "Name=Your name"
  112.                     if (NULL != myName_p)
  113.                         delete myName_p; // Deallocate previous definition.
  114.                     myName_p = strdup(ch_p);
  115.                 }
  116.                 else if (!stricmp(configline, "NETMAIL")) {
  117.                     // "Netmail=Netmail area name"
  118.                     strncpy(netmail, ch_p, sizeof(netmail));
  119.                     // Make sure there is a trailing null character
  120.                     netmail[sizeof(netmail) - 1] = 0;
  121.                 }
  122.                 else if (!stricmp(configline, "BADMAIL")) {
  123.                     // "Badmail=Badmail area name"
  124.                     strncpy(badmail, ch_p, sizeof(badmail));
  125.                     // Make sure there is a trailing null character.
  126.                     badmail[sizeof(badmail) - 1] = 0;
  127.                 }
  128.                 else if (!stricmp(configline, "BASENAME")) {
  129.                     // "Basename=Blue Wave name"
  130.                     if (NULL != base_p)
  131.                         delete base_p; // Deallocate previous definition.
  132.                     base_p = strdup(ch_p);
  133.                 }
  134.                 else if (!stricmp(configline, "OUTBOUND")) {
  135.                     // "Outbound=Outbound path,default zone"
  136.                     char *ch2_p;
  137.                     split2(ch_p, ch2_p); // Split the data value.
  138.                     strncpy(outboundpath, ch_p, sizeof(outboundpath));
  139.                     // Make sure there is a trailing null character.
  140.                     outboundpath[sizeof(outboundpath) - 1] = 0;
  141.                     // Get the default zone number.
  142.                     sscanf(ch2_p, "%u", &defaultzone);
  143.                 }
  144.                 else if (!stricmp(configline, "ORIGIN")) {
  145.                     // "Origin=Origin string"
  146.                     free(origin); // Deallocate previous definition.
  147.                     origin = strdup(ch_p);
  148.                 }
  149.                 else if (!stricmp(configline, "COMPRESS")) {
  150.                     // "Compress=Compression command specification"
  151.                     // Make sure it's a valid string.
  152.                     if (checkCommandString(ch_p)) {
  153.                         // The compression command is ok.
  154.                         if (NULL != compresscmd_p)
  155.                             delete compresscmd_p; // Deallocate previous def.
  156.                         compresscmd_p = strdup(ch_p);
  157.                     }
  158.                     else {
  159.                         // The compression command is not ok.
  160.                         // This is a fatal error.
  161.                         fprintf(stderr, "* Illegal compress command: %s\n",
  162.                                 ch_p);
  163.                         exit(1);
  164.                     }
  165.                 }
  166.                 else if (!stricmp(configline, "DECOMPRESS")) {
  167.                     // "Decompress=Decompression command specification"
  168.                     // Make sure it's a valid string.
  169.                     if (checkCommandString(ch_p)) {
  170.                         // The decompression command is ok.
  171.                         if (NULL != decompresscmd_p)
  172.                             delete decompresscmd_p; // Deallocate previous def.
  173.                         decompresscmd_p = strdup(ch_p);
  174.                     }
  175.                     else {
  176.                         // The decompression command is not ok.
  177.                         // This is a fatal error.
  178.                         fprintf(stderr, "* Illegal decompress command: %s\n",
  179.                                 ch_p);
  180.                         exit(1);
  181.                     }
  182.                 }
  183.                 else if (!stricmp(configline, "TEMPPATH")) {
  184.                     // "TempPath=Path to temporary directory"
  185.                     if (NULL != temppath_p)
  186.                         delete temppath_p; // Deallocate previous definition.
  187.                     temppath_p = strdup(ch_p);
  188.                 }
  189.                 else if (!stricmp(configline, "BWPATH")) {
  190.                     // "BWPath=Path to Blue Wave packets"
  191.                     if (NULL != bwpath_p)
  192.                         delete bwpath_p; // Deallocate previous definition.
  193.                     bwpath_p = strdup(ch_p);
  194.                 }
  195.                 else {
  196.                     // The configuration keyword is unknown.
  197.                     fprintf(stderr, "* Illegal configuration option: %s\n",
  198.                             configline);
  199.                     exit(1);
  200.                 }
  201.                 break;
  202.                 
  203.             case uplinks: // Uplink settings.
  204.                 if (0 == numuplinks && !stricmp(configline, "UPLINKS")) {
  205.                     // "Uplinks=Number of uplinks"
  206.  
  207.                     // Extract the number of uplinks.
  208.                     numuplinks = atoi(ch_p);
  209.  
  210.                     // Allocate space for the address pointer arrays.
  211.                     myAddress_pp = new FidoAddressP[numuplinks];
  212.                     uplink_pp =    new FidoAddressP[numuplinks];
  213.  
  214.                     // Fill the address pointer arrays with NULL pointers.
  215.                     for (unsigned i = 0; i < numuplinks; i ++) {
  216.                         myAddress_pp[i] = NULL;
  217.                         uplink_pp[i] = NULL;
  218.                     }
  219.  
  220.                     // If we are in outbound mode, allocate space for the
  221.                     // uplink pointer array (for the PKT files).
  222.                     if (out == direction) {
  223.                         uplinklist_pp = new UplinkP[numuplinks];
  224.                         // Fill the uplink pointer array with NULL pointers.
  225.                         for (unsigned i = 0; i < numuplinks; i ++)
  226.                             uplinklist_pp[i] = NULL;
  227.                     }
  228.                 }
  229.                 else if (numuplinks != 0 && uplinkcounter < numuplinks &&
  230.                          !stricmp(configline, "ADDRESS")) {
  231.                     // "Address=Your address,Uplink address,Password"
  232.                     char *ch2_p, *ch3_p;
  233.                     split3(ch_p, ch2_p, ch3_p); // Split the data value
  234.                     if (ch3_p) { // There were three parts.
  235.                         unsigned z, n, f, p = 0; // p=0 allows for 3D addresses
  236.  
  237.                         // Extract the first address (your own).
  238.                         sscanf(ch_p, "%u:%u/%u.%u", &z, &n, &f, &p);
  239.                         // Allocate space for a "your address" in the pointer
  240.                         // array.
  241.                         myAddress_pp[uplinkcounter] =
  242.                             new FidoAddress(z, n, f, p);
  243.  
  244.                         // Extract the second address (uplink).
  245.                         p = 0; // p=0 allows for 3D addresses.
  246.                         sscanf(ch2_p, "%u:%u/%u.%u", &z, &n, &f, &p);
  247.                         // Allocate space for an uplink address in the pointer
  248.                         // array.
  249.                         uplink_pp[uplinkcounter] =
  250.                             new FidoAddress(z, n, f, p);
  251.  
  252.                         // If we are in outbound direction, we need to
  253.                         // allocate space for a PKT object ("uplink").
  254.                         if (out == direction) {
  255.                             // Check that we have a outbound path
  256.                             // defined, but continue even if there is
  257.                             // none.
  258.                             if (0 == outboundpath[0]) {
  259.                                 puts("* Config error: OUTBOUND must "
  260.                                      "be defined before ADDRESS");
  261.                             }
  262.  
  263.                             // Create the uplink object.
  264.                             uplinklist_pp[uplinkcounter] =
  265.                                 new Uplink(*myAddress_pp[uplinkcounter],
  266.                                            *uplink_pp[uplinkcounter],
  267.                                            outboundpath,
  268.                                            ch3_p, // password
  269.                                            defaultzone,
  270.                                            origin);
  271.                         }
  272.  
  273.                         uplinkcounter ++;
  274.                     }
  275.                 }
  276.                 else {
  277.                     // The configuration keyword is unknown.
  278.                     fprintf(stderr, "* Illegal uplink configuration option: %s\n",
  279.                             configline);
  280.                     exit(1);
  281.                 }
  282.                 break;
  283.                 
  284.             case areas: // settings.
  285.                 if (0 == numareas && !stricmp(configline, "AREAS")) {
  286.                     // "Areas=Number of areas"
  287.  
  288.                     // Extract the number of defined echomail areas.
  289.                     sscanf(ch_p, "%u", &numareas);
  290.  
  291.                     // Add to it the number of non-echomail areas
  292.                     // (one netmail per uplink, plus a badmail area).
  293.                     numareas += uplinkcounter + 1;
  294.  
  295.                     // In incoming mode, allocate a Blue Wave area pointer
  296.                     // array.
  297.                     if (in == direction) {
  298.                         arealist_pp = new BlueWaveAreaP[numareas];
  299.  
  300.                         // Create the non-echomail areas.
  301.  
  302.                         // First the netmail areas. Their tag is created
  303.                         // on the format "[zone.net.node.point]", and their
  304.                         // area numbers are on the format "NExxx" where
  305.                         // xxx is the number of the uplink in our list.
  306.                         // The area title is the string for "netmail" defined
  307.                         // earlier, followed by the address we use.
  308.                         for (unsigned i = 0; i < uplinkcounter; i ++) {
  309.                             char nettag[21];
  310.                             sprintf(nettag, "[%u.%u.%u.%u]",
  311.                                     myAddress_pp[i]->zone,
  312.                                     myAddress_pp[i]->net,
  313.                                     myAddress_pp[i]->node,
  314.                                     myAddress_pp[i]->point);
  315.                             char netnum[6], nettitle[50];
  316.                             sprintf(netnum, "NE%03u", i);
  317.                             sprintf(nettitle, "%s %u:%u/%u.%u", netmail,
  318.                                     myAddress_pp[i]->zone, myAddress_pp[i]->net,
  319.                                     myAddress_pp[i]->node,
  320.                                     myAddress_pp[i]->point);
  321.                             arealist_pp[i] = new BlueWaveArea(1, netnum, nettag,
  322.                                                               nettitle,
  323.                                                               myAddress_pp[i]->zone);
  324.                         }
  325.  
  326.                         // Secondly, create the badmail area.
  327.                         arealist_pp[uplinkcounter] =
  328.                             new BlueWaveArea(0, "BAD", "BADMAIL", badmail,
  329.                                              myAddress_pp[0]->zone);
  330.                     }
  331.  
  332.                     // Remember the number of the badmail area.
  333.                     badareano = uplinkcounter;
  334.                     // Set the area counter to point past the areas
  335.                     // created here.
  336.                     areacounter = uplinkcounter + 1;
  337.                 }
  338.                 else if (areacounter < numareas) {
  339.                     // "Echotag=Your address,Area number,Area title"
  340.                     char *ch2_p, *ch3_p;
  341.                     split3(ch_p, ch2_p, ch3_p);
  342.  
  343.                     // configline -> echotag
  344.                     // ch_p       -> address
  345.                     // ch2_p      -> number
  346.                     // ch3_p      -> name
  347.  
  348.                     if (ch3_p) { // There were three parts.
  349.                         if (in == direction) {
  350.                             // If in inbound mode, we need to allocate a
  351.                             // Blue Wave area object for our area.
  352.                             arealist_pp[areacounter] =
  353.                                 new BlueWaveArea(0, ch2_p, configline, ch3_p,
  354.                                                  atoi(ch_p));
  355.                         }
  356.                         else {
  357.                             // If in outbound mode, we need to add the area
  358.                             // to the list of known areas for the uplink
  359.                             // that is to be sent to.
  360.  
  361.                             // Extract the address for the area.
  362.                             unsigned z, n, f, p = 0;
  363.                             sscanf(ch_p, "%u:%u/%u.%u", &z, &n, &f, &p);
  364.  
  365.                             // Search for the uplink.
  366.                             int uplink = uplinkNumber(FidoAddress(z, n, f, p));
  367.  
  368.                             if (-1 == uplink) {
  369.                                 // If we didn't find an uplink setup,
  370.                                 // report this, and consider it a fatal
  371.                                 // error. This error is only found in
  372.                                 // outbound mode.
  373.                                 fprintf(stderr,
  374.                                         "* Area %s: missing uplink for %s\n",
  375.                                         configline, ch_p);
  376.                                 exit(1);
  377.                             }
  378.                             else {
  379.                                 // Insert the area into the list of known
  380.                                 // areas.
  381.                                 uplinklist_pp[uplink]->addArea(configline);
  382.                             }
  383.                         }
  384.                         // Increase the area counter.
  385.                         areacounter ++;
  386.                         
  387.                         doDEBUG(printf("  areacounter = %u", areacounter));
  388.                     }
  389.                     else {
  390.                         // This area definition is illegal.
  391.                         fprintf(stderr, "* Illegal area definition: %s\n",
  392.                                 configline);
  393.                         exit(1);
  394.                     }
  395.                 }
  396.                 else {
  397.                     // If we still have areas left, but the number of
  398.                     // areas that we allocated are to few, warn the
  399.                     // user about it, and consider it a fatal error.
  400.                     if (areacounter < numareas) {
  401.                         fputs("* Too few area definitions allocated!\n",
  402.                               stderr);
  403.                         exit(1);
  404.                     }
  405.                 }
  406.                 break;
  407.             }
  408.         }
  409.         doDEBUG(puts(""));
  410.     }
  411.  
  412.     fclose(cfg);
  413.     
  414.     // Now we have read the configuration file, check that some criteria
  415.     // are fullfilled.
  416.  
  417.     // 1: The number of uplinks allocated should match the number of
  418.     // uplinks read. If not, consider it a fatal error.
  419.     if (uplinkcounter < numuplinks) {
  420.         fprintf(stderr, "* %u uplinks allocated, only %u used!\n",
  421.                 numuplinks, uplinkcounter);
  422.         exit(1);
  423.     }
  424.  
  425.     // 2: The number of areas allocated should match the number of
  426.     // areas read. If not, consider it a fatal error.
  427.     if (areacounter < numareas) {
  428.         fputs("* Too many area definitions allocated!\n", stderr);
  429.         doDEBUG(fprintf(stderr, "areacounter=%u, numareas=%u", areacounter,
  430.                         numareas));
  431.         exit(1);
  432.     }
  433.  
  434.     // 3: There should be a path to put the Blue Wave packets in, if
  435.     // we are in inbound mode. If not, consider it a fatal error.
  436.     if (NULL == bwpath_p && in == direction) {
  437.         fputs("* BwPath setup missing", stderr);
  438.         exit(1);
  439.     }
  440.  
  441.     // 4: There should be a Blue Wave base name defined.
  442.     // If not, consider it a fatal error.
  443.     if (NULL == base_p) {
  444.         fputs("* BaseName setup missing", stderr);
  445.         exit(1);
  446.     }
  447.  
  448.     // 5: There should be a decompression command defined, if we are
  449.     // in outbound mode. If not, consider it a fatal error.
  450.     if (NULL == decompresscmd_p && out == direction) {
  451.         fputs("* Decompression command setup missing", stderr);
  452.         exit(1);
  453.     }
  454.  
  455.     // 6: There should be a compression command defined, if we are in
  456.     // inbound mode. If not, consider it a fatal error.
  457.     if (NULL == compresscmd_p && in == direction) {
  458.         fputs("* Compression command setup missing", stderr);
  459.         exit(1);
  460.     }
  461.  
  462.     // Free the origin line allocation. We don't need it anymore.
  463.     free(origin);
  464. }
  465.  
  466. // destructor
  467. // Deallocate things we have allocated.
  468. Configuration::~Configuration()
  469. {
  470.     doDEBUG(printf("Configuration::~Configuration()\n"));
  471.  
  472.     // Kill allocated stuff.
  473.     if (NULL != base_p)
  474.         delete base_p;
  475.  
  476.     if (NULL != myName_p)
  477.         delete myName_p;
  478.  
  479.     if (NULL != temppath_p)
  480.         delete temppath_p;
  481.  
  482.     if (NULL != decompresscmd_p)
  483.         delete decompresscmd_p;
  484.  
  485.     if (NULL != compresscmd_p)
  486.         delete compresscmd_p;
  487.  
  488.     if (NULL != bwpath_p)
  489.         delete bwpath_p;
  490.  
  491.     if (NULL != myAddress_pp) {
  492.         for (unsigned i = 0; i < numuplinks; i ++)
  493.             if (NULL != myAddress_pp[i])
  494.                 delete myAddress_pp[i];
  495.         delete myAddress_pp;
  496.     }
  497.  
  498.     if (NULL != uplink_pp) {
  499.         for (unsigned i = 0; i < numuplinks; i ++)
  500.             if (NULL != uplink_pp[i])
  501.                 delete uplink_pp[i];
  502.         delete uplink_pp;
  503.     }
  504.  
  505.     // Kill the area list
  506.     if (NULL != arealist_pp) {
  507.         for (unsigned i = 0; i < numareas; i ++)
  508.             if (NULL != arealist_pp[i])
  509.                 delete arealist_pp[i];
  510.         delete arealist_pp;
  511.     }
  512.  
  513.     // Kill the uplink list
  514.     if (NULL != uplinklist_pp) {
  515.         for (unsigned i = 0; i < numuplinks; i ++)
  516.             if (NULL != uplinklist_pp[i])
  517.                 delete uplinklist_pp[i];
  518.         delete uplinklist_pp;
  519.     }
  520. }
  521.  
  522. // method: uplinkNumber
  523. // Find a uplink number in the configuration that matches the address given.
  524. int Configuration::uplinkNumber(FidoAddress &findMe)
  525. {
  526.     doDEBUG(printf("Configuration::uplinkNumber(%u:%u/%u.%u) => ",
  527.             findMe.zone, findMe.net, findMe.node, findMe.point));
  528.  
  529.     // Search the list, looking at both the uplink and own addresses.
  530.     for (unsigned i = 0; i < numuplinks; i ++)
  531.         if (findMe == *uplink_pp[i] || findMe == *myAddress_pp[i]) {
  532.             doDEBUG(printf("%d\n", i));
  533.             return i; // match!
  534.     }
  535.  
  536.     doDEBUG(puts("Missing!"));
  537.     return -1;  // No match.
  538. }
  539.  
  540. // method: command
  541. // Creates a [de]compression command line.
  542. char *Configuration::command(char *format, char *str1, char *str2)
  543. {
  544.     doDEBUG(printf("Configuration::command(\"%s\", \"%s\", \"%s\")\n",
  545.                    format, str1, str2));
  546.     static char cmdline[256];
  547.  
  548.     // If we don't have a template to build on, then don't try.
  549.     if (NULL == format)
  550.         return NULL;
  551.  
  552.     // Create the command line, and return it to the caller.
  553.     sprintf(cmdline, format, str1, str2);
  554.     return cmdline;
  555. }
  556.  
  557. // method: tempName
  558. // Create a temporary file name in the defined temporary directory.
  559. char *Configuration::tempName(char *tempFileName)
  560. {
  561.     doDEBUG(printf("Configuration::tempName(\"%s\")\n", tempFileName));
  562.     static char tempname[256];
  563.  
  564.     // Copy over the temporary path.
  565.     strcpy(tempname, temppath_p);
  566.  
  567.     // Add a trailing backslash if there is none.
  568.     if ('\\' != tempname[strlen(tempname) - 1])
  569.         strcat(tempname, "\\");
  570.  
  571.     // Add the file name as specified.
  572.     if (tempFileName)
  573.         strcat(tempname, tempFileName);
  574.  
  575.     // And return the result.
  576.     return tempname;
  577. }
  578.  
  579. // method: bwName
  580. // Create a Blue Wave packet name, based on the number given.
  581. char *Configuration::bwName(int number)
  582. {
  583.     doDEBUG(printf("Configuration::bwName(%d)\n", number));
  584.  
  585.     // Since we are dealing with three-number extensions here, make sure
  586.     // the number isn't bigger than 999, or less than zero.
  587.     if (number > 999)
  588.         number = 999;
  589.  
  590.     if (number < 0)
  591.         number = 0;
  592.  
  593.     // Move it to a string.
  594.     char ext[4];
  595.     sprintf(ext, "%03d", number);
  596.  
  597.     // Call the "extension in string" version.
  598.     return bwName(ext);
  599. }
  600.  
  601. // method: bwName
  602. // Create a Blue Wave packet name, based on the extension string given.
  603. char *Configuration::bwName(char *ext_p)
  604. {
  605.     doDEBUG(printf("Configuration::bwName(\"%s\")\n", ext_p));
  606.     static char bwname[256];
  607.  
  608.     // If we don't have a base name, don't try to create a BW name.
  609.     if (NULL == base_p)
  610.         return NULL;
  611.  
  612.     // 'slash' will point either to a backslash or nothing at all.
  613.     char *slash = "\\";
  614.     if ('\\' == bwpath_p[strlen(bwpath_p) - 1])
  615.         slash ++;
  616.  
  617.     // Create the name and return it.
  618.     sprintf(bwname, "%s%s%s.%s", bwpath_p, slash, base_p, ext_p);
  619.     return bwname;
  620. }
  621.  
  622. // split3
  623. // Split a string into three pieces at the comma signs.
  624. void split3(charP start_p, charP &pt2_p, charP &pt3_p)
  625. {
  626.     doDEBUG(printf("\nsplit3(\"%s\", charP &, charP &) => ", start_p));
  627.  
  628.     if (NULL != (pt2_p = strchr(start_p, ','))) {
  629.         *pt2_p = 0;
  630.         pt2_p ++;
  631.         if (NULL != (pt3_p = strchr(pt2_p, ','))) {
  632.             *pt3_p = 0;
  633.             pt3_p ++;
  634.             doDEBUG(printf("\"%s\" - \"%s\" - \"%s\"\n", start_p, pt2_p,
  635.                     pt3_p));
  636.         }
  637.     }
  638.     else
  639.         pt3_p = NULL;
  640. }
  641.  
  642. // split2
  643. // Split a string into two pieces at the comma signs.
  644. void split2(charP start_p, charP &pt2_p)
  645. {
  646.     doDEBUG(printf("\nsplit2(\"%s\", charP &) => ", start_p));
  647.  
  648.     if (NULL != (pt2_p = strchr(start_p, ','))) {
  649.         *pt2_p = 0;
  650.         pt2_p ++;
  651.         doDEBUG(printf("\"%s\" - \"%s\"\n", start_p, pt2_p));
  652.     }
  653. }
  654.  
  655. // checkCommandString
  656. // Check that a [de]compression command specification has the correct amount
  657. // of parameters.
  658. int checkCommandString(char *cmdstring)
  659. {
  660.     char *tmp;
  661.  
  662.     if (NULL != (tmp = strchr(cmdstring, '%'))) {
  663.         tmp ++;
  664.         if ('s' == *tmp) { // First token was a %s
  665.             if (NULL != (tmp = strchr(tmp, '%'))) {
  666.                 tmp ++;
  667.                 if ('s' == *tmp) { // Second token was a %s
  668.                     tmp ++;
  669.                     if (NULL == strchr(tmp, '%'))
  670.                         return 1; // No more % signs -> it is ok!
  671.                 }
  672.             }
  673.         }
  674.     }
  675.  
  676.     // If we fall out of any of the ifs, the command string is not ok.
  677.     return 0;
  678. }
  679.