home *** CD-ROM | disk | FTP | other *** search
- /*
- Postman's Sort (R) Version 1.0
- Copyright (c) Robert Ramey 1991. All Rights Reserved
- */
-
- #include <fcntl.h>
- #include <io.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <assert.h>
- #include <links.h>
- #include "psort.h"
- #include "key.h"
- #include "record.h"
- #include "arg.h"
-
- STACK *d_stack;
- RECORD *((*infunc)()) = rec_variable;
- size_t record_size
- = DEFAULT_RECORD_SIZE; /* max size of fixed or variable length record */
- size_t data_size = 0; /* space required for fields, links etc. */
- char *record_buffer = NULL; /* buffer to hold variable length record */
- int delimiter = '\t'; /* field delimiter */
-
- void *
- need(STACK *, SEG_SIZE); /* defined in sort.c */
- RECORD *
- rec_get(char *, SEG_SIZE, FILE *);
- void
- rec_fill(RECORD *);
- void
- rec_windup(void);
-
- /**********************************************************************
- rec_init - get command line info for record functions
- **********************************************************************/
- void
- rec_init(argc, argv)
- int argc;
- char *argv[];
- {
- RANGE range;
- unsigned int i;
-
- /* process key information */
- key_init(argc, argv);
- data_size = record_offset + sizeof(ADDRESS) + 1;
-
- /* analize arguments in command line */
- i = arg_find(argc, argv, "-d");
- if(i == -1)
- i = arg_find(argc, argv, "-D");
- if(i != -1){
- argv[i] = "";
- if(++i >= argc
- || *argv[i] == '-'
- || *argv[i] == '0')
- error("-d switch muse specify delimiter char in apostrophes");
- arg_value(argv[++i], &delimiter);
- argv[i] = "";
- }
- i = arg_find(argc, argv, "-s");
- if(i == -1)
- i == arg_find(argc, argv, "-S");
- if(i != -1){
- argv[i] = "";
- if(++i >= argc
- || *argv[i] == '-'
- || *argv[i] == '0'){
- error("-s switch must specify record width or range");
- }
- else{
- arg_range(argv[i], &range);
- argv[i] = "";
- if(range.start == range.end){
- record_size = range.start;
- infunc = rec_fixed;
- setmode(fileno(stdin), O_BINARY);
- setmode(fileno(stdout), O_BINARY);
- }
- else{
- record_size = range.end;
- record_buffer = malloc(record_size + 1);
- if(record_buffer == (char *)NULL)
- error("Couldn't get space for record buffer");
- }
- }
- }
- if(record_buffer == (char *)NULL){
- record_buffer = malloc(record_size + 1);
- if(record_buffer == (char *)NULL)
- error("Couldn't get space for record buffer");
- }
- if(record_buffer != (char *)NULL){
- if(atexit(rec_windup))
- error("Couldn't register record windup");
- }
- return;
- }
- /**********************************************************
- rec_windup - return unused memory area
- ***********************************************************/
- private void
- rec_windup(){
- if(record_buffer != (char *)NULL)
- free(record_buffer);
- }
- /**********************************************************
- rec_variable - get a variable size record from standard input
- ***********************************************************/
- RECORD *
- rec_variable()
- {
- RECORD *record_address; /* pointer to record */
- size_t record_length;
-
- /* make sure we don't fill the record buffer up */
- if(rec_get(record_buffer, record_size , stdin)
- == (char *)NULL)
- return (RECORD *)NULL;
- record_length = strlen(record_buffer);
- record_address
- = (RECORD *)mklinks(need(d_stack, data_size+record_length), 1);
- memcpy(record_address->data+record_offset,
- record_buffer, record_length + 1);
-
- /* if record data doesn't fit within buffer */
- if(record_address->data[record_offset + record_length - 1] != '\n')
- error("Record too long");
-
- record_address->field[0] = record_offset + record_length;
- rec_fill(record_address);
-
- return record_address;
- }
- /**********************************************************
- rec_get - get a record from standard input
- ***********************************************************/
- private
- RECORD *
- rec_get(ptr, size, fptr)
- char *ptr;
- SEG_SIZE size;
- FILE *fptr;
- {
- if(fgets(ptr, (int)size, fptr) == (char *)NULL){
-
- /* be sure its an end of file */
- if(feof(fptr)){
- /* if we're done, change future input source */
- fclose(fptr);
- /* and return NULL */
- return (RECORD *)NULL;
- }
- else{
- perror("I/O error in standard input");
- exit(1);
- }
- }
- }
- /*********************************************************
- rec_fixed - get a fixed size record from standard input
- ***********************************************************/
- RECORD *
- rec_fixed()
- {
- RECORD *record_address; /* pointer to record including links and fields */
- int record_read;
- SEG_SIZE size;
-
- /* get space for input */
- record_address
- = (RECORD *)mklinks(need(d_stack, data_size + record_size), 1);
- record_address->field[0] = record_offset + record_size;
-
- /* get a line of text from standard input */
- record_read =
- fread(record_address->data+record_offset, record_size, 1, stdin);
-
- /* add null terminator */
- record_address->data[record_address->field[0]] = (char)NULL;
-
- if(record_read == 0){
- /* be sure its an end of file */
- if(feof(stdin)){
- /* if we're done, change future input source */
- fclose(stdin);
- /* and return NULL */
- return (RECORD *)NULL;
- }
- else{
- assert(ferror(stdin))
- perror("I/O error in standard input");
- exit(1);
- }
- }
- rec_fill(record_address);
- return record_address;
- }
- /*********************************************************************
- rec_fill - give a record, fill in the field pointers
- **********************************************************************/
- private
- void
- rec_fill(record_address)
- RECORD *record_address; /* pointer to record */
- {
- unsigned int
- i, /* index into field sequence array */
- fstart; /* start of numeric field */
- static int
- sign, /* +1 or -1 depending on sign of field */
- offset, /* offset to record data */
- noffset; /* offset to filled numeric data */
- char *tptr, *eptr, c;
-
- /* figure where data starts */
- tptr = record_address->data + record_offset;
- eptr = record_address->data + record_address->field[0];
-
- /* find where fields start */
- tab[0] = record_offset;
- i = 1;
- while(i < tab_count){
- while(!isdelim(*tptr++)){
- if(tptr >= eptr){
- goto fini;
- }
- }
- tab[i++] = tptr - record_address->data;
- }
- fini:
- /* missing fields all point to null */
- while(i < tab_count)
- tab[i++] = record_address->field[0];
-
- noffset = data_offset;
- for(i = 0 ; i < key_count; ++i){
- if(key[i].key_type == DEFAULT){
- offset = tab[key[i].rfield+1] - tab[key[i].rfield];
- offset = min(offset-1, key[i].disp) + tab[key[i].rfield];
- assert(record_address);
- record_address->field[i+1] = offset;
- }
- else{
- /* Next 3 keys should be SIGN, NUMERIC, and FRACTION */
- offset = tab[key[i].rfield+1] - tab[key[i].rfield];
- offset = min(offset-1, key[i].disp) + tab[key[i].rfield];
- /* skip leading spaces */
- while(record_address->data[offset] == ' ')
- ++offset;
- c = record_address->data[offset];
- sign = 1;
- if('+' == c)
- ++offset;
- else
- if('-' == c){
- sign = -1;
- ++offset;
- }
- while(record_address->data[offset] == '0')
- ++offset;
- fstart = offset;
- while(key[i + 1].seq->value[record_address->data[offset]])
- ++offset;
- assert(record_address);
- record_address->data[noffset] = sign * (offset - fstart + 1);
- record_address->field[i + 1] = noffset++;
- record_address->field[i + 2] = fstart;
-
- /* skip . or , if exists */
- c = record_address->data[offset];
- if(c == '.' || c == ',')
- ++offset;
- record_address->field[i + 3] = offset;
- i += 3;
- }
- }
- rec_memflag(record_address) = FALSE;
- return;
- }
- /*********************************************************************
- rec_output - write one record to standard output
- **********************************************************************/
- void
- rec_output(record_address)
- RECORD *record_address;
- {
- efwrite(record_address->data + record_offset,
- record_address->field[0] - record_offset,
- 1, stdout);
- }
-