human68k.c
上传用户:andy_li
上传日期:2007-01-06
资源大小:1019k
文件大小:27k
源码类别:

压缩解压

开发平台:

MultiPlatform

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