home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / unzip52.zip / human68k / human68k.c < prev    next >
C/C++ Source or Header  |  1996-04-20  |  23KB  |  713 lines

  1. /*---------------------------------------------------------------------------
  2.  
  3.   human68k.c
  4.  
  5.   Human68K-specific routines for use with Info-ZIP's UnZip 5.1 and later.
  6.  
  7.   Contains:  do_wild()
  8.              mapattr()
  9.              mapname()
  10.              checkdir()
  11.              close_outfile()
  12.              version()
  13.              TwentyOne()
  14.              normalize_name()
  15.  
  16.   ---------------------------------------------------------------------------*/
  17.  
  18.  
  19. #include <dirent.h>
  20. #include <sys/dos.h>
  21. #include <sys/xunistd.h>
  22. #include <jstring.h>
  23. #define UNZIP_INTERNAL
  24. #include "unzip.h"
  25.  
  26.  
  27. static void normalize_name(char *);
  28.  
  29. static int created_dir;        /* used in mapname(), checkdir() */
  30. static int renamed_fullpath;   /* ditto */
  31.  
  32. #ifndef SFX
  33.  
  34. /**********************/
  35. /* Function do_wild() */
  36. /**********************/
  37.  
  38. char *do_wild(__G__ wildspec)
  39.     __GDEF
  40.     char *wildspec;         /* only used first time on a given dir */
  41. {
  42.     static DIR *dir = NULL;
  43.     static char *dirname, *wildname, matchname[FILNAMSIZ];
  44.     static int firstcall=TRUE, have_dirname, dirnamelen;
  45.     struct dirent *file;
  46.  
  47.  
  48.     /* Even when we're just returning wildspec, we *always* do so in
  49.      * matchname[]--calling routine is allowed to append four characters
  50.      * to the returned string, and wildspec may be a pointer to argv[].
  51.      */
  52.     if (firstcall) {        /* first call:  must initialize everything */
  53.         firstcall = FALSE;
  54.  
  55.         /* break the wildspec into a directory part and a wildcard filename */
  56.         if ((wildname = strrchr(wildspec, '/')) == NULL) {
  57.             dirname = ".";
  58.             dirnamelen = 1;
  59.             have_dirname = FALSE;
  60.             wildname = wildspec;
  61.         } else {
  62.             ++wildname;     /* point at character after '/' */
  63.             dirnamelen = wildname - wildspec;
  64.             if ((dirname = (char *)malloc(dirnamelen+1)) == NULL) {
  65.                 Info(slide, 1, ((char *)slide,
  66.                   "warning:  can't allocate wildcard buffers\n"));
  67.                 strcpy(matchname, wildspec);
  68.                 return matchname;   /* but maybe filespec was not a wildcard */
  69.             }
  70.             strncpy(dirname, wildspec, dirnamelen);
  71.             dirname[dirnamelen] = '\0';   /* terminate for strcpy below */
  72.             have_dirname = TRUE;
  73.         }
  74.  
  75.         if ((dir = opendir(dirname)) != NULL) {
  76.             while ((file = readdir(dir)) != NULL) {
  77.                 if (file->d_name[0] == '.' && wildname[0] != '.')
  78.                     continue;  /* Unix:  '*' and '?' do not match leading dot */
  79.                 if (match(file->d_name, wildname, 0)) {  /* 0 == case sens. */
  80.                     if (have_dirname) {
  81.                         strcpy(matchname, dirname);
  82.                         strcpy(matchname+dirnamelen, file->d_name);
  83.                     } else
  84.                         strcpy(matchname, file->d_name);
  85.                     return matchname;
  86.                 }
  87.             }
  88.             /* if we get to here directory is exhausted, so close it */
  89.             closedir(dir);
  90.             dir = NULL;
  91.         }
  92.  
  93.         /* return the raw wildspec in case that works (e.g., directory not
  94.          * searchable, but filespec was not wild and file is readable) */
  95.         strcpy(matchname, wildspec);
  96.         return matchname;
  97.     }
  98.  
  99.     /* last time through, might have failed opendir but returned raw wildspec */
  100.     if (dir == NULL) {
  101.         firstcall = TRUE;  /* nothing left to try--reset for new wildspec */
  102.         if (have_dirname)
  103.             free(dirname);
  104.         return (char *)NULL;
  105.     }
  106.  
  107.     /* If we've gotten this far, we've read and matched at least one entry
  108.      * successfully (in a previous call), so dirname has been copied into
  109.      * matchname already.
  110.      */
  111.     while ((file = readdir(dir)) != NULL)
  112.         if (match(file->d_name, wildname, 0)) {   /* 0 == don't ignore case */
  113.             if (have_dirname) {
  114.                 /* strcpy(matchname, dirname); */
  115.                 strcpy(matchname+dirnamelen, file->d_name);
  116.             } else
  117.                 strcpy(matchname, file->d_name);
  118.             return matchname;
  119.         }
  120.  
  121.     closedir(dir);     /* have read at least one dir entry; nothing left */
  122.     dir = NULL;
  123.     firstcall = TRUE;  /* reset for new wildspec */
  124.     if (have_dirname)
  125.         free(dirname);
  126.     return (char *)NULL;
  127.  
  128. } /* end function do_wild() */
  129.  
  130. #endif /* !SFX */
  131.  
  132.  
  133.  
  134.  
  135. /**********************/
  136. /* Function mapattr() */
  137. /**********************/
  138.  
  139. int mapattr(__G)
  140.     __GDEF
  141. {
  142.     ulg  tmp = G.crec.external_file_attributes;
  143.  
  144.     if (G.pInfo->hostnum == UNIX_ || G.pInfo->hostnum == VMS_)
  145.     G.pInfo->file_attr = _mode2dos(tmp >> 16);
  146.     else
  147.     /* set archive bit (file is not backed up): */
  148.     G.pInfo->file_attr = (unsigned)(G.crec.external_file_attributes|32) &
  149.           0xff;
  150.     return 0;
  151.  
  152. } /* end function mapattr() */
  153.  
  154.  
  155.  
  156.  
  157.  
  158. /**********************/
  159. /* Function mapname() */
  160. /**********************/
  161.  
  162. int mapname(__G__ renamed)   /* return 0 if no error, 1 if caution (filename */
  163.     __GDEF                   /* trunc), 2 if warning (skip file because dir */
  164.     int renamed;             /* doesn't exist), 3 if error (skip file), 10 */
  165. {                            /* if no memory (skip file) */
  166.     char pathcomp[FILNAMSIZ];    /* path-component buffer */
  167.     char *pp, *cp=(char *)NULL;  /* character pointers */
  168.     char *lastsemi=(char *)NULL; /* pointer to last semi-colon in pathcomp */
  169.     int quote = FALSE;           /* flags */
  170.     int error = 0;
  171.     register unsigned workch;    /* hold the character being tested */
  172.  
  173.  
  174. /*---------------------------------------------------------------------------
  175.     Initialize various pointers and counters and stuff.
  176.   ---------------------------------------------------------------------------*/
  177.  
  178.     if (G.pInfo->vollabel)
  179.         return IZ_VOL_LABEL;    /* can't set disk volume labels in Unix */
  180.  
  181.     /* can create path as long as not just freshening, or if user told us */
  182.     G.create_dirs = (!G.fflag || renamed);
  183.  
  184.     created_dir = FALSE;        /* not yet */
  185.  
  186.     /* user gave full pathname:  don't prepend rootpath */
  187.     renamed_fullpath = (renamed && (*filename == '/'));
  188.  
  189.     if (checkdir(__G__ (char *)NULL, INIT) == 10)
  190.         return 10;              /* initialize path buffer, unless no memory */
  191.  
  192.     *pathcomp = '\0';           /* initialize translation buffer */
  193.     pp = pathcomp;              /* point to translation buffer */
  194.     if (G.jflag)                /* junking directories */
  195.         cp = (char *)strrchr(G.filename, '/');
  196.     if (cp == NULL)             /* no '/' or not junking dirs */
  197.         cp = G.filename;        /* point to internal zipfile-member pathname */
  198.     else
  199.         ++cp;                   /* point to start of last component of path */
  200.  
  201. /*---------------------------------------------------------------------------
  202.     Begin main loop through characters in filename.
  203.   ---------------------------------------------------------------------------*/
  204.  
  205.     while ((workch = (uch)*cp++) != 0) {
  206.     if (iskanji(workch)) {
  207.         *pp++ = (char)workch;
  208.         quote = TRUE;
  209.     } else if (quote) {                 /* if character quoted, */
  210.             *pp++ = (char)workch;    /*  include it literally */
  211.             quote = FALSE;
  212.         } else
  213.             switch (workch) {
  214.             case '/':             /* can assume -j flag not given */
  215.                 *pp = '\0';
  216.                 if ((error = checkdir(__G__ pathcomp, APPEND_DIR)) > 1)
  217.                     return error;
  218.                 pp = pathcomp;    /* reset conversion buffer for next piece */
  219.                 lastsemi = NULL;  /* leave directory semi-colons alone */
  220.                 break;
  221.  
  222.             case ';':             /* VMS version (or DEC-20 attrib?) */
  223.                 lastsemi = pp;         /* keep for now; remove VMS ";##" */
  224.                 *pp++ = (char)workch;  /*  later, if requested */
  225.                 break;
  226.  
  227.             case '\026':          /* control-V quote for special chars */
  228.                 quote = TRUE;     /* set flag for next character */
  229.                 break;
  230.  
  231.             case ' ':             /* change spaces to underscore under */
  232.                 *pp++ = '_';      /*  MTS; leave as spaces under Unix */
  233.                 break;
  234.  
  235.             default:
  236.                 /* allow European characters in filenames: */
  237.                 if (isprint(workch) || (128 <= workch && workch <= 254))
  238.                     *pp++ = (char)workch;
  239.             } /* end switch */
  240.  
  241.     } /* end while loop */
  242.  
  243.     *pp = '\0';                   /* done with pathcomp:  terminate it */
  244.  
  245.     /* if not saving them, remove VMS version numbers (appended ";###") */
  246.     if (!G.V_flag && lastsemi) {
  247.         pp = lastsemi + 1;
  248.         while (isdigit((uch)(*pp)))
  249.             ++pp;
  250.         if (*pp == '\0')          /* only digits between ';' and end:  nuke */
  251.             *lastsemi = '\0';
  252.     }
  253.  
  254. /*---------------------------------------------------------------------------
  255.     Report if directory was created (and no file to create:  filename ended
  256.     in '/'), check name to be sure it exists, and combine path and name be-
  257.     fore exiting.
  258.   ---------------------------------------------------------------------------*/
  259.  
  260.     if (G.filename[strlen(G.filename) - 1] == '/') {
  261.         checkdir(__G__ G.filename, GETPATH);
  262.         if (created_dir && QCOND2) {
  263.             Info(slide, 0, ((char *)slide, "   creating: %s\n",
  264.               G.filename));
  265.             return IZ_CREATED_DIR;   /* set dir time (note trailing '/') */
  266.         }
  267.         return 2;   /* dir existed already; don't look for data to extract */
  268.     }
  269.  
  270.     if (*pathcomp == '\0') {
  271.         Info(slide, 1, ((char *)slide, "mapname:  conversion of %s failed\n",
  272.           G.filename));
  273.         return 3;
  274.     }
  275.  
  276.     checkdir(__G__ pathcomp, APPEND_NAME);   /* returns 1 if truncated:  care? */
  277.     checkdir(__G__ G.filename, GETPATH);
  278.  
  279.     return error;
  280.  
  281. } /* end function mapname() */
  282.  
  283.  
  284.  
  285.  
  286.  
  287. /***********************/
  288. /* Function checkdir() */
  289. /***********************/
  290.  
  291. int checkdir(__G__ pathcomp, flag)
  292.     __GDEF
  293.     char *pathcomp;
  294.     int flag;
  295. /*
  296.  * returns:  1 - (on APPEND_NAME) truncated filename
  297.  *           2 - path doesn't exist, not allowed to create
  298.  *           3 - path doesn't exist, tried to create and failed; or
  299.  *               path exists and is not a directory, but is supposed to be
  300.  *           4 - path is too long
  301.  *          10 - can't allocate memory for filename buffers
  302.  */
  303. {
  304.     static int rootlen = 0;   /* length of rootpath */
  305.     static char *rootpath;    /* user's "extract-to" directory */
  306.     static char *buildpath;   /* full path (so far) to extracted file */
  307.     static char *end;         /* pointer to end of buildpath ('\0') */
  308.  
  309. #   define FN_MASK   7
  310. #   define FUNCTION  (flag & FN_MASK)
  311.  
  312.  
  313.  
  314. /*---------------------------------------------------------------------------
  315.     APPEND_DIR:  append the path component to the path being built and check
  316.     for its existence.  If doesn't exist and we are creating directories, do
  317.     so for this one; else signal success or error as appropriate.
  318.   ---------------------------------------------------------------------------*/
  319.  
  320.     if (FUNCTION == APPEND_DIR) {
  321.         int too_long = FALSE;
  322.         char *old_end = end;
  323.  
  324.         Trace((stderr, "appending dir segment [%s]\n", pathcomp));
  325.         while ((*end = *pathcomp++) != '\0')
  326.             ++end;
  327.     normalize_name(old_end);
  328.  
  329.         /* GRR:  could do better check, see if overrunning buffer as we go:
  330.          * check end-buildpath after each append, set warning variable if
  331.          * within 20 of FILNAMSIZ; then if var set, do careful check when
  332.          * appending.  Clear variable when begin new path. */
  333.  
  334.         if ((end-buildpath) > FILNAMSIZ-3)  /* need '/', one-char name, '\0' */
  335.             too_long = TRUE;                /* check if extracting directory? */
  336.         if (stat(buildpath, &G.statbuf))    /* path doesn't exist */
  337.         {
  338.             if (!G.create_dirs) { /* told not to create (freshening) */
  339.                 free(buildpath);
  340.                 return 2;         /* path doesn't exist:  nothing to do */
  341.             }
  342.             if (too_long) {
  343.                 Info(slide, 1, ((char *)slide,
  344.                   "checkdir error:  path too long: %s\n",
  345.                   buildpath));
  346.                 free(buildpath);
  347.                 return 4;         /* no room for filenames:  fatal */
  348.             }
  349.             if (MKDIR(buildpath, 0666) == -1) {   /* create the directory */
  350.                 Info(slide, 1, ((char *)slide,
  351.                   "checkdir error:  can't create %s\n\
  352.                  unable to process %s.\n",
  353.                   buildpath, G.filename));
  354.                 free(buildpath);
  355.                 return 3;      /* path didn't exist, tried to create, failed */
  356.             }
  357.             created_dir = TRUE;
  358.         } else if (!S_ISDIR(G.statbuf.st_mode)) {
  359.             Info(slide, 1, ((char *)slide,
  360.               "checkdir error:  %s exists but is not directory\n\
  361.                  unable to process %s.\n",
  362.               buildpath, G.filename));
  363.             free(buildpath);
  364.             return 3;          /* path existed but wasn't dir */
  365.         }
  366.         if (too_long) {
  367.             Info(slide, 1, ((char *)slide,
  368.               "checkdir error:  path too long: %s\n",
  369.               buildpath));
  370.             free(buildpath);
  371.             return 4;         /* no room for filenames:  fatal */
  372.         }
  373.         *end++ = '/';
  374.         *end = '\0';
  375.         Trace((stderr, "buildpath now = [%s]\n", buildpath));
  376.         return 0;
  377.  
  378.     } /* end if (FUNCTION == APPEND_DIR) */
  379.  
  380. /*---------------------------------------------------------------------------
  381.     GETPATH:  copy full path to the string pointed at by pathcomp, and free
  382.     buildpath.
  383.   ---------------------------------------------------------------------------*/
  384.  
  385.     if (FUNCTION == GETPATH) {
  386.         strcpy(pathcomp, buildpath);
  387.         Trace((stderr, "getting and freeing path [%s]\n", pathcomp));
  388.         free(buildpath);
  389.         buildpath = end = (char *)NULL;
  390.         return 0;
  391.     }
  392.  
  393. /*---------------------------------------------------------------------------
  394.     APPEND_NAME:  assume the path component is the filename; append it and
  395.     return without checking for existence.
  396.   ---------------------------------------------------------------------------*/
  397.  
  398.     if (FUNCTION == APPEND_NAME) {
  399.         char *old_end = end;
  400.  
  401.         Trace((stderr, "appending filename [%s]\n", pathcomp));
  402.         while ((*end = *pathcomp++) != '\0') {
  403.             ++end;
  404.             normalize_name(old_end);
  405.             if ((end-buildpath) >= FILNAMSIZ) {
  406.                 *--end = '\0';
  407.                 Info(slide, 1, ((char *)slide,
  408.                   "checkdir warning:  path too long; truncating\n\
  409.                    %s\n                -> %s\n",
  410.                   G.filename, buildpath));
  411.                 return 1;   /* filename truncated */
  412.             }
  413.         }
  414.         Trace((stderr, "buildpath now = [%s]\n", buildpath));
  415.         return 0;  /* could check for existence here, prompt for new name... */
  416.     }
  417.  
  418. /*---------------------------------------------------------------------------
  419.     INIT:  allocate and initialize buffer space for the file currently being
  420.     extracted.  If file was renamed with an absolute path, don't prepend the
  421.     extract-to path.
  422.   ---------------------------------------------------------------------------*/
  423.  
  424. /* GRR:  for VMS and TOPS-20, add up to 13 to strlen */
  425.  
  426.     if (FUNCTION == INIT) {
  427.         Trace((stderr, "initializing buildpath to "));
  428.         if ((buildpath = (char *)malloc(strlen(G.filename)+rootlen+1)) ==
  429.             (char *)NULL)
  430.             return 10;
  431.         if ((rootlen > 0) && !renamed_fullpath) {
  432.             strcpy(buildpath, rootpath);
  433.             end = buildpath + rootlen;
  434.         } else {
  435.             *buildpath = '\0';
  436.             end = buildpath;
  437.         }
  438.         Trace((stderr, "[%s]\n", buildpath));
  439.         return 0;
  440.     }
  441.  
  442. /*---------------------------------------------------------------------------
  443.     ROOT:  if appropriate, store the path in rootpath and create it if neces-
  444.     sary; else assume it's a zipfile member and return.  This path segment
  445.     gets used in extracting all members from every zipfile specified on the
  446.     command line.
  447.   ---------------------------------------------------------------------------*/
  448.  
  449. #if (!defined(SFX) || defined(SFX_EXDIR))
  450.     if (FUNCTION == ROOT) {
  451.         Trace((stderr, "initializing root path to [%s]\n", pathcomp));
  452.         if (pathcomp == (char *)NULL) {
  453.             rootlen = 0;
  454.             return 0;
  455.         }
  456.         if ((rootlen = strlen(pathcomp)) > 0) {
  457.             int had_trailing_pathsep=FALSE;
  458.  
  459.             if (pathcomp[rootlen-1] == '/') {
  460.                 pathcomp[--rootlen] = '\0';
  461.                 had_trailing_pathsep = TRUE;
  462.             }
  463.             if (rootlen > 0 && (SSTAT(pathcomp, &G.statbuf) ||
  464.                 !S_ISDIR(G.statbuf.st_mode)))          /* path does not exist */
  465.             {
  466.                 if (!G.create_dirs /* || iswild(pathcomp) */ ) {
  467.                     rootlen = 0;
  468.                     return 2;   /* skip (or treat as stored file) */
  469.                 }
  470.                 /* create the directory (could add loop here to scan pathcomp
  471.                  * and create more than one level, but why really necessary?) */
  472.                 if (MKDIR(pathcomp, 0777) == -1) {
  473.                     Info(slide, 1, ((char *)slide,
  474.                       "checkdir:  can't create extraction directory: %s\n",
  475.                       pathcomp));
  476.                     rootlen = 0;   /* path didn't exist, tried to create, and */
  477.                     return 3;  /* failed:  file exists, or 2+ levels required */
  478.                 }
  479.             }
  480.             if ((rootpath = (char *)malloc(rootlen+2)) == NULL) {
  481.                 rootlen = 0;
  482.                 return 10;
  483.             }
  484.             strcpy(rootpath, pathcomp);
  485.             rootpath[rootlen++] = '/';
  486.             rootpath[rootlen] = '\0';
  487.             Trace((stderr, "rootpath now = [%s]\n", rootpath));
  488.         }
  489.         return 0;
  490.     }
  491. #endif /* !SFX || SFX_EXDIR */
  492.  
  493. /*---------------------------------------------------------------------------
  494.     END:  free rootpath, immediately prior to program exit.
  495.   ---------------------------------------------------------------------------*/
  496.  
  497.     if (FUNCTION == END) {
  498.         Trace((stderr, "freeing rootpath\n"));
  499.         if (rootlen > 0)
  500.             free(rootpath);
  501.         return 0;
  502.     }
  503.  
  504.     return 99;  /* should never reach */
  505.  
  506. } /* end function checkdir() */
  507.  
  508.  
  509.  
  510.  
  511.  
  512. /****************************/
  513. /* Function close_outfile() */
  514. /****************************/
  515.  
  516. void close_outfile(__G)
  517.     __GDEF
  518. {
  519. #ifdef USE_EF_UX_TIME
  520.     ztimbuf z_utime;
  521.  
  522.     /* The following DOS date/time structure is machine dependent as it
  523.      * assumes "little endian" byte order. For MSDOS specific code, which
  524.      * is run on ix86 CPUs (or emulators), this assumption is valid; but
  525.      * care should be taken when using this code as template for other ports.
  526.      */
  527.     union {
  528.         ulg z_dostime;
  529.         struct {                /* date and time words */
  530.             union {             /* DOS file modification time word */
  531.                 ush ztime;
  532.                 struct {
  533.                     unsigned zt_se : 5;
  534.                     unsigned zt_mi : 6;
  535.                     unsigned zt_hr : 5;
  536.                 } _tf;
  537.             } _t;
  538.             union {             /* DOS file modification date word */
  539.                 ush zdate;
  540.                 struct {
  541.                     unsigned zd_dy : 5;
  542.                     unsigned zd_mo : 4;
  543.                     unsigned zd_yr : 7;
  544.                 } _df;
  545.             } _d;
  546.         } zt;
  547.     } dos_dt;
  548. #endif /* USE_EF_UX_TIME */
  549.  
  550.     if (G.cflag) {
  551.     fclose(G.outfile);
  552.         return;
  553.     }
  554.  
  555. #ifdef USE_EF_UX_TIME
  556.     if (G.extra_field &&
  557.         ef_scan_for_izux(G.extra_field, G.lrec.extra_field_length,
  558.                          &z_utime, NULL) > 0) {
  559.         struct tm *t;
  560.  
  561.         TTrace((stderr, "close_outfile:  Unix e.f. modif. time = %ld\n",
  562.           z_utime.modtime));
  563.         /* round up to even seconds */
  564.         z_utime.modtime = (z_utime.modtime + 1) & (~1);
  565.         t = localtime(&(z_utime.modtime));
  566.         if (t->tm_year < 80) {
  567.             dos_dt.zt._t._tf.zt_se = 0;
  568.             dos_dt.zt._t._tf.zt_mi = 0;
  569.             dos_dt.zt._t._tf.zt_hr = 0;
  570.             dos_dt.zt._d._df.zd_dy = 1;
  571.             dos_dt.zt._d._df.zd_mo = 1;
  572.             dos_dt.zt._d._df.zd_yr = 0;
  573.         } else {
  574.             dos_dt.zt._t._tf.zt_se = t->tm_sec >> 1;
  575.             dos_dt.zt._t._tf.zt_mi = t->tm_min;
  576.             dos_dt.zt._t._tf.zt_hr = t->tm_hour;
  577.             dos_dt.zt._d._df.zd_dy = t->tm_mday;
  578.             dos_dt.zt._d._df.zd_mo = t->tm_mon + 1;
  579.             dos_dt.zt._d._df.zd_yr = t->tm_year - 80;
  580.         }
  581.     } else {
  582.         dos_dt.zt._t.ztime = G.lrec.last_mod_file_time;
  583.         dos_dt.zt._d.zdate = G.lrec.last_mod_file_date;
  584.     }
  585.     _dos_filedate(fileno(G.outfile), dos_dt.z_dostime);
  586. #else /* !USE_EF_UX_TIME */
  587.     _dos_filedate(fileno(G.outfile),
  588.       (ulg)G.lrec.last_mod_file_date << 16 | G.lrec.last_mod_file_time);
  589. #endif /* ?USE_EF_UX_TIME */
  590.  
  591.     fclose(G.outfile);
  592.  
  593.     _dos_chmod(G.filename, G.pInfo->file_attr);
  594.  
  595. } /* end function close_outfile() */
  596.  
  597.  
  598.  
  599.  
  600. #ifndef SFX
  601.  
  602. /************************/
  603. /*  Function version()  */
  604. /************************/
  605.  
  606. void version(__G)
  607.     __GDEF
  608. {
  609.     int len;
  610. #if 0
  611.     char buf[40];
  612. #endif
  613.  
  614.     len = sprintf((char *)slide, LoadFarString(CompiledWith),
  615.  
  616. #ifdef __GNUC__
  617.       "gcc ", __VERSION__,
  618. #else
  619. #  if 0
  620.       "cc ", (sprintf(buf, " version %d", _RELEASE), buf),
  621. #  else
  622.       "unknown compiler", "",
  623. #  endif
  624. #endif
  625.  
  626.       "Human68k", " (X68000)",
  627.  
  628. #ifdef __DATE__
  629.       " on ", __DATE__
  630. #else
  631.       "", ""
  632. #endif
  633.       );
  634.  
  635.     (*G.message)((zvoid *)&G, slide, (ulg)len, 0);
  636.  
  637. } /* end function version() */
  638.  
  639. #endif /* !SFX */
  640.  
  641.  
  642.  
  643.  
  644.  
  645. /* Human68K-specific routines */
  646.  
  647. #define VALID_CHAR "&#()@_^{}!"
  648.  
  649. extern ulg TwentyOneOptions(void);
  650.  
  651. static int multi_period = 0;
  652. static int special_char = 0;
  653.  
  654. void
  655. InitTwentyOne(void)
  656. {
  657.     ulg stat;
  658.  
  659.     stat = TwentyOneOptions();
  660.     if (stat == 0 || stat == (unsigned long) -1) {
  661.     special_char = 0;
  662.     multi_period = 0;
  663.     return;
  664.     }
  665.     if (stat & (1UL << 29))
  666.     special_char = 1;
  667.     if (stat & (1UL << 28))
  668.     multi_period = 1;
  669. }
  670.  
  671. static void
  672. normalize_name(char *name)
  673. {
  674.     char *dot;
  675.     char *p;
  676.  
  677.     if (strlen(name) > 18) {    /* too long */
  678.     char base[18 + 1];
  679.     char ext[4 + 1];
  680.  
  681.     if ((dot = jstrrchr(name, '.')) != NULL)
  682.         *dot = '\0';
  683.     strncpy(base, name, 18);
  684.     base[18] = '\0';
  685.     if (dot) {
  686.         *dot = '.';
  687.         strncpy(ext, dot, 4);
  688.         ext[4] = '\0';
  689.     } else
  690.         *ext = '\0';
  691.     strcpy(name, base);
  692.     strcat(name, ext);
  693.     }
  694.     dot = NULL;
  695.     for (p = name; *p; p++) {
  696.     if (iskanji((unsigned char)*p) && p[1] != '\0')
  697.         p++;
  698.     else if (*p == '.') {
  699.         if (!multi_period) {
  700.         dot = p;
  701.         *p = '_';
  702.         }
  703.     } else if (!special_char && !isalnum (*p)
  704.            && strchr(VALID_CHAR, *p) == NULL)
  705.         *p = '_';
  706.     }
  707.     if (dot != NULL) {
  708.     *dot = '.';
  709.     if (strlen(dot) > 4)
  710.         dot[4] = '\0';
  711.     }
  712. }
  713.