home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!comp.vuw.ac.nz!waikato.ac.nz!aukuni.ac.nz!cs18.cs.aukuni.ac.nz!jwil1
- Newsgroups: comp.sources.acorn
- Subject: Source [C, UNIX]: CBadecode for UNIX
- Message-ID: <1992Dec17.015625.7604@cs.aukuni.ac.nz>
- From: jwil1@cs.aukuni.ac.nz (TMOTA)
- Date: Thu, 17 Dec 1992 01:56:25 GMT
- Sender: jwil1@cs.aukuni.ac.nz (TMOTA)
- Organization: Computer Science Dept. University of Auckland
- Approved: cba@acorn.co.nz
- Lines: 742
-
-
- /*
- The following is pcc and ANSI compatible C source code for a command-line
- version of the Archimedes !CBAdecode application.
-
- NOTE: You do not *need* this program to decode postings to this group.
- Currently it is expected that all postings will be uucoded Spark
- Archives, and this is unlikely to change in the next year or two...
-
- If you wish to gain all of the advantages of this autodecoder on a
- machine other than the Archimedes (for which you should use !CBAdecode)
- then simply compile the following program. On my ULTRIX box, I typed
- "gcc cbadecode.c" and it worked fine, so hopefully it'll be easy to
- compile on your system as well.
-
- --- Cut here (or below the Help section) ---------------------------->8---
- */
- /* (This Help file is embedded into a C comment so you don't need to strip
- it if you can't be bothered... )
-
- Help for CBAdecode (UNIX source version)
- ========================================
-
- * This source code is PUBLIC DOMAIN
- * You may copy/distribute it as much as you like so long as it is not
- * copied or distributed for profit, or as part of a commercial product.
- * Use (of application and source) is entirely at your own risk.
-
- This application is designed specifically to make decoding
- comp.binaries.acorn postings easier and quicker. It will NOT work with
- postings to other usenet or FidoNet groups! (This is because it relies on
- some header data that we place when we post files, which cannot be expected
- in other groups)
-
- It is supplied as a UNIX (pcc/ANSI) source file. (Please excuse the messiness,
- but it's a cut-back version of the !CBAdecode application on the Archimedes)
-
- This version of the application is the command-line version of the
- Archimedes application. It compiles OK on my Ultrix box, so it shouldn't be
- too difficult to compile on any C compiler...
-
- Run the application with the syntax:
- CBAdecode [list_of_filenames]
-
- CBAdecode csa/95 csa/96 csa/97
- CBAdecode file1 file3
-
- Any complete and valid postings found will be decoded immediately, using the
- name after the "begin 777" in the first part of the posting. The output
- files are Spark archives, which can be decompressed using UNIX Spark, or
- (on an archimedes) using !Spark, SparkPlug, SparkFS, ArcFS.
- Output files will be placed in the current directory. The name will be
- extended with a ".arc" or a ".txt" extension to identify its type. (archive
- or text/unknown file)
-
- If a file of the same name as the output file already exists, an extra
- extension (.retry1 .retry2 etc) will be added in an attempt to get a unique
- (safe) filename.
-
- Operation
- =========
-
- The way the program scans for parts means that you do not need to delete
- message headers and signatures, concatenate files, or even get them in the
- right order - everything is done automatically for you!
-
- In fact, if you do strip headers, the program will FAIL, so just leave the
- message files you get from c.b.a alone, and pass them to this program in
- their RAW, unprocessed form.
-
- The application will cope with all of the posted messages concatenated into
- one (or more) file(s), or a lot of seperate files.
-
- It also handles any mixture of parts from different postings without
- complaint. It shouldn't cause any damage to any of the source files, or any
- other files in the same directory, but work from a backup just in case.
-
- The only thing it won't currently handle is a posting with more than 32
- parts in it (which is a 1.6 Megabyte posting...). However, such a large
- posting will produce an archive file of approximately 1MB, which is a bit
- big for many people to handle anyway, so it is extremely unlikely that
- binaries larger than this will be posted on c.b.a. in one archive chunk.
-
-
- Problem shooting
- ================
-
- Don't shoot problems. It's antisocial. (Bdooom-Tsh!)
-
- What can you do wrong? Here's a list:
- (There are 2 types of error - warnings, which indicate possible problems,
- but usually don't affect the outcome of the decode, and bad errors, which
- will cause the application to abort its attempt to decode that particular
- posting. (Some very bad and unlikely errors may even cause the application
- to quit)
-
- * Not all parts present
- You will not be able to decode a posting until files containing all the
- relevant parts have been supplied.
-
- * One or more parts duplicated
- The duplicate parts are ignored without comment.
-
- * The quoted total number of posted parts changes from one part to another
- Processing of that posting will abort, and the next posting will be
- started. This shouldn't happen unless the messages get corrupted or
- you happen to get 2 different postings under the same name (unlikely!)
-
- * Too many parts in the posting
- The application thinks there are supposed to be (eg) 5 parts in the
- posting, and it has found a part number less than 1 or greater than 5.
- This usually indicates corruption of some of the files, or possibly
- that the 32 part-per-post limit of the application has been reached.
-
- * Filing errors
- If any problems occur when trying to read or write any files (most likely
- because an input file wasn't found or because the disc is full - disc
- is full? Hopefully not on your UNIX box!) the program will abort
-
- * UUcode errors
- These are usually fatal (uucode is either right or wrong), and are usually
- caused by parts of the uucode data being corrupted or missing. There isn't
- much that can be done about this - try to get a new copy of the offending
- files.
-
- If anything goes wrong, what can you do to fix it?
- * Check that you are giving it the correct set of files, and try again.
-
- * If you still can't get any joy, then you will have to resort to decoding
- the file by hand - strip headers and footers, concatenate all the text
- together in the correct order, and use uudecode and UNIX Spark to decode
- the file.
-
- The author
- ==========
-
- If you have any bug reports, suggestions, or improved code to send to the
- author, or if you want to offer him an extremely highly paid job and a
- Porsche (preference, black 930 or 944), write to:
-
- * Jason Williams
- * R.D.2, Manuel Road,
- * Silverdale,
- * North Auckland,
- * NEW ZEALAND.
- *
- * jwil1@cs.aukuni.ac.nz
- *
- * (A moderator of the usenet group comp.binaries.acorn)
-
- */
-
- /* Program: CBAdecode.c
- * Purpose: comp.binaries.acorn auto-post decoder
- * Author: Jason Williams
- * Version: 21 May 1992
- *
- * This source code is PUBLIC DOMAIN
- * You may copy/distribute it as much as you like so long as it is not
- * copied or distributed for profit, or as part of a commercial product.
- * Use of this program and source code is entirely at your own risk.
- *
- * You can contact me at:
- * Jason Williams, jwil1@cs.aukuni.ac.nz
- * R.D.2, Manuel road, (until March 1993)
- * Silverdale,
- * North Auckland,
- * NEW ZEALAND.
- */
-
-
- #include <stddef.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include "string.h"
-
- #ifndef BOOL
- # define BOOL int
- # define FALSE 0
- # define TRUE 1
- # define ERROR 1
- # define NOERROR 0
- #endif
-
- #ifndef SEEK_SET
- # define SEEK_SET 0
- #endif
-
-
- /* Maximum number of parts per post */
- #define MAXPARTS 32
-
- /* Number of the first icon in the series used for the list */
- #define BASEICON 1
-
- /* Gap between left & top of window and icons */
-
- #define NOTFOUND 0
- #define FOUND 1
- #define PROCESSED 2
-
- /*
- * Posted archives should all have a 0x1a as their first byte
- * If this is the case we will *SetType the type to "Archive" (0xDDC)
- */
- #define ARCIDBYTE (0x1a)
-
-
- typedef struct
- {
- char filename[260]; /* Input file data can be found in */
- long int filepos; /* Place in file the data starts */
- int status; /* Not-found, Found, or processed */
- } partinfo;
-
-
- typedef struct _postinfo
- {
- struct _postinfo *next; /* Next postinfo in linked list */
- int totalparts, partsfound; /* Number of parts found & total */
- char id[48]; /* Post identifier name */
- char icontext[48]; /* Indirected text for icon */
- char postname[32]; /* Output leaf filename */
- int filetype; /* Output file type */
- partinfo part[MAXPARTS]; /* list of part information */
- int index; /* index in list (== icon index) */
- BOOL selected; /* Is this item selected? */
- } postinfo;
-
-
- BOOL quit = FALSE;
-
- /* Static data for scanning source files... */
- static postinfo *postheader = NULL;
-
- /* Static data for uudecoding... */
- static FILE *outfile = NULL;
- static char outfilename[256] = "\0";
-
-
-
- static void FreeEntry(prev, this)
- postinfo *prev;
- postinfo *this;
- {
- if (prev == NULL)
- postheader = this->next;
- else
- prev->next = this->next;
-
- free(this);
- }
-
-
-
- static void FreeEntryList()
- {
- postinfo *ptr = postheader, *next;
-
- while (ptr != NULL)
- {
- next = ptr->next;
- free(ptr);
- ptr = next;
- }
-
- postheader = NULL;
- }
-
-
-
- static void InitData()
- /* (re)sets all data back to initial state */
- {
- outfile = NULL;
- FreeEntryList();
- }
-
-
-
- static BOOL ProcessError()
- /*
- * Tidies up after unrecoverable error
- */
- {
- if (outfile != NULL)
- fclose(outfile);
-
- return(ERROR);
- }
-
-
-
- static void GetFilePath(pathname, path)
- char *pathname;
- char *path;
- /* Given a full-path filename, find the pathname
- */
- {
- int index, loop;
-
- path[0] = '\0';
- if (pathname[0] == '\0') return;
-
- index = strlen(pathname);
- while (index > 0 && pathname[index] != '/')
- index--;
-
- if (index > 0)
- {
- for (loop = 0; loop <= index; loop++)
- path[loop] = pathname[loop];
- path[loop] = '\0';
- }
- }
-
-
-
- /*
- * UUDecode function & macro
- */
- #define decode(ch) (((ch) - ' ') & 0x3F)
-
- void outdec(buffer, outfile, numbytes)
- char *buffer;
- FILE *outfile;
- int numbytes;
- {
- int c1, c2, c3;
-
- c1 = (decode(buffer[0]) << 2) | (decode( buffer[1]) >> 4);
- c2 = (decode(buffer[1]) << 4) | (decode( buffer[2]) >> 2);
- c3 = (decode(buffer[2]) << 6) | (decode( buffer[3]));
-
- /* Make sure we don't output too much at EOF */
- if(numbytes >= 1) putc(c1, outfile);
- if(numbytes >= 2) putc(c2, outfile);
- if(numbytes >= 3) putc(c3, outfile);
- }
-
-
-
- static BOOL GetOutputName(outname, path, leafname, filetype)
- char *outname;
- char *path;
- char *leafname;
- int filetype;
- /*
- * Tries to open the specified filename as an output file. Ensures
- * that no existing files are overwritten by generating random
- * names until a filename is found that is unique.
- * I would use tmpnam(), but this is unhelpful in that it doesn't
- * give you just a leafname.
- */
- {
- char leaf[64];
- FILE *outfile = (FILE *) 42;
- int retry = 1;
-
- strcpy(leaf,leafname); /* First try is the leafname we were given */
- if (filetype = 0xDDC)
- strcat(leaf, ".arc");
- else
- strcat(leaf, ".txt");
-
- sprintf(outname, "%s%s", path, leaf);
- while (outfile != NULL)
- {
- outfile = fopen(outname, "rb");
- if (outfile != NULL)
- {
- fclose(outfile);
- sprintf(outname, "%s%s.retry%d", path, leaf, retry++);
- if (retry > 32) /* 32 retries and still no joy */
- {
- printf("Error: Unable to generate unique filename!\n");
- return(ProcessError());
- }
- }
- }
- return(NOERROR);
- }
-
-
-
- static BOOL UUDecodePart(post, partnum, pathname)
- postinfo *post;
- int partnum;
- char *pathname;
- /*
- * Starts/continues/completes uudecoding by processing the given part
- */
- {
- FILE *infile;
- char line[260], filepath[260] = "\0";
- partinfo *part = &post->part[partnum];
-
- if (part->status != FOUND)
- return(ERROR);
-
- infile = fopen(part->filename, "rb");
- if (infile == NULL)
- {
- printf("Error: Unable to read part %d from %s\n",
- partnum, part->filename);
- return(ProcessError());
- }
-
- fseek(infile, part->filepos, SEEK_SET);
- if (partnum == 1)
- {
- fgets(line, 256, infile);
- if (strncmp(line, "begin", 5) != 0)
- {
- printf("Error: 'begin' line not found (%s, part %d)\n",
- post->id, partnum);
- return(ProcessError());
- }
-
- GetFilePath(pathname, filepath);
- if (GetOutputName(outfilename, filepath, post->postname, post->filetype) == ERROR)
- return(ERROR);
-
- printf("UUDecoding post '%s' as '%s'\n", post->id, outfilename);
-
- if (outfile != NULL) fclose(outfile);
-
- outfile = fopen(outfilename, "wb");
- if (outfile == NULL)
- {
- printf("Error: Can't open output file, '%s'!\n", outfilename);
- return(ProcessError());
- }
- }
-
-
- /* Actual UUDecode pass over rest of file
- * --------------------------------------
- */
- {
- int numbytes;
- char *buffptr;
-
- while(TRUE)
- {
- if(fgets(line, sizeof(line), infile) == NULL)
- {
- printf("Error: Short file (%s)\n", part->filename);
- return(ProcessError());
- }
-
- if (strlen(line) >= 60 && strncmp(line, "END", 3) == 0 &&
- strncmp(&line[57], "---", 3) == 0)
- break;
-
- numbytes = decode(*line);
- if(numbytes <= 0)
- break;
-
- buffptr = line + 1;
- while (numbytes > 0)
- {
- outdec(buffptr, outfile, numbytes);
- buffptr += 4;
- numbytes -= 3;
- }
- }
- }
-
- /* uudecode of part complete
- * -------------------------
- */
- part->status = PROCESSED;
- fclose(infile);
-
- if (partnum == post->totalparts)
- fclose(outfile);
-
- return(NOERROR);
- }
-
-
-
- static BOOL UUDecodePost(post, pathname, icon)
- postinfo *post;
- char *pathname;
- int icon;
- /*
- * Calls UUDecodePart for each part to be processed in turn
- */
- {
- int partnum;
-
- post->selected = FALSE;
- if (post->totalparts <= 0)
- return(ERROR);
-
- if (post->totalparts - post->partsfound > 0)
- {
- printf("Error: %d parts of %s are missing\n",
- post->totalparts - post->partsfound, post->id);
- return(ProcessError());
- }
-
- for (partnum = 1; partnum <= post->totalparts; partnum++)
- {
- if (UUDecodePart(post, partnum, pathname) == ERROR || quit)
- return(ERROR);
- }
-
- return(NOERROR);
- }
-
-
-
- static void UUDecodeFiles(pathname)
- char *pathname;
- {
- postinfo *ptr = postheader, *last = NULL;
-
- while (ptr != NULL)
- {
- if (ptr->selected)
- {
- UUDecodePost(ptr, pathname, ptr->index);
- if (quit)
- break;
-
- FreeEntry(last, ptr);
- if (last == NULL) /* Have deleted "ptr" item out from under us! */
- ptr = (postinfo *) &postheader;
- else
- ptr = last;
- }
- last = ptr;
- if (ptr != NULL)
- ptr = ptr->next;
- }
- }
-
-
-
- static postinfo *FindPost(name, create)
- char *name;
- BOOL create;
- /* Looks for the given posting in the linked list. Returns a ptr to it.
- * If the entry isn't found, (and create == TRUE), a new one is created
- */
- {
- postinfo *ptr = postheader, *last = (postinfo *) &postheader;
- int loop = BASEICON;
-
- while (ptr != NULL)
- {
- if (!strcmp(name, ptr->id))
- break;
- last = ptr;
- ptr->index = loop;
- ptr = ptr->next;
- loop++; /* remember index in list (== icon number) */
- }
-
- if (ptr == NULL && create)
- {
- ptr = (postinfo *) malloc(sizeof(postinfo));
- if (ptr == NULL)
- {
- printf("Error: Out of memory!\n");
- return(NULL);
- }
-
- last->next = ptr;
-
- ptr->selected = FALSE;
- ptr->index = loop;
- ptr->filetype = 0xDDC;
- ptr->next = NULL;
- ptr->totalparts = 0;
- ptr->partsfound = 0;
- strcpy(ptr->id, name);
- ptr->postname[0] = '\0';
-
- for (loop = 0; loop < MAXPARTS; loop++)
- {
- ptr->part[loop].status = NOTFOUND;
- ptr->part[loop].filename[0] = '\0';
- ptr->part[loop].filepos = NULL;
- }
- }
-
- return(ptr);
- }
-
-
-
- static void AddEntry(infile, filename, line)
- FILE *infile;
- char *filename;
- char *line;
- /*
- * Adds an entry for the given post & part so that we remember where to
- * find the uucode data for the parts of the post when it is needed.
- */
- {
- int index = 5;
- int namestart;
- int partnum, totalparts;
- char postid[64];
- postinfo *post;
- long int filepos = ftell(infile); /* remember where 'begin' line started */
-
- while(line[index] != 0 && line[index] != '[') index++;
- namestart = index + 1;
- while (line[index] != 0 && line[index] != ' ') index++;
- if (line[index] == 0) return;
-
- line[index++] = '\0';
- strcpy(postid, &line[namestart]);
- if ((post = FindPost(postid, TRUE)) == NULL) return;
-
- if (strncmp(&line[index], "part", 4) != 0)
- {
- printf("Warning: Invalid part header in file '%s' ignored", filename);
- return;
- }
- sscanf(&line[index], "part %d of %d]", &partnum, &totalparts);
-
- if (partnum == 1) /* If part 1, get postname (output file name) */
- {
- fgets(line, 255, infile);
- sscanf(line, "begin 777 %s ", post->postname);
- fgets(line, 255, infile);
- if (((decode(line[1]) << 2) | (decode(line[2]) >> 4)) == ARCIDBYTE)
- post->filetype = 0xDDC;
- else
- post->filetype = 0xFFF;
- }
-
- if (post->totalparts == 0) /* Get idea of how many parts to expect */
- post->totalparts = totalparts;
- else
- if (post->totalparts != totalparts)
- {
- printf("Error: Number of parts in %s is inconsistent!\n", postid);
- return;
- }
- /* Check part number validity */
- if (partnum < 1 || partnum > totalparts || partnum > MAXPARTS)
- {
- printf("Error: Illegal part number (%d) in %s\n", partnum, postid);
- return;
- }
-
- if (post->part[partnum].filename[0] == '\0') /* Check if its a duplicate */
- {
- strcpy(post->part[partnum].filename, filename);
- post->part[partnum].filepos = filepos;
- post->part[partnum].status = FOUND;
- post->partsfound++;
- }
- else
- printf("Warning: Duplicate of %s part %d ignored\n", postid, partnum);
-
- if (post->totalparts == post->partsfound)
- post->selected = TRUE; /* If all parts found, select the post icon */
- }
-
-
-
- static void ScanFile(filename)
- char *filename;
- /*
- * Scans the given file looking for post headers
- */
- {
- FILE *infile;
- char line[256];
-
- infile = fopen(filename, "rb");
- if (infile == NULL)
- {
- printf("Warning: Unable to process %s\n", filename);
- return;
- }
-
- printf("Scanning file %s\n", filename);
- while (!feof(infile))
- {
- fgets(line, 255, infile);
- if (!strncmp(line, "BEGIN", 5))
- AddEntry(infile, filename, line);
- }
-
- fclose(infile);
- }
-
-
-
- static void PrintHelp()
- /*
- * This, ah... prints the... er... help.
- */
- {
- printf("\n");
- printf(" #### ##### #### Autoposted binary uudecoder\n");
- printf(" ## ## ## ## ## ## Syntax: CBADecode [-options] [filename(s)]\n");
- printf(" ## ##### ###### \n");
- printf(" ## ## ## ## ## ## By Jason Williams - jwil1@cs.aukuni.ac.nz\n");
- printf(" #### ##### ## ## Version: 5 June 1992\n");
- exit(1);
- }
-
-
-
- extern int main(argc, argv)
- int argc;
- char *argv[];
- /*
- * If you don't know what this is for, then maybe you shouldn't be
- * mucking about with it? ;-)
- */
- {
- int count;
-
- if (argc < 2) /* check if user has absolutely no idea what to do */
- PrintHelp();
-
- InitData(); /* Initialise data structures */
-
- for(count = 1; count < argc; count++) /* Scan files given in Command line */
- ScanFile(argv[count]);
-
- UUDecodeFiles("\0");
- return(0);
- }
-
- --- CUT HERE ---
-
- --
- _________________ "I'd like to answer this question in two ways:
- /____ _ _/_ __ First in my normal voice, and then
- // / //_//_ /_/ in a silly, high-pitched whine." (Monty Python)
-