home *** CD-ROM | disk | FTP | other *** search
- /* --------------------------------- -------
- * |\ | | | | | |.| | \| |/ /|\ |||||||
- * | | | |/ | |\ |/ |/| |\ |/ | ? ---+--- =<
- * | | | | | | | | | | | \qqqqqqqqq/
- * --------------------------------- ~~~~~~~~~~~~~~~~
- * Split - Split a file into pieces.
- * Copyright (C) 1989, 1992, 1993 Torsten Poulin
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public Licence as published by
- * the Free Software Foundation; either version 2 of the Licence, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public Licence for more details.
- *
- * You should have received a copy of the GNU General Public Licence
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * The author can be contacted by s-mail at
- * Torsten Poulin
- * Banebrinken 99, 2, 77
- * DK-2400 Copenhagen NV
- * DENMARK
- *
- * $Id: Split.c,v 37.5 93/03/30 23:12:33 Torsten Rel $
- * $Log: Split.c,v $
- * Revision 37.5 93/03/30 23:12:33 Torsten
- * Rewritten from scratch. The code is a lot easier to maintain
- * and improve now. An informal test showed that byte oriented
- * splits (BYTES and PARTS) are approx. 10-35 times faster than before.
- * The line oriented mode hasn't been optimized yet.
- * The price to be paid is an 80% bigger executable (still smaller
- * than 2kb though ;-).
- * The 28 character limit on the TO name has been raised to 253.
- * Important: The template has been changed!!!
- *
- * Revision 37.4 93/02/13 16:13:10 Torsten
- * Replaced exec.library/SetSignal() with dos.library/CheckSignal().
- *
- */
-
- #include <exec/types.h>
- #include <exec/memory.h>
- #include <dos/dos.h>
- #include <dos/dostags.h>
- #include <clib/macros.h>
- #include <clib/dos_protos.h>
- #include <clib/exec_protos.h>
- #ifdef __SASC
- #include <pragmas/dos_pragmas.h>
- #include <pragmas/exec_pragmas.h>
- #endif
- #include <string.h>
- #include "tastlib.h"
- #include "split_rev.h"
-
- #define SPLITBUFSIZE 51200L
-
- #define PROGNAME "Split"
- #define TEMPLATE "FROM,TO/K,LINES/K/N,BYTES/K/N,PARTS/K/N,PROMPT/S"
- #define OPT_FROM 0
- #define OPT_TO 1
- #define OPT_LINES 2
- #define OPT_BYTES 3
- #define OPT_PARTS 4
- #define OPT_PROMPT 5
-
- typedef struct {
- struct DosLibrary *DOSBase;
- struct FileInfoBlock fib;
- BOOL prompt;
- LONG type;
- LONG number;
- UBYTE outname[256], *ext2, *ext1;
- /* a future version will automatically try smaller buffers if necessary */
- UBYTE buffer[SPLITBUFSIZE];
- LONG bufsize;
- } Global;
-
- char const versionID[] = VERSTAG;
- char const copyright[] = "$COPYRIGHT:©1989,1992,1993 Torsten Poulin$";
-
- LONG getnumber(LONG);
- VOID initoutname(UBYTE *, Global *);
- VOID incoutname(Global *);
- LONG split(BPTR, Global *);
- LONG copylines(BPTR, BPTR, LONG, Global *);
- LONG copybytes(BPTR, BPTR, LONG, Global *);
- VOID promptuser(Global *);
-
-
- LONG entrypoint(VOID)
- {
- struct DosLibrary *DOSBase;
- struct RDArgs *args;
- Global *global;
- LONG arg[6];
- LONG rc = RETURN_OK;
- BPTR input;
-
- if (!(DOSBase = (struct DosLibrary *) OpenLibrary("dos.library", 37L)))
- return RETURN_FAIL;
-
- if (!(global = AllocVec(sizeof(Global), MEMF_CLEAR)))
- rc = ERROR_NO_FREE_STORE;
- else
- {
- global->DOSBase = DOSBase;
- global->bufsize = SPLITBUFSIZE;
-
- arg[OPT_FROM] = arg[OPT_TO] = arg[OPT_LINES] =
- arg[OPT_PARTS] = arg[OPT_BYTES] = arg[OPT_PROMPT] = 0L;
-
- if (!(args = ReadArgs(TEMPLATE, arg, NULL)))
- rc = RETURN_FAIL;
- else
- {
- initoutname(arg[OPT_TO] ? (UBYTE *) arg[OPT_TO] : "x", global);
- global->prompt = (BOOL) arg[OPT_PROMPT];
-
- if (arg[OPT_PARTS])
- {
- global->type = OPT_PARTS;
- global->number = getnumber(arg[OPT_PARTS]);
- }
- else if (arg[OPT_BYTES])
- {
- global->type = OPT_BYTES;
- global->number = getnumber(arg[OPT_BYTES]);
- }
- else if (arg[OPT_LINES])
- {
- global->type = OPT_LINES;
- global->number = getnumber(arg[OPT_LINES]);
- }
- else
- {
- global->type = OPT_LINES;
- global->number = 1000;
- }
-
- if (!arg[OPT_FROM])
- rc = split(Input(), global);
- else if (input = Open((UBYTE *) arg[OPT_FROM], MODE_OLDFILE))
- {
- rc = split(input, global);
- Close(input);
- }
- else
- rc = RETURN_ERROR;
-
- FreeArgs(args);
- }
- FreeVec(global);
- }
- rc = printErrorMsg(rc, PROGNAME, DOSBase);
- CloseLibrary((struct Library *) DOSBase);
- return rc;
- }
-
-
- LONG getnumber(LONG val)
- {
- LONG number;
-
- number = *(ULONG *) val;
- if (number < 1L)
- number = 1L;
- return number;
- }
-
-
- VOID initoutname(UBYTE *name, Global *global)
- {
- UBYTE *p = global->outname;
- LONG len;
-
- for (len = 0; *name && len < 253; len++, name++)
- *p++ = *name;
- global->ext1 = p;
- *p++ = 'a';
- global->ext2 = p;
- *p++ = 'a';
- *p = '\0';
- }
-
-
- VOID incoutname(Global *global)
- {
- if (*global->ext2 < 'z')
- ++*global->ext2;
- else
- {
- *global->ext2 = 'a';
- ++*global->ext1;
- }
- }
-
-
- LONG split(BPTR input, Global *global)
- {
- struct DosLibrary *DOSBase = global->DOSBase;
- LONG (*copy)(BPTR in, BPTR out, LONG number, Global *global);
- LONG rc = RETURN_OK;
- LONG count = 0;
- BPTR output;
-
- if (global->type == OPT_PARTS)
- {
- /* To use PARTS we obviously need to know how long the file is.
- * Previous versions of this program used Seek() to determine the
- * length. This led to very unhappy results if the input happened
- * to be a pipe. In my humble opinion pipes either shouldn't
- * support the ACTION_SEEK packet, or better when supporting
- * ACTION_EXAMINE_OBJECT should set the fib_DirEntryType to
- * something like ST_PIPE or whatever (to be honest the various
- * pipe handlers I have actually do that: William Hawes' PIP: sets
- * it to -5. C-A's PIPE: and Matt Dillon's FIFO: set it to 0).
- * How about creating an official (documented) standard? So given
- * the present circumstances the following, though not without its
- * flaws, works a little better.
- */
- if (!ExamineFH(input, &global->fib)
- || global->fib.fib_Size == 0
- || global->fib.fib_DirEntryType == -5
- || global->fib.fib_DirEntryType == 0)
- {
- MyPrintf(global,
- "%s: Cannot determine size (file is a pipe or empty)\n",
- PROGNAME);
- SetIoErr(ERROR_OBJECT_WRONG_TYPE);
- return RETURN_ERROR;
- }
- else
- {
- if (global->number > 676)
- global->number = 676;
- global->number = global->fib.fib_Size / global->number + 1;
- }
- }
-
- if (global->type == OPT_LINES)
- copy = copylines;
- else
- copy = copybytes;
-
- while (rc == RETURN_OK)
- {
- count++;
- if (count == 676)
- global->number = -1;
-
- if (global->prompt)
- promptuser(global);
-
- if (!(output = Open(global->outname, MODE_NEWFILE)))
- {
- MyPrintf(global, "%s: Cannot open %s\n", PROGNAME, global->outname);
- return RETURN_ERROR;
- }
- rc = copy(input, output, global->number, global);
- Close(output);
- incoutname(global);
- }
- if (rc == EOF)
- rc = RETURN_OK;
- return rc;
- }
-
-
- LONG copylines(BPTR in, BPTR out, LONG number, Global *global)
- {
- struct DosLibrary *DOSBase = global->DOSBase;
- register UBYTE breakcheck = 0;
- LONG count = 0;
- LONG c;
-
- while ((c = FGetC(in)) != EOF)
- {
- if (FPutC(out, c) == EOF)
- return RETURN_ERROR;
- if (c == '\n')
- {
- count++;
- if (count == number)
- return RETURN_OK;
- }
- if (!(breakcheck -= 4) && CheckSignal(SIGBREAKF_CTRL_C))
- return ERROR_BREAK;
- }
- return EOF;
- }
-
-
- LONG copybytes(BPTR in, BPTR out, LONG number, Global *global)
- {
- struct DosLibrary *DOSBase = global->DOSBase;
- LONG wrote, read;
- LONG bytes;
- BOOL to_end = number < 0;
-
- bytes = to_end ? global->bufsize : MIN(global->bufsize, number);
- wrote = 1;
- while ((read = Read(in, global->buffer, bytes)) > 0 && wrote > 0)
- {
- wrote = Write(out, global->buffer, read);
- if (!to_end)
- {
- if ((number -= read) == 0)
- break;
- bytes = MIN(global->bufsize, number);
- }
- if (CheckSignal(SIGBREAKF_CTRL_C))
- return ERROR_BREAK;
- }
-
- if (read < 0 || wrote < 0)
- return RETURN_ERROR;
- else if (read == 0)
- return EOF;
- else
- return RETURN_OK;
- }
-
-
- VOID promptuser(Global *global)
- {
- struct DosLibrary *DOSBase = global->DOSBase;
- BPTR console;
-
- MyPrintf(global, "Press RETURN to write %s", global->outname);
- Flush(Output());
- if (console = Open("CONSOLE:", MODE_OLDFILE))
- {
- FGetC(console);
- Close(console);
- }
- }
-