home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / shar349.zip / src / shar.c < prev    next >
C/C++ Source or Header  |  1992-02-22  |  44KB  |  1,561 lines

  1. char *revision = "3.49";
  2. char RCS_ID[] = "$Header: /u/rhg/src/shar/shar.c,v 3.49 90/09/12 15:14:41 rhg Exp $";
  3. /*
  4. ** shar.c
  5.  
  6.   Defined functions:
  7.     gen_mkdir(path)
  8.     gen_mkdir_script(path)
  9.     setTOUCH()
  10.     walktree(rtn,rootname)
  11.     header(argc,argv)
  12.     helpuser()
  13.     main(argc,argv)
  14.     mode_map(mode,mode_str)
  15.     shar(file,RstrName)
  16.  
  17. */
  18. /*+:EDITS:*/
  19. /*:09-12-1990-14:24-rhg@cps.com-added missing return(0) to walkdown */
  20. /*:09-12-1990-14:13-rhg@cps.com-deleted some redundant, unused, code */
  21. /*:09-12-1990-00:28-rhg@cps.com-added more directions to the shar header */
  22. /*:09-09-1990-20:12-rhg@cps.com-added CLOSEDIR_VOID */
  23. /*:09-09-1990-18:42-rhg@cps.com-added check for "From" under OptPREFIX */
  24. /*:09-09-1990-11:55-rhg@cps.com-modified code under NOT STR(N)CMP_IS_FAST */
  25. /*:09-08-1990-21:20-rhg@cps.com-added NO_DIRENT for SunOS 3 sys/dir.h */
  26. /*:09-08-1990-21:04-rhg@cps.com-fixed bug in PREFIX check: strcmp(line,Delim) */
  27. /*:08-06-1990-00:40-rhg@cps.com-revised Cut message to be more explanatory */
  28. /*:08-05-1990-14:04-rhg@cps.com-merged Rname into walktree */
  29. /*:08-05-1990-12:11-rhg@cps.com-added walktree & support for sharing dirs */
  30. /*:08-05-1990-09:05-rhg@cps.com-change -Bn, -t, and -b to -bn, -T, and -B */
  31. /*:08-04-1990-15:31-rhg@cps.com-added -Bn to set compress -bn (default 12) */
  32. /*:08-04-1990-15:31-rhg@cps.com-changed shar3_???_.tmp to _shar_???_.tmp */
  33. /*:08-04-1990-15:22-rhg@cps.com-added check for "exit 0" under OptPREFIX */
  34. /*:08-04-1990-14:32-rhg@cps.com-added -m to generate TOUCH (default off) */
  35. /*:08-04-1990-14:18-rhg@cps.com-reversed the meaning of -x and deleted -O */
  36. /*:06-14-1990-14:48-rhg@cps.com-made Split and eXists compatible.
  37. /*:06-14-1990-14:18-rhg@cps.com-made -x the default and added -O
  38. /*:06-14-1990-12:44-rhg@cps.com-always terminate the && and report failures
  39. /*:06-14-1990-12:28-rhg@cps.com-clear mkdir_already between -l files
  40. /*:06-14-1990-12:14-rhg@cps.com-change PREFIX from a #define to an int variable.
  41. /*:04-19-1990-22:49-rhg@cps.com-get rid of "set" so "sh sharfil -c" will work */
  42. /*:04-19-1990-21:52-rhg@cps.com-add -F to clear OptPREFIX */
  43. /*:04-18-1990-08:49-rhg@cps.com-add OptPREFIX (for now, always on) */
  44. /*:07-09-1990-19:24-wht@n4hgf-back to fgrep amc -- fits more -m touches */
  45. /*:07-01-1990-18:37-wht@n4hgf-wait() needed after fork() */
  46. /*:05-19-1990-02:47-wht@n4hgf-change fgrep amc to mmdd */
  47. /*:05-16-1990-01:53-wht@n4hgf-Archive-name had extra period sometimes */
  48. /*:05-10-1990-20:39-wht@n4hgf-altos does not not like at-sign in filenames */
  49. /*:05-10-1990-13:38-wht@n4hgf-add -V Vanilla mode */
  50. /*:05-07-1990-00:06-wht@n4hgf-test all mallocs for Purity Of Essence */
  51. /*:05-07-1990-00:06-wht@n4hgf-add -S switch */
  52. /*:05-05-1990-01:37-relay.EU.net!rivm!a3-dont assume vax is running BSD */
  53. /*:04-18-1990-02:01-wht@n4hgf-3.20 rhg@cps.com did all the NICE work */
  54. /*:04-17-1990-14:30-rhg@cps.com-pretty up if-then-else-fi in shar file */
  55. /*:04-17-1990-12:13-rhg@cps.com-add Split and renamed old -l to -L */
  56. /*:04-17-1990-12:13-rhg@cps.com-add -c option to shar file execution */
  57. /*:04-17-1990-11:20-rhg@cps.com-simplify TOUCH logic in shar file */
  58. /*:04-17-1990-10:27-rhg@cps.com-create setTOUCH to avoid duplicate code */
  59. /*:04-17-1990-04:43-rhg@cps.com-add missing && to commands in shar file(s) */
  60. /*:04-17-1990-02:03-rhg@cps.com-add Compress */
  61. /*:04-16-1990-17:08-rhg@cps.com-add AvoidPipes as well as code to use pipes */
  62. /*:04-03-1990-20:09-wht@n4hgf-3.11 */
  63. /*:04-01-1990-13:20-pat@rwing-correct case on M option in getopt() call */
  64. /*:04-01-1990-13:50-pat@rwing-change defaults on -v, -w to be on */
  65. /*:03-29-1990-18:23-wht@n4hgf-add automatic sequent support */
  66. /*:03-28-1990-15:56-wht@n4hgf-add mode and length net.bandwidth chrome */
  67. /*:03-28-1990-14:23-wht@n4hgf-correct some runtime diagnostics */
  68. /*:11-14-1989-02:21-wht-SHAR_EOF was botched if last file char not newline */
  69. /*:11-02-1989-14:11-wht-add touch -am */
  70.  
  71. /*
  72.  Shar puts readable text files together in a package
  73.  from which they are easy to extract.
  74.  earlier attribution wht@n4hgf has:    decvax!microsof!uw-beave!jim
  75.                                     (James Gosling at CMU)
  76. */
  77. /*
  78.  *    I have made several mods to this program:
  79.  *
  80.  *    1) the -----Cut Here-----... now preceds the script.
  81.  *    2) the cat has been changed to a sed which removes a prefix
  82.  *    character from the beginning of each line of the extracted
  83.  *    file, this prefix character is added to each line of the archived
  84.  *    files and is not the same as the first character of the
  85.  *    file delimeter.
  86.  *    3) added several options:
  87.  *        -c    - add the -----Cut Here-----... line.
  88.  *        -d'del' - change the file delimeter to del.
  89.  *        -s    - cause the resulting script to print the wc of
  90.  *              the orignal file and the wc of the extracted
  91.  *              file.
  92.  *
  93.  *                Michael A. Thompson
  94.  *                Dalhousie University
  95.  *                Halifax, N.S., Canada.
  96.  */
  97.  
  98. /*
  99.  *    I, too, have been hacking this code. This is the version on sixhub
  100.  *        bill davidsen (davidsen@sixhub.uucp)
  101.  *
  102.  *    - added support for binary files
  103.  *    - automatic creation of limited size multiple file archives,
  104.  *      each of which may be unpacked separately, and with sequence
  105.  *      checking.
  106.  *    - support for mixed text and binary files
  107.  *    - preserve file permissions
  108.  *    - restore to filename rather than pathname
  109.  *
  110.  */
  111. /*
  112.  *  One good hack deserves another ... this version generates shell
  113.  *  code which attempts to create missing directories
  114.  *  handle deviants sun, vax, pyr (pyramid), SCO XENIX/UNIX automatically
  115.  *  for sequent, add -DBSD42
  116.  *  force Verbose on
  117.  *  if unsharing system's touch Sys V compatible (allows touch -m),
  118.  *  restore file dates
  119.  *  -n switch puts an alpha "name" in header
  120.  *  -a (if also -n) puts "Submitted-by:" & "Archive-name: <name>/part##
  121.  *  use getopt
  122.  *  as well as some other chrome-plated junque
  123.  *  ...!gatech!emory!tridom!wht (wht%n4hgf@gatech.edu) Warren Tucker
  124.  *
  125.  *  3.11 - Fri Apr  6 14:21:51 EDT 1990
  126.  *  With due deference to davidsen@sixhub, more changes..... copies
  127.  *  of this, like 3.10,  were mailed to him:
  128.  *  From wht  Fri Apr  6 15:14:30 1990 remote from n4hgf
  129.  *  Received: by n4hgf.UUCP (smail2.5-UNIX/386 5.3.2)
  130.  *      id AA01781; 6 Apr 90 15:14:30 EDT (Fri)
  131.  *  Date: Fri, 6 Apr 90 15:14:30 EDT
  132.  *  X-Mailer: Mail User's Shell (6.5 4/17/89)
  133.  *  From: wht@n4hgf (Warren Tucker)
  134.  *  To: davidsen@sixhub
  135.  *  Subject: shar 3.11
  136.  *  X-Bang-Reply-to: gatech!n4hgf!wht -or- emory!tridom!n4hgf!wht
  137.  *  Reply-to: wht%n4hgf@gatech.edu
  138.  *  Message-Id: <9004061514.AA01781@n4hgf.UUCP>
  139.  *
  140.  *  1. changes suggested by pat@rwing (Pat Myrto) and silvert@cs.dal.ca
  141.  *  (Bill Silvert)
  142.  *  2. fixes to who_am_i code in who@where.c
  143.  *
  144.  *  3.20 - Wed Apr 18 01:58:32 EDT 1990
  145.  *  changes were made per edit notes by
  146. From: gatech!mailrus!uunet!cpsolv.CPS.COM!rhg (Richard H. Gumpertz)
  147.  *  ...!gatech!n4hgf!wht (wht%n4hgf@gatech.edu) Warren Tucker
  148.  *
  149.  */
  150.  
  151. /* MS-DOS port (c) 1990 by Thorsten Ohl, ohl@gnu.ai.mit.edu
  152.    This port is distributed under the terms of the
  153.    GNU General Public License as published by the
  154.    Free Software Foundation.  */
  155.  
  156. #include <stdio.h>
  157. #include <sys/types.h>
  158. #include <time.h>
  159. #include <sys/stat.h>
  160. #include <ctype.h>
  161.  
  162. /* assume system v unless otherwise fixed */
  163. #if (defined(pyr) || defined(vax) || defined(sequent)) && !defined(BSD42) && !defined(SYS5)
  164. #define BSD42
  165. #endif
  166. #if defined(sun)    /* this miscreant doesn't exactly fit BSD or SYSV */
  167. #undef BSD42
  168. #undef SYS5
  169. #endif
  170. #if !defined(BSD42) && !defined(sun) && !defined(SYS5)
  171. #define SYS5
  172. #endif
  173.  
  174. #if defined(sun) || defined(BSD42)
  175. #define strchr    index
  176. #define strrchr    rindex
  177. #endif
  178.  
  179. #ifdef MSDOS
  180.  
  181. #include <stdlib.h>
  182. #include <string.h>
  183. #include <errno.h>
  184. #include <stdarg.h>
  185. #include <process.h>
  186. #include <direct.h>
  187. #include <io.h>
  188.  
  189. /* We will use some GNUish MS-DOS stuff */
  190. #include <getopt.h>
  191. #include <gnulib.h>
  192. char *program_name;
  193.  
  194. /* Unkown to MS-DOS */
  195. #define S_ISUID 0x00
  196. #define S_ISGID 0x00
  197. #define S_ISVTX 0x00
  198.  
  199. /* Nobody ever waits for MS-DOS ... */
  200. #define wait(foo) (-1)
  201.  
  202. #define who_where(buf) \
  203.   {                            \
  204.     char *user = getenv ("USER");            \
  205.     strcpy (buf, user ? user : "anonymous@any.net");    \
  206.   }
  207.  
  208. #define getcwd(buf, len)  msdos_format_filename (getcwd (buf, len))
  209.  
  210. /* We make this program selfcontained by providing our own pipes.
  211.    This also avoids the neccessity of invoking a subshell (which
  212.    may turn out to be a command.com ....  */
  213.  
  214. #define pipe_file1 (_pipe_file (0))
  215. #define pipe_file2 (_pipe_file (1))
  216. extern char *_pipe_file (int n);
  217. extern int filter_through_command (char *infile, char *outfile,
  218.                    char *command, ...);
  219.  
  220. /* From uuchar.c */
  221. extern void encode (FILE *in, FILE *out);
  222.  
  223. extern void main (int argc, char **argv);
  224. static char *mode_map (unsigned short mode, char *mode_str);
  225. static void setTOUCH (void);
  226. static int walkdown (int (*rtn) (char *, char *), char *file, int filelen,
  227.              char *rname);
  228. static int walktree (int (*rtn) (char *, char *), char *rootname);
  229. static int onecheck (char *file, char *rname);
  230. static int oneheader (char *file, char *rname);
  231. static int header (int argc, char **argv);
  232. static void gen_mkdir (char *path);
  233. static void gen_mkdir_script (char *path);
  234. static int shar (char *file, char *RstrName);
  235. static int helpuser (void);
  236.  
  237. #else /* not MSDOS */
  238.  
  239. char *strchr();
  240. char *strrchr();
  241. #ifdef __STDC__ /* my concession to ANSI-pansiness */
  242. void *malloc();
  243. #else
  244. char *malloc();
  245. #endif
  246. FILE *fdopen();
  247. FILE *popen();
  248.  
  249. #endif /* not MSDOS */
  250.  
  251. #define    DELIM        "SHAR_EOF"/* put after each file */
  252. #define PREFIX1        'X'    /* goes in front of each line */
  253. #define PREFIX2        'Y'    /* goes in front of each line if Delim[0] == PREFIX1 */
  254. #define WC            "wc -c <"
  255.  
  256. int PREFIX = PREFIX1;    /* Character to get at the beginning of each line */
  257.  
  258. int Archive_name = 0;    /* option to generate "Archive-name:" headers */
  259. int Verbose = 1;        /* option to provide append/extract feedback */
  260. int Wc_c = 1;            /* option to provide wc checking */
  261. char *Delim = DELIM;    /* pointer to delimiter string */
  262. int OptPREFIX = 1;        /* suppress PREFIX unless 1st char forces it */
  263. int Cut = 0;            /* option to provide cut mark */
  264. char *CutMessage = "---- Cut Here and feed the following to sh ----\n";
  265. int Binary = 0;            /* flag for binary files */
  266. int AvoidPipes = 0;        /* use temp file instead of pipe to feed uudecode, etc.
  267.                            (better error detection at expense of disk space) */
  268. int Vanilla = 0;        /* no Brown-Shirt mode */
  269. int Touch = 0;            /* generate $TOUCH commands */
  270. int Compress = 0;        /* run input files through compress (requires Binary) */
  271. int CompressBits = 12;    /* -b option to compress */
  272. int Mixed = 0;            /* mixed text and binary files */
  273. int eXists = 1;            /* check if file exists */
  274. int InterOW = 0;        /* interactive overwrite */
  275. int PosParam = 0;        /* allow positional parameters */
  276. int FileStrip;            /* strip directories from filenames */
  277. #ifdef    DEBUG
  278. int de_bug = 0;            /* switch for debugging on */
  279. #define DeBug(f,v) if (de_bug) printf(f, v)
  280. #else    /* normal compile */
  281. #define DeBug(f,v)        /* do nothing */
  282. #endif
  283.  
  284. FILE *fpout = stdout;
  285. int shar();
  286. unsigned limit = 0;
  287. int Split = 0;            /* Split files in the middle */
  288. long ftell();
  289. long TypePos;            /* position for archive type message */
  290. long EndHeadPos;        /* position for first file in the shar file */
  291. char outname[50];        /* base for output filename */
  292. char filename[50];        /* actual output filename */
  293. char *sharname = (char *)0;
  294. char *submitter = (char *)0;
  295. int filenum = 0;        /* output file # */
  296. struct stat fst;        /* check file type, access */
  297.  
  298. #ifdef MSDOS
  299. void
  300. main (int argc, char **argv)
  301. #else
  302. main(argc,argv)
  303. char **argv;
  304. #endif
  305. {
  306. int status = 0;
  307. int stdin_file_list = 0;
  308. char *oname;
  309. int c;
  310. extern int optind;
  311. extern char *optarg;
  312.  
  313. #ifdef MSDOS
  314.     program_name = argv[0];
  315. #endif
  316.     while((c = getopt(argc,argv,"VmSvwd:BTCb:xXcfMpPFas:n:l:L:o:h")) != -1)
  317.     {
  318.         switch(c)
  319.         {
  320.         case 'V':
  321.             Vanilla = 1;
  322.             break;
  323.         case 'm':
  324.             Touch = 1;
  325.             break;
  326.         case 'S':
  327.             stdin_file_list = 1;
  328.             break;
  329.         case 'v':
  330.             Verbose = 0;
  331.             break;
  332.         case 'w':
  333.             Wc_c = 0;
  334.             break;
  335.         case 'd':
  336.             Delim = optarg;
  337.             PREFIX = (Delim[0] == PREFIX1 ? PREFIX2 : PREFIX1);
  338.             break;
  339.         case 'B': /* binary files */
  340.             Binary = 1;
  341.             Compress = 0;
  342.             break;
  343.         case 'T': /* text mode */
  344.             Binary = 0;
  345.             Compress = 0;
  346.             break;
  347.         case 'b': /* Compress bits */
  348.             CompressBits = atoi(optarg);
  349.             /* fall through to -C */
  350.         case 'C': /* Compress */
  351.             Binary = 1;
  352.             Compress = 1;
  353.             break;
  354.         case 'x': /* don't worry whether the file exist */
  355.             eXists = 0;
  356.             break;
  357.         case 'X': /* ask the user whether to overwrite existing files */
  358.             InterOW = 1;
  359.             eXists = 1;
  360.             break;
  361.         case 'c':
  362.             Cut = 1;
  363.             break;
  364.         case 'f': /* filenames only */
  365.             FileStrip = 1;
  366.             break;
  367.         case 'M': /* mixed text and binary */
  368.             Mixed = 1;
  369.             break;
  370.         case 'p': /* allow positional parameters */
  371.             PosParam = 1;
  372.             break;
  373.         case 'P': /* use temp files instead of pipes in the shar file */
  374.             AvoidPipes = 1;
  375.             break;
  376.         case 'F': /* force PREFIX to be put out even if not required */
  377.             OptPREFIX = 0;
  378.             break;
  379.         case 'l': /* soft size limit in k */
  380.             if((limit = atoi(optarg)) > 1)
  381.                 --limit;
  382.             Split = 0;
  383.             DeBug("Soft limit %dk\n",limit);
  384.             break;
  385.         case 'L': /* hard size limit in k */
  386.             if((limit = atoi(optarg)) > 1)
  387.                 --limit;
  388.             Split = (limit != 0);
  389.             AvoidPipes = 1;
  390.             DeBug("Hard limit %dk\n",limit);
  391.             break;
  392.         case 'n': /* name of archive */
  393.             sharname = optarg;
  394.             break;
  395.         case 's': /* submitter */
  396.             submitter = optarg;
  397.             break;
  398.         case 'a': /* generate Archive-name: headers */
  399.             Archive_name = 1;
  400.             break;
  401.         case 'o': /* specify output file */
  402.             oname = optarg;
  403.             strcpy(outname,oname);
  404.             strcat(outname,".");
  405.             filenum = 1;
  406.             strcpy(filename,outname);
  407.             strcat(filename,"01");
  408.             fpout = fopen(filename,"w");
  409.             if(!fpout)
  410.             { /* creation error */
  411.                 perror("can't create output file");
  412.                 exit(1);
  413.             }
  414.             break;
  415. #ifdef    DEBUG
  416.         case '$': /* totally undocumented $ option, debug on */
  417.             de_bug = 1;
  418.             break;
  419. #endif
  420.         default: /* invalid option */
  421.         case 'h': /* help */
  422.             helpuser();
  423.             break;
  424.         }
  425.     }
  426.  
  427.     if(Vanilla)
  428.     {
  429.         fprintf(stderr,"Vanilla mode disabling years of progress :-)\n");
  430.         Wc_c = 0;
  431.         OptPREFIX = 0;
  432. #ifdef V_AVOIDPIPES    /* pipes are benign and only used with uudecode anyway */
  433.         AvoidPipes = 1;
  434. #endif /* V_AVOIDPIPES */
  435. #ifdef V_NOFORCE    /* If the user specifies non-defaults, let him have them */
  436. #else
  437.         Touch = 0;
  438.         InterOW = 0;
  439.         if(Binary || Mixed || Compress || PosParam)
  440.             fprintf(stderr,"WARNING: non-Text storage options overridden.\n");
  441.         Binary = 0;
  442.         Mixed = 0;
  443.         Compress = 0;
  444.         PosParam = 0;
  445. #endif /* V_NOFORCE */
  446.     }
  447.  
  448.     if(stdin_file_list)
  449.     {
  450.         char stdin_buf[258];
  451.         argc = 0;
  452.         if(!(argv = (char **)malloc(1024 * sizeof(char *))))
  453.             goto MEMORY_ERROR;
  454.         stdin_buf[0] = 0;
  455.         while(fgets(stdin_buf,sizeof(stdin_buf),stdin))
  456.         {
  457.             if(argc == 1024)
  458.             {
  459.                 fprintf(stderr,"max files from stdin is 1024!\n");
  460.                 exit(1);
  461.             }
  462.             if(stdin_buf[0])
  463.                 stdin_buf[strlen(stdin_buf) - 1] = 0;
  464.             if(!(argv[argc] = malloc(strlen(stdin_buf) + 1)))
  465.             {
  466. MEMORY_ERROR: /* NOT likely, but free software must pure as snow! */
  467.                 fprintf(stderr,"out of memory handling stdin input at %d\n",
  468.                     argc);
  469.                 exit(1);
  470.             }
  471.             strcpy(argv[argc],stdin_buf);
  472.             ++argc;
  473.             stdin_buf[0] = 0;
  474.         }
  475.         optind = 0;
  476.     }
  477.  
  478.     if(optind >= argc)
  479.     {
  480.         fprintf(stderr,"shar: No input files\n");
  481.         helpuser();
  482.         exit(1);
  483.     }
  484.  
  485.     if(Archive_name && !sharname)
  486.     {
  487.         fprintf(stderr,"shar: -n must accompany -a\n");
  488.         helpuser();
  489.         exit(1);
  490.     }
  491.  
  492.     if(!submitter)
  493.     {
  494.         if(!(submitter = malloc(128)))
  495.         {
  496.             fprintf(stderr,"memory allocation failed\n"); /* NOT likely */
  497.             exit(1);
  498.         }
  499.         who_where(submitter);
  500.     }
  501.  
  502.     if(header(argc-optind,&argv[optind]))
  503.         exit(2);
  504.  
  505.     if(InterOW)
  506.     {
  507.         Verbose = 1;
  508.         fputs("wish=\n",fpout);
  509.         if(Archive_name)
  510.         {
  511.             fprintf(stderr,
  512.                 "PLEASE do not submit -X shars to the usenet or other\n");
  513.             fprintf(stderr,
  514.                 "public networks.  They will cause problems.\n");
  515.         }
  516.     }
  517.  
  518.     EndHeadPos = ftell(fpout);
  519.  
  520.     for( ; optind < argc; ++optind)
  521.     { /* process positional parameters and files */
  522.         if(PosParam)
  523.         {        /* allow -B and -T and -C inline */
  524.             if(strcmp(argv[optind],"-B") == 0)
  525.             { /* set binary */
  526.                 Binary = 1;
  527.                 Compress = 0;
  528.                 continue;
  529.             }
  530.             if(strcmp(argv[optind],"-T") == 0)
  531.             { /* set mode text */
  532.                 Binary = 0;
  533.                 Compress = 0;
  534.                 continue;
  535.             }
  536.             if(strcmp(argv[optind],"-C") == 0)
  537.             { /* set compress */
  538.                 Binary = 1;
  539.                 Compress = 1;
  540.                 continue;
  541.             }
  542.         }
  543.         status += walktree(shar,argv[optind]);
  544.     }
  545.  
  546.     /* delete the sequence file, if any */
  547.     if(Split && filenum > 1)
  548.     {
  549.         fputs("rm -f _shar_seq_.tmp\n",fpout);
  550.         fputs("echo You have unpacked the last part\n",fpout);
  551.         if(!Verbose)
  552.             fprintf(stderr,"Created %d files\n",filenum);
  553.     }
  554.     fputs("exit 0\n",fpout);
  555.     exit(status);
  556. }
  557.  
  558. /*+-----------------------------------------------------------------------
  559.     mode_map(mode,mode_str)    build drwxrwxrwx string
  560. ------------------------------------------------------------------------*/
  561. char *
  562. mode_map(mode,mode_str)
  563. unsigned short mode;
  564. char *mode_str;
  565. {
  566. #ifdef THIS_IS_NOT_NEEDED_FOR_SHAR
  567. register unsigned ftype = mode & S_IFMT;
  568. #endif
  569. register char *rtn;
  570. static char result[12];
  571.  
  572.     rtn = (mode_str == (char *)0) ? result : mode_str;
  573.  
  574.     /*          drwxrwxrwx */
  575.     /*          0123456789 */
  576.     strcpy(rtn,"----------");
  577.  
  578. #ifdef THIS_IS_NOT_NEEDED_FOR_SHAR
  579.     switch(ftype)
  580.     {
  581.         case S_IFIFO:    *rtn = 'p'; break; /* FIFO (named pipe) */
  582.         case S_IFDIR:    *rtn = 'd'; break; /* directory */
  583.         case S_IFCHR:    *rtn = 'c'; break; /* character special */
  584.         case S_IFBLK:    *rtn = 'b'; break; /* block special */
  585.         case S_IFREG:    *rtn = '-'; break; /* regular */
  586.  
  587. #if defined(sun) | defined(BSD42)
  588.         case S_IFLNK:    *rtn = 'l'; break; /* symbolic link */
  589.         case S_IFSOCK:    *rtn = 's'; break; /* socket */
  590. #endif
  591.  
  592. #if defined (SYS5)
  593.         case S_IFNAM:                        /* name space entry */
  594.             if(mode & S_INSEM)                /* semaphore */
  595.             {
  596.                 *rtn = 's';
  597.                 break;
  598.             }
  599.             if(mode & S_INSHD)                /* shared memory */
  600.             {
  601.                 *rtn = 'm';
  602.                 break;
  603.             }
  604. #endif
  605.  
  606.         default:        *rtn = '?'; break;    /* ??? */
  607.     }
  608. #endif /* THIS_IS_NOT_NEEDED_FOR_SHAR */
  609.  
  610.     if(mode & 000400) *(rtn + 1) = 'r';
  611.     if(mode & 000200) *(rtn + 2) = 'w';
  612.     if(mode & 000100) *(rtn + 3) = 'x';
  613.     if(mode & 004000) *(rtn + 3) = 's';
  614.     if(mode & 000040) *(rtn + 4) = 'r';
  615.     if(mode & 000020) *(rtn + 5) = 'w';
  616.     if(mode & 000010) *(rtn + 6) = 'x';
  617.     if(mode & 002000) *(rtn + 6) = 's';
  618.     if(mode & 000004) *(rtn + 7) = 'r';
  619.     if(mode & 000002) *(rtn + 8) = 'w';
  620.     if(mode & 000001) *(rtn + 9) = 'x';
  621.     if(mode & 001000) *(rtn + 9) = 't';
  622.  
  623.     return(rtn);
  624.  
  625. }    /* end of mode_map */
  626.  
  627. void
  628. setTOUCH()
  629. {
  630.     if(Touch)
  631.     {
  632.         fputs("if touch 2>&1 | fgrep 'amc' > /dev/null\n",fpout);
  633.         fputs(" then TOUCH=touch\n",fpout);
  634.         fputs(" else TOUCH=true\n",fpout);
  635.         fputs("fi\n",fpout);
  636.     }
  637. } /* end of setTOUCH */
  638.  
  639. #ifdef NO_WALKTREE
  640.  
  641. int
  642. walktree(rtn,file)                /* dummy walktree */
  643. int (*rtn)(/*file,rname*/);    /* may also assume fst is set */
  644. char *file;
  645. {
  646.     register char *rname;
  647.  
  648.     if(stat(file,&fst))
  649.     {
  650.         fprintf(stderr,"shar: Can't access %s\n",file);
  651.         return(1);
  652.     }
  653.  
  654.     if(FileStrip)
  655.     { /* use just the filename */
  656.         rname = file + strlen(file);
  657.         while(rname > file && *rname != '/')
  658.             --rname;
  659.         if(*rname == '/')
  660.             ++rname;
  661.     }
  662.     else
  663.         rname = file;
  664.     if(!strncmp(rname,"./",2) && rname[2])
  665.         rname += 2;
  666.  
  667.     return((*rtn)(file,rname));
  668. }
  669.  
  670. #else /* NO_WALKTREE*/
  671.  
  672.  
  673. #ifdef MSDOS
  674.  
  675. #include <ndir.h>
  676. #define DIRENTRY struct direct
  677. #define CLOSEDIR_VOID
  678.  
  679. /* The one from ndir.h is much too short! (and has different semantics) */
  680. #undef MAXNAMLEN
  681. #define MAXNAMLEN _MAX_PATH
  682.  
  683. #else /* not MSDOS */
  684.  
  685. #ifdef NO_DIRENT
  686.  
  687. #include <sys/dir.h>            /* SunOS 3, etc. */
  688. #define DIRENTRY struct direct
  689.  
  690. #else /* NO_DIRENT */
  691.  
  692. #include <dirent.h>            /* Doug Gwyn's dirent routines */
  693. #define DIRENTRY struct dirent
  694.  
  695. #endif /* NO_DIRENT */
  696.  
  697. DIR *opendir();
  698. DIRENTRY *readdir();
  699.  
  700. #endif /* not MSDOS */
  701.  
  702. int
  703. #ifdef MSDOS
  704. walkdown (int (*rtn)(char *, char *), char *file, int filelen, char *rname)
  705. #else
  706. walkdown(rtn,file,filelen,rname)
  707. int (*rtn)(/*file,rname*/);    /* may also assume fst is set */
  708. char *file, *rname;            /* *rname must be *file + n where n < filelen */
  709. int filelen;
  710. #endif
  711. {
  712.     DIR *dirp;
  713.     DIRENTRY *dp;
  714.  
  715.     if(stat(file,&fst))
  716.     {
  717.         fprintf(stderr,"shar: Can't access %s\n",file);
  718.         return(1);
  719.     }
  720.  
  721.     if((fst.st_mode & S_IFMT) != S_IFDIR)
  722.         return((*rtn)(file,rname));
  723.  
  724.     if(!(dirp = opendir(file)))
  725.     {
  726.         fprintf(stderr,"shar: unable to open directory %s",file);
  727.         return(1);
  728.     }
  729.  
  730.     if(!strcmp(rname,"."))
  731.         rname += 2;                /* avoid "./xxx" when sharing "." */
  732.  
  733.     while((dp = readdir(dirp)))
  734.         if (strcmp(dp->d_name,".") && strcmp(dp->d_name,".."))
  735.         {
  736.             int newlen;
  737.  
  738.             if((newlen = filelen + 1 + strlen(dp->d_name)) >= MAXNAMLEN)
  739.             {
  740.                 fprintf(stderr,"shar: file name too long: %s/%s\n",
  741.                         file,dp->d_name);
  742.                 return(1);
  743.             }
  744.             sprintf(file + filelen,"/%s",dp->d_name);
  745.  
  746.             if(walkdown(rtn,file,newlen,rname))
  747.                 return(1);
  748.  
  749.             file[filelen] = '\0';    /* in case we print any error messages */
  750.         }
  751.  
  752. #ifdef CLOSEDIR_VOID
  753.     closedir(dirp);
  754. #else /* CLOSEDIR_VOID */
  755.     if(closedir(dirp))
  756.     {
  757.         fprintf(stderr,"shar: unable to close directory %s",file);
  758.         return(1);
  759.     }
  760. #endif /* CLOSEDIR_VOID */
  761.     return(0);
  762. }
  763.  
  764. int
  765. #ifdef MSDOS
  766. walktree (int (*rtn)(char *, char *), char *rootname)
  767. #else
  768. walktree(rtn,rootname)                /* real walktree */
  769. int (*rtn)(/*file,rname*/);    /* may also assume fst is set */
  770. char *rootname;
  771. #endif
  772. {
  773.     char file[MAXNAMLEN];
  774.     int filelen;
  775.     register char *rname;
  776.  
  777.     if((filelen = strlen(rootname)) >= MAXNAMLEN)
  778.     {
  779.         fprintf(stderr,"shar: file name too long: %s\n",rootname);
  780.         return(1);
  781.     }
  782.     strcpy(file,rootname);
  783.  
  784.     if(FileStrip)
  785.     { /* use just the filename */
  786.         rname = file + filelen;
  787.         while(rname > file && *rname != '/')
  788.             --rname;
  789.         if(*rname == '/')
  790.             ++rname;
  791.     }
  792.     else
  793.         rname = file;
  794.     if(!strncmp(rname,"./",2) && rname[2])
  795.         rname += 2;
  796.  
  797.     return(walkdown(rtn,file,filelen,rname));
  798. }
  799.  
  800. #endif /* NO_WALKTREE */
  801.  
  802. int
  803. onecheck(file,rname)
  804. char *file, *rname;
  805. {
  806.     if(access(file,04))
  807.     {
  808.         fprintf(stderr,"shar: Can't access %s\n",file);
  809.         return(1);
  810.     }
  811.  
  812.     return(0);
  813. }
  814.  
  815. int
  816. oneheader(file,rname)
  817. char *file, *rname;
  818. {
  819.     fprintf(fpout,"# %6ld %s %s\n",fst.st_size,
  820.         mode_map(fst.st_mode & ~(S_ISUID|S_ISGID|S_ISVTX),(char *)0),rname);
  821.     return(0);
  822. }
  823.  
  824. #ifdef MSDOS
  825. int
  826. header (int argc, char **argv)
  827. #else
  828. header(argc,argv)
  829. char **argv;
  830. #endif
  831. {
  832. int i;
  833. FILE *fpsource;    /* pipe temp */
  834. char s128[128];
  835. long now;
  836. struct tm *utc;
  837. struct tm *gmtime();
  838.  
  839.     /* see if any conflicting options */
  840.     if(limit && !filenum)
  841.     { /* can't rename what you don't have */
  842.         fprintf(stderr,"Can't use -l or -L option without -o\n");
  843.         helpuser();
  844.         return(1);
  845.     }
  846.  
  847.     for(i = 0; i < argc; i++)
  848.     { /* skip positional parameters */
  849.         if(PosParam &&
  850.             (strcmp(argv[i],"-B") == 0 ||
  851.              strcmp(argv[i],"-T") == 0 ||
  852.              strcmp(argv[i],"-C") == 0))
  853.             continue;
  854.  
  855.         if(walktree(onecheck,argv[i]))
  856.             return(1);
  857.     }
  858.  
  859.     if(Archive_name)
  860.     {
  861.         fprintf(fpout,"Submitted-by: %s\n",submitter);
  862.         fprintf(fpout,"Archive-name: %s%s%02d\n\n",
  863.             sharname,(strchr(sharname,'/')) ? "" : "/part",
  864.             (filenum) ? filenum : 1);
  865.     }
  866.  
  867.     if(Cut)
  868.         fputs(CutMessage,fpout);
  869.     fputs("#!/bin/sh\n",fpout);
  870.     if(sharname)
  871.         fprintf(fpout,"# This is %s, a shell archive (produced by shar %s)\n",
  872.             sharname,revision);
  873.     else
  874.         fprintf(fpout,"# This is a shell archive (produced by shar %s)\n",
  875.             revision);
  876.     fputs("# To extract the files from this archive, save it to a file, remove\n",
  877.         fpout);
  878.     fputs("# everything above the \"!/bin/sh\" line above, and type \"sh file_name\".\n#\n",
  879.         fpout);
  880.  
  881.     time(&now);
  882.     utc = gmtime(&now);
  883.     fprintf(fpout,"# made %02d/%02d/%04d %02d:%02d UTC by %s\n",
  884.         utc->tm_mon + 1,utc->tm_mday,utc->tm_year + 1900,
  885.         utc->tm_hour,utc->tm_min,
  886.         submitter);
  887.  
  888.  
  889. #ifdef MSDOS
  890.     /* Get current directory (w/ cosmetics) */
  891.     getcwd (s128, 127);
  892. #else /* not MSDOS */
  893. #if defined(SYS5)
  894.     if(!(fpsource = popen("/bin/pwd","r")))
  895.         return(-1);
  896.     fgets(s128,sizeof(s128),fpsource);
  897.     s128[strlen(s128) - 1] = 0;
  898.     fclose(fpsource);
  899. #else
  900. #if defined(BSD42) || defined(sun)
  901.     getwd(s128);
  902. #else
  903. #include "Need_conditional_compile_fix"
  904. #endif
  905. #endif
  906. #endif /* not MSDOS */
  907.  
  908.     fprintf(fpout,"# Source directory %s\n",s128);
  909.  
  910.     fprintf(fpout,"#\n# existing files %s\n",
  911.         (eXists) ? "will NOT be overwritten unless -c is specified" 
  912.             : ((InterOW) ? "MAY be overwritten"
  913.                 : "WILL be overwritten"));
  914.  
  915.     if(InterOW)
  916.         fputs("# The unsharer will be INTERACTIVELY queried.\n",fpout);
  917.  
  918.     if(Vanilla)
  919.     {
  920.         fputs("# This format requires very little intelligence at unshar time.\n",fpout);
  921.         fputs("# ",fpout);
  922.         if(eXists || Split)
  923.             fputs("\"if test\", ",fpout);
  924.         if(Split)
  925.             fputs("\"cat\", \"rm\", ",fpout);
  926.         fputs("\"echo\", \"true\", and \"sed\" may be needed.\n",fpout);
  927.     }
  928.  
  929.     if(Split)
  930.     { /* may be split, explain */
  931.         fputs("#\n",fpout);
  932.         TypePos = ftell(fpout);
  933.         fprintf(fpout,"%-75s\n%-75s\n","#","#");
  934.     }
  935.  
  936.     fputs("#\n# This shar contains:\n",fpout);
  937.     fputs("# length  mode       name\n",fpout);
  938.     fputs("# ------ ---------- ------------------------------------------\n",
  939.         fpout);
  940.     for(i = 0; i < argc; i++)
  941.     { /* output names of files but not parameters */
  942.         if(PosParam &&
  943.             (strcmp(argv[i],"-B") == 0 ||
  944.              strcmp(argv[i],"-T") == 0 ||
  945.              strcmp(argv[i],"-C") == 0))
  946.             continue;
  947.         if(walktree(oneheader,argv[i]))
  948.             exit(1);
  949.     }
  950.     fputs("#\n",fpout);
  951.  
  952.     setTOUCH();
  953.  
  954.     if(Split)
  955.     { /* now check the sequence */
  956.         fputs("if test -r _shar_seq_.tmp; then\n",fpout);
  957.         fputs("\techo 'Must unpack archives in sequence!'\n",fpout);
  958.         fputs("\techo Please unpack part `cat _shar_seq_.tmp` next\n",fpout);
  959.         fputs("\texit 1\nfi\n",fpout);
  960.     }
  961.     return(0);
  962. }
  963.  
  964. #define MAX_MKDIR_ALREADY    128    /* ridiculously enough */
  965. char *mkdir_already[MAX_MKDIR_ALREADY];
  966. int mkdir_already_count = 0;
  967.  
  968. void
  969. gen_mkdir(path)
  970. char *path;
  971. {
  972. register int ialready;
  973. char *cptr;
  974.  
  975. /* if already generated code for this dir creation, don't do again */
  976.     for(ialready = 0; ialready < mkdir_already_count; ialready++)
  977.     {
  978.         if(!strcmp(path,mkdir_already[ialready]))
  979.             return;
  980.     }
  981.  
  982. /* haven't done this one */
  983.     if(mkdir_already_count == MAX_MKDIR_ALREADY)
  984.     {
  985.         fprintf(stderr,"too many directories for mkdir generation\n");
  986.         exit(255);
  987.     }
  988.     if(!(cptr = mkdir_already[mkdir_already_count++] = malloc(strlen(path)+1)))
  989.     {
  990.         fprintf(stderr,"out of memory for mkdir generation\n");
  991.         exit(255);
  992.     }
  993.     strcpy(cptr,path);
  994.  
  995. /* generate the text */
  996.     fprintf(fpout,"if test ! -d '%s'; then\n",path);
  997.     if(Verbose)
  998.         fprintf(fpout,"    echo 'x - creating directory %s'\n",path);
  999.     fprintf(fpout,"    mkdir '%s'\n",path);
  1000.     fputs("fi\n",fpout);
  1001.  
  1002. }    /* end of gen_mkdir */
  1003.  
  1004. void
  1005. gen_mkdir_script(path)
  1006. register char *path;
  1007. {
  1008. register char *cptr;
  1009.  
  1010.     for(cptr = strchr(path,'/'); cptr; cptr = strchr(cptr + 1,'/'))
  1011.     {
  1012.         /* avoid empty string if leading or double '/' */
  1013.         if(cptr == path || *(cptr - 1) == '/')
  1014.             continue;
  1015.         /* omit '.' */
  1016.         if((*(cptr - 1) == '.') && ((cptr == path + 1) || (*(cptr - 2) == '/')))
  1017.             continue;
  1018.         *cptr = 0;                /* temporarily terminate string */
  1019.         gen_mkdir(path);
  1020.         *cptr = '/';
  1021.     }
  1022. }    /* end of gen_mkdir_script */
  1023.  
  1024. int
  1025. shar(file,RstrName)
  1026. char *file, *RstrName;
  1027. {
  1028. char line[BUFSIZ];
  1029. FILE *fpsource;
  1030. long cursize,remaining,ftell();
  1031. int split = 0;        /* file split flag */
  1032. char *filetype;        /* text or binary */
  1033. struct tm *lt;
  1034. char *filename_base;
  1035.  
  1036.     /* check to see that this is still a regular file  and readable */
  1037.     if((fst.st_mode & S_IFMT) != S_IFREG)
  1038.     { /* this is not a regular file */
  1039.         fprintf(stderr,"shar: %s is not a regular file\n",file);
  1040.         return(1);
  1041.     }
  1042.     if(access(file,04))
  1043.     {
  1044.         fprintf(stderr,"shar: Can't access %s\n",file);
  1045.         return(1);
  1046.     }
  1047.  
  1048.     /* if limit set, get the current output length */
  1049.     if(limit)
  1050.     {
  1051.         cursize = ftell(fpout);
  1052.         remaining = (limit * 1024L) - cursize;
  1053.         DeBug("In shar: remaining size %ld\n",remaining);
  1054.         
  1055.         if(!Split && cursize > EndHeadPos &&
  1056.             (Binary ? fst.st_size + fst.st_size/3 : fst.st_size) > remaining)
  1057.         { /* change to another file */
  1058.             DeBug("Newfile, remaining %ld, ",remaining);
  1059.             DeBug("limit still %d\n",limit);
  1060.  
  1061.             /* close the "&&" and report an error if any of the above failed */
  1062.             fprintf(fpout,"true || echo 'restore of %s failed'\n",RstrName);
  1063.  
  1064.             fprintf(fpout, "echo End of part %d, continue with part %d\n",
  1065.                 filenum,filenum + 1);
  1066.             fputs("exit 0\n",fpout);
  1067.  
  1068.             fclose(fpout);
  1069.  
  1070.             /* Clear mkdir_already in case the user unshars out of order */
  1071.             while (mkdir_already_count > 0)
  1072.                 free(mkdir_already[--mkdir_already_count]);
  1073.  
  1074.             /* form the next filename */
  1075.             sprintf(filename,"%s%02d",outname,++filenum);
  1076.             fpout = fopen(filename,"w");
  1077.             if(Verbose)
  1078.                 fprintf(stderr,"Starting file %s\n",filename);
  1079.  
  1080.             if(Archive_name)
  1081.             {
  1082.                 fprintf(fpout,"Submitted-by: %s\n",submitter);
  1083.                 fprintf(fpout,"Archive-name: %s%s%02d\n\n",
  1084.                     sharname,(strchr(sharname,'/')) ? "" : "/part",
  1085.                     (filenum) ? filenum : 1);
  1086.             }
  1087.  
  1088.             if(Cut)
  1089.                 fputs(CutMessage,fpout);
  1090.  
  1091.             fputs("#!/bin/sh\n",fpout);
  1092.             fprintf(fpout,"# This is part %02d of %s\n",
  1093.                 filenum,(sharname) ? sharname : "a multipart archive");
  1094.  
  1095.             setTOUCH();
  1096.  
  1097.             EndHeadPos = ftell(fpout);
  1098.         }
  1099.     }
  1100.  
  1101.     fprintf(fpout,"# ============= %s ==============\n",RstrName);
  1102.  
  1103.     gen_mkdir_script(RstrName);
  1104.  
  1105.     /* if mixed, determine the file type */
  1106.     if(Mixed)
  1107.     {
  1108. #ifdef MSDOS
  1109.         int i;
  1110.         int chars_read;
  1111.         char buf[128];
  1112.  
  1113.         /* Heuristics:  look for nonprintable characters
  1114.            at the head of the file.  */
  1115.  
  1116.         FILE *fp = fopen (file, "rb");
  1117.         chars_read = fread (buf, 1, 128, fp);
  1118.         fclose (fp);
  1119.  
  1120.         for (i = 0; i < chars_read; i++)
  1121.           if (!isgraph (buf[i]) && !isspace (buf[i]))
  1122.             break;
  1123.  
  1124.         Binary = (i == chars_read) ? 0 : 1;
  1125.  
  1126. #else /* not MSDOS */
  1127.  
  1128.         int count;
  1129.         sprintf(line,"file %s | egrep -c \"text|shell\"",file);
  1130.         fpsource = popen(line,"r");
  1131.         fscanf(fpsource,"%d",&count);
  1132.         pclose(fpsource);
  1133.         Binary = (count != 1);
  1134.  
  1135. #endif /* not MSDOS */
  1136.     }
  1137.  
  1138.     if(Binary)
  1139. #ifdef MSDOS
  1140.     {
  1141.         FILE *outptr;
  1142.  
  1143.         fflush (fpout);
  1144.  
  1145.         if (Compress)
  1146.           {
  1147.             sprintf (line, "-b%d", CompressBits);
  1148.             filter_through_command (file, pipe_file1,
  1149.                         "compress", line, NULL);
  1150.             fpsource = fopen (pipe_file1, "rb");
  1151.           }
  1152.         else
  1153.           fpsource = fopen(file, "rb");
  1154.  
  1155.         outptr = fopen (pipe_file2, "w");
  1156.         fprintf (outptr,"begin 600 %s\n",
  1157.                 (Compress ? "_shar_cmp_.tmp" : RstrName));
  1158.         encode (fpsource, outptr);
  1159.         fprintf (outptr, "end\n");
  1160.         fclose (outptr);
  1161.  
  1162.         fpsource = freopen (pipe_file2, "r", fpsource);
  1163.         filetype = (Compress ? "Compressed" : "Binary");
  1164.     }
  1165. #else /* not MSDOS */
  1166.     { /* fork a uuencode process */
  1167.         static int pid,pipex[2];
  1168.  
  1169.         pipe(pipex);
  1170.         fflush(fpout);
  1171.  
  1172.         if(pid = fork())
  1173.         { /* parent, create a file to read */
  1174.             if(pid < 0)
  1175.             {
  1176.                 fprintf(stderr,"could not fork!\n");
  1177.                 exit(1);
  1178.             }
  1179.             close(pipex[1]);
  1180.             fpsource = fdopen(pipex[0],"r");
  1181.             filetype = (Compress ? "Compressed" : "Binary");
  1182.         }
  1183.         else
  1184.         { /* start writing the pipe with encodes */
  1185.             FILE *outptr;
  1186.  
  1187.             if(Compress)
  1188.             {
  1189.                 sprintf(line, "compress -b%d < '%s'", CompressBits, file);
  1190.                 fpsource = popen(line, "r");
  1191.             }
  1192.             else
  1193.                 fpsource = fopen(file, "rb");
  1194.             outptr = fdopen(pipex[1],"w");
  1195.             fprintf(outptr,"begin 600 %s\n",
  1196.                 (Compress ? "_shar_cmp_.tmp" : RstrName));
  1197.             encode(fpsource,outptr);
  1198.             fprintf(outptr,"end\n");
  1199.             if(Compress)
  1200.                 pclose(fpsource);
  1201.             else
  1202.             {
  1203.                 fclose(fpsource);
  1204.             }
  1205.             exit(0);
  1206.         }
  1207.     }
  1208. #endif /* not MSDOS */
  1209.     else
  1210.     {
  1211.         fpsource = fopen(file,"r");
  1212.         filetype = "Text";
  1213.     }
  1214.  
  1215.     if(fpsource)
  1216.     {
  1217.         /* protect existing files */
  1218.         if(eXists)
  1219.         {
  1220.             fprintf(fpout,"if test -f '%s' -a X\"$1\" != X\"-c\"; then\n",
  1221.                 RstrName);
  1222.             if(InterOW)
  1223.             {
  1224.                 fputs("\tcase $wish in\n",fpout);
  1225.                 fprintf(fpout,"\tA*|a*) echo 'x - overwriting %s';;\n",
  1226.                     RstrName);
  1227.                 fprintf(fpout,
  1228.         "\t*) echo '? - overwrite %s -- [No], [Y]es, [A]ll, [Q]uit? '\n",
  1229.                     RstrName);
  1230.                 fputs("\t\tread wish;;\n",fpout);
  1231.                 fputs("\tesac\n",fpout);
  1232.                 fputs("\tcase $wish in\n",fpout);
  1233.                 fputs("\tQ*|q*) echo aborted; exit 86;;\n",fpout);
  1234.                 fputs("\tA*|a*|Y*|y*) x=Y;;\n",fpout);
  1235.                 fputs("\t*) x=N;;\n",fpout);
  1236.                 fputs("\tesac\n",fpout);
  1237.                 fputs("else\n",fpout);
  1238.                 fputs("\tx=Y\n",fpout);
  1239.                 fputs("fi\n",fpout);
  1240.                 fputs("if test $x != Y; then\n",fpout);
  1241.                 fprintf(fpout,"\techo 'x - skipping %s'\n",RstrName);
  1242.             }
  1243.             else
  1244.                 fprintf(fpout,"\techo 'x - skipping %s (File already exists)'\n",
  1245.                     RstrName);
  1246.             if (Split)
  1247.                 fputs("\trm -f _shar_wnt_.tmp\n",fpout);
  1248.             fputs("else\n",fpout);
  1249.             if (Split)
  1250.                 fputs("> _shar_wnt_.tmp\n",fpout);    
  1251.         }
  1252.  
  1253.         fprintf(stderr,"shar: saving %s (%s)\n",file,filetype);
  1254.         if(Verbose)
  1255.         { /* info on archive and unpack */
  1256.             fprintf(fpout,"echo 'x - extracting %s (%s)'\n",
  1257.                 RstrName,filetype);
  1258.         }
  1259.         if(Binary)
  1260.         { /* run sed through uudecode (via temp file if might get split) */
  1261.             fprintf(fpout, "sed 's/^%c//' << '%s' %s &&\n",
  1262.                    PREFIX,Delim,
  1263.                 (AvoidPipes ? "> _shar_tmp_.tmp" : "| uudecode"));
  1264.         }
  1265.         else
  1266.         { /* just run it into the file */
  1267.             fprintf(fpout,"sed 's/^%c//' << '%s' > '%s' &&\n",
  1268.                 PREFIX,Delim,RstrName);
  1269.         }
  1270.         while(fgets(line,BUFSIZ,fpsource))
  1271.         { /* output a line and test the length */
  1272.             if(OptPREFIX && isgraph(line[0]) && line[0] != PREFIX
  1273. #ifdef STRCMP_IS_FAST
  1274.                && strcmp(line,Delim)
  1275. #else /* STRCMP_IS_FAST */
  1276.                && (line[0] != Delim[0] || strcmp(line,Delim))
  1277. #endif /* STRCMP_IS_FAST */
  1278. #ifdef STRNCMP_IS_FAST
  1279.                && strncmp(line,"exit 0",6)    /* See unshar -e: avoid "exit 0" */
  1280.                && strncmp(line,"From",4)    /* Don't let mail prepend a ">" */
  1281. #else /* STRNCMP_IS_FAST */
  1282.                && (line[0] != 'e'            /* See unshar -e: avoid "exit 0" */
  1283.                    || strncmp(line,"exit 0",6))
  1284.                && (line[0] != 'F'            /* Don't let mail prepend a ">" */
  1285.                       || strncmp(line,"From",4))
  1286. #endif /* STRNCMP_IS_FAST */
  1287.               )
  1288.                 fputs(line,fpout);
  1289.             else
  1290.             {
  1291.                 fprintf(fpout,"%c%s",PREFIX,line);
  1292.                 --remaining;    /* count PREFIX (in case Split is in effect) */
  1293.             }
  1294. #ifdef MSDOS    /* This probably doesn't work but accounts for some old code */
  1295.             if(Split && (remaining -= strlen(line) + 1) < 0)    /* 1 extra for CR */
  1296. #else
  1297.             if(Split && (remaining -= strlen(line)) < 0)
  1298. #endif
  1299.             { /* change to another file */
  1300.                 DeBug("Newfile, remaining %ld, ",remaining);
  1301.                 DeBug("limit still %d\n",limit);
  1302.  
  1303.                 if(line[strlen(line) - 1] != '\n')
  1304.                     fputc('\n',fpout);
  1305.  
  1306.                 fprintf(fpout,"%s\n",Delim);
  1307.  
  1308.                 /* close the "&&" and report an error if any of the above failed */
  1309.                 fprintf(fpout,"true || echo 'restore of %s failed'\n",RstrName);
  1310.  
  1311.                 if (eXists)
  1312.                     fputs("fi\n",fpout);
  1313.  
  1314.                 if(Verbose)
  1315.                 { /* output some reassurance */
  1316.                     fprintf(fpout, "echo 'End of %s part %d'\n",
  1317.                         (sharname) ? sharname : "",filenum);
  1318.                     fprintf(fpout, "echo 'File %s is continued in part %d'\n",
  1319.                         RstrName,filenum + 1);
  1320.                 }
  1321.                 else
  1322.                     fprintf(fpout,
  1323.                         "echo 'End of part %d, continue with part %d'\n",
  1324.                         filenum,filenum + 1);
  1325.                 fprintf(fpout,"echo %d > _shar_seq_.tmp\n",filenum + 1);
  1326.                 fputs("exit 0\n",fpout);
  1327.  
  1328.                 if(filenum == 1)
  1329.                 { /* rewrite the info lines on the firstheader */
  1330.                     fseek(fpout,TypePos,0);
  1331.                     fprintf(fpout,"%-75s\n%-75s\n",
  1332.                         "# This is part 1 of a multipart archive",
  1333.                         "# do not concatenate these parts, unpack them in order with /bin/sh");
  1334.                 }
  1335.                 fclose(fpout);
  1336.  
  1337.                 /* form the next filename */
  1338.                 sprintf(filename,"%s%02d",outname,++filenum);
  1339.                 fpout = fopen(filename,"w");
  1340.  
  1341.                 if(Archive_name)
  1342.                 {
  1343.                     fprintf(fpout,"Submitted-by: %s\n",submitter);
  1344.                     fprintf(fpout,"Archive-name: %s%s%02d\n\n",
  1345.                         sharname,(strchr(sharname,'/')) ? "" : "/part",
  1346.                         (filenum) ? filenum : 1);
  1347.                 }
  1348.  
  1349.                 if(Cut)
  1350.                     fputs(CutMessage,fpout);
  1351.                 fputs("#!/bin/sh\n",fpout);
  1352.  
  1353.                 fprintf(fpout,"# this is %s (part %d of %s)\n",
  1354.                     ((filename_base = strrchr(filename,'/'))
  1355.                         ? filename_base + 1
  1356.                         : filename),
  1357.                     filenum,
  1358.                     (sharname) ? sharname : "a multipart archive");
  1359.                 fputs(
  1360.         "# do not concatenate these parts, unpack them in order with /bin/sh\n",
  1361.                     fpout);
  1362.                 fprintf(fpout,"# file %s continued\n#\n",RstrName);
  1363.  
  1364.                 setTOUCH();
  1365.  
  1366.                 fputs("if test ! -r _shar_seq_.tmp; then\n",fpout);
  1367.                 fputs("\techo 'Please unpack part 1 first!'\n",fpout);
  1368.                 fputs("\texit 1\nfi\n",fpout);
  1369.                 fputs("(read Scheck\n",fpout);
  1370.                 fprintf(fpout," if test \"$Scheck\" != %d; then\n",filenum);
  1371.                 fputs("\techo Please unpack part \"$Scheck\" next!\n",
  1372.                     fpout);
  1373.                 fputs("\texit 1\n",fpout);
  1374.                 fputs(" else\n\texit 0\n fi\n",fpout);
  1375.                 fputs(") < _shar_seq_.tmp || exit 1\n",fpout);
  1376.  
  1377.                 if(eXists)
  1378.                     if(Verbose)
  1379.                     { /* keep everybody informed */
  1380.                         fputs("if test ! -f _shar_wnt_.tmp; then\n",fpout);
  1381.                         fprintf(fpout,"\techo 'x - still skipping %s'\n",
  1382.                                 RstrName);
  1383.                         fputs("else\n",fpout);
  1384.                     }
  1385.                     else
  1386.                         fputs("if test -f _shar_wnt_.tmp; then\n",fpout);
  1387.  
  1388.                 if(Verbose)
  1389.                 { /* keep everybody informed */
  1390.                     fprintf(stderr,"Starting file %s\n",filename);
  1391.                     fprintf(fpout,"echo 'x - continuing file %s'\n",RstrName);
  1392.                 }
  1393.                 fprintf(fpout,"sed 's/^%c//' << '%s' >> '%s' &&\n",
  1394.                     PREFIX,Delim,
  1395.                     (Binary ? "_shar_tmp_.tmp" : RstrName));
  1396.                 remaining = limit * 1024L;
  1397.                 split = 1;
  1398.             }
  1399.         }
  1400.  
  1401.         (void) fclose(fpsource);
  1402.         while(wait((int *)0) >= 0)
  1403.             ;
  1404.  
  1405.         if(line[strlen(line) - 1] != '\n')
  1406.             fputc('\n',fpout);
  1407.  
  1408.         fprintf(fpout,"%s\n",Delim);
  1409.         if(split && Verbose)
  1410.             fprintf(fpout,"echo 'File %s is complete' &&\n",RstrName);
  1411.  
  1412.         /* if this file was uuencoded w/Split, decode it and drop the temp */
  1413.         if(Binary && AvoidPipes)
  1414.         {
  1415.             if(Verbose)
  1416.                 fprintf(fpout,"echo 'uudecoding file %s' &&\n",RstrName);
  1417.             fputs("uudecode < _shar_tmp_.tmp && rm -f _shar_tmp_.tmp &&\n",fpout);
  1418.         }
  1419.  
  1420.         /* if this file was compressed, uncompress it and drop the temp */
  1421.         if(Compress)
  1422.         {
  1423.             if(Verbose)
  1424.                 fprintf(fpout,"echo 'uncompressing file %s' &&\n",RstrName);
  1425.             fprintf(fpout,
  1426.                 "compress -d < _shar_cmp_.tmp > '%s' && rm -f _shar_cmp_.tmp &&\n",
  1427.                 RstrName);
  1428.         }
  1429.  
  1430.         if(Touch)
  1431.         {
  1432.             /* set the dates as they were */
  1433.             lt = localtime(&fst.st_mtime);
  1434.             fprintf(fpout,"$TOUCH -am %02d%02d%02d%02d%02d '%s' &&\n",
  1435.                 lt->tm_mon + 1,
  1436.                 lt->tm_mday,
  1437.                 lt->tm_hour,
  1438.                 lt->tm_min,
  1439.                 lt->tm_year,
  1440.                 RstrName);
  1441.         }
  1442.  
  1443.         if(Vanilla)
  1444.         {
  1445.             /* close the "&&" and report an error if any of the above failed */
  1446.             fprintf(fpout,"true || echo 'restore of %s failed'\n",RstrName);
  1447.         }
  1448.         else
  1449.         {
  1450.             /* set the permissions as they were */
  1451.             fprintf(fpout,"chmod %04o %s ||\n",
  1452.                 fst.st_mode & 00777,RstrName);
  1453.  
  1454.             /* report an error if any of the above failed */
  1455.             fprintf(fpout,"echo 'restore of %s failed'\n",RstrName);
  1456.  
  1457.             if(Wc_c)
  1458.             { /* validate the transferred file */
  1459.                 FILE *pfp;
  1460.                 char command[BUFSIZ];
  1461.  
  1462. #ifdef MSDOS
  1463.                 filter_through_command (file, pipe_file1,
  1464.                             "wc", "-c", NULL);
  1465.                 if (pfp = fopen (pipe_file1, "r"))
  1466. #else
  1467.                 sprintf(command,"%s '%s'",WC,file);
  1468.                 if((pfp = popen(command,"r")))
  1469. #endif
  1470.                 {
  1471.                     char wc[BUFSIZ];
  1472.  
  1473.                     fscanf(pfp,"%s",wc);
  1474.                     fprintf(fpout,"Wc_c=\"`%s '%s'`\"\n",WC,RstrName);
  1475.                     fprintf(fpout,"test %s -eq \"$Wc_c\" ||\n",wc);
  1476.                     fprintf(fpout,
  1477.                         "\techo '%s: original size %s, current size' \"$Wc_c\"\n",
  1478.                         RstrName, wc);
  1479. #ifdef MSDOS
  1480.                     fclose (pfp);
  1481. #else
  1482.                     pclose(pfp);
  1483. #endif
  1484.                 }
  1485.             }
  1486.         }
  1487.  
  1488.         /* if the exists option is in place close the if */
  1489.         if(eXists)
  1490.         {
  1491.             if (Split)
  1492.                 fputs("rm -f _shar_wnt_.tmp\n",fpout);
  1493.  
  1494.             fputs("fi\n",fpout);
  1495.         }
  1496.  
  1497.         return(0);
  1498.     }
  1499.     else
  1500.     {
  1501.         fprintf(stderr,"shar: Can't open %s (%s): ",file,filetype);
  1502.         perror("");
  1503.         return(1);
  1504.     }
  1505. }
  1506.  
  1507.  
  1508. char *helpinfo[] =
  1509. {
  1510.     "-V  produce \"vanilla\" shars demanding little of the unshar environment",
  1511.     "-v  verbose messages OFF while executing",
  1512.     "-m  restore file modification dates & times with \"touch\" commands",
  1513.     "-w  don't check with 'wc -c' after unpack",
  1514.     "-a  generate Submitted-by: & Archive-name: headers",
  1515.     "-nXXX   use XXX as the name of the archive (documentation)",
  1516.     "-s  override automatically determined submitter name",
  1517.     "-x  overwrite existing files without checking if they already exist",
  1518.     "-X  interactively overwrite existing files (NOT FOR NET SHARS)",
  1519.     "-B  treat all files as binary, use uuencode",
  1520.     "-T  treat all files as text (default)",
  1521.     "-C  compress and uuencode all files",
  1522.     "-bXX    pass -bXX (default 12) to compress when compressing (implies -C)",
  1523.     "-p  allow positional parameter options. The options \"-B\" and \"-T\"",
  1524.     "    and \"-C\" may be embedded, and files to the right of the",
  1525.     "    option will be processed in the specified mode",
  1526.     "-M  mixed mode. Determine if the files are text or",
  1527.     "    binary and archive correctly.",
  1528.     "-P  use temp files instead of pipes in the shar file",
  1529.     "-F  force the prefix character on every line (even if not required)",
  1530.     "-c  start the shar with a cut line",
  1531.     "-f  restore by filename only, rather than path",
  1532.     "-dXXX   use XXX to delimit the files in the shar",
  1533.     "-oXXX   (or -o XXX) output to file XXX.01 thru XXX.nn",
  1534.     "-lXX    limit output file size to XXk bytes (but don't split files)",
  1535.     "-LXX    limit output file size to XXk bytes (may split files)",
  1536.     "-S      read files to wrap from stdin, ignoring argument line",
  1537.     "\nThe -S option reads filenames one per line from stdin; input",
  1538.     "format must be similar to 'find' output, except that if -p",
  1539.     "is specified, -B, -T or -C may be used (on lines by themselves)",
  1540.     "e.g., find . -type f -print | sort | shar -C -l50 -o /tmp/big",
  1541.     "\nThe 'o' option is required if the 'l' or 'L' option is used",
  1542.     "The 'n' option is required if the 'a' option is used",
  1543.     "\n-a generates sharname/part## headers. If the -a argument contains",
  1544.     "a '/', then /part is not appended",
  1545.     "The automatic submitter name is trivial: essentially `whoami`@`uname`",
  1546.     (char *)0
  1547. };
  1548.  
  1549. helpuser()
  1550. {                /* output a command format message */
  1551.     register char **ptr;
  1552.     fprintf(stderr,
  1553.         "shar %s\nusage: shar [ options ] file ...\n       shar -S [ options ]\n",
  1554.         revision);
  1555.     for(ptr = helpinfo; *ptr; ptr++)
  1556.         fprintf(stderr,"%s\n",*ptr);
  1557.  
  1558.     exit(1);
  1559. }
  1560. /* vi: set tabstop=4 shiftwidth=4: */
  1561.