From:	CSBVAX::MRGATE!RELAY-INFO-VAX@CRVAX.SRI.COM@SMTP  3-SEP-1988 14:23
To:	ARISIA::EVERHART
Subj:	ATREAD.3_of_4


Received: From KL.SRI.COM by CRVAX.SRI.COM with TCP; Fri,  2 SEP 88 19:41:15 PDT
Received: from ucbvax.Berkeley.EDU by KL.SRI.COM with TCP; Fri, 2 Sep 88 19:25:42 PDT
Received: by ucbvax.Berkeley.EDU (5.59/1.31)
	id AA17214; Fri, 2 Sep 88 17:13:54 PDT
Received: from USENET by ucbvax.Berkeley.EDU with netnews
	for info-vax@kl.sri.com (info-vax@kl.sri.com)
	(contact usenet@ucbvax.Berkeley.EDU if you have questions)
Date: 29 Aug 88 03:24:22 GMT
From: naucse!jdc@arizona.edu  (John Campbell)
Organization: Northern Arizona University, Flagstaff, AZ
Subject: ATREAD.3_of_4
Message-Id: <850@naucse.UUCP>
Sender: info-vax-request@kl.sri.com
To: info-vax@kl.sri.com


+-+-+-+ Beginning of part 3 +-+-+-+
X         if ((yy_data[i] & 0xff) < ' ' || (yy_data[i] & 0xff) > '~')
X            printf ("``", yy_data[i] & 0xff);
X         else
X            printf ("%c", yy_data[i] & 0xff);
X      }
X      printf ("\n");
X   }
X}
X
X
Xact_mount_tape (mount, assign)
Xint mount, assign;
X/*-
X   Action routine to mount the tape (next tape or first tape).
X
X   Parameters:
X
X        mount:  Flag indicating that a mount request should be made.  If assign
X                is 0 then the user will be asked for a message to send to the
X                operator.  1 - do the mount, 0 don't.
X
X       assign:  Flag indicating if the tape drive is to be opened and assigned
X                a channel number--on the first call this should be 1, next
X                tapes this should be 0.
X-*/
X{
X   struct {
X      item_desc dev_name;
X      item_desc block_size;
X      item_desc flags_item;
X      item_desc comment;
X      int terminator;
X   }  mnt_list;
X
X   int flags = MNT$M_FOREIGN | MNT$M_NOWRITE,
X       blocks = MAX_BUF, comment=0, status;
X   char buf[100];
X   $DESCRIPTOR(tape_desc, tape);
X
X/* set up mnt_list */
X   mnt_list.dev_name.buffer_len = strlen(tape);
X   mnt_list.dev_name.item_code = MNT$_DEVNAM;
X   mnt_list.dev_name.buffer_addr = tape;
X   mnt_list.dev_name.ret_len_addr = 0;
X
X   mnt_list.block_size.buffer_len = 4;
X   mnt_list.block_size.item_code = MNT$_BLOCKSIZE;
X   mnt_list.block_size.buffer_addr = &blocks;
X   mnt_list.block_size.ret_len_addr = 0;
X
X   mnt_list.flags_item.buffer_len = 4;
X   mnt_list.flags_item.item_code = MNT$_FLAGS;
X   mnt_list.flags_item.buffer_addr = &flags;
X   mnt_list.flags_item.ret_len_addr = 0;
X
X   if (!assign) {
X   /* Ask the user if they want a comment to the operator. */
X      printf("\n%s\n%s",
V"The first tape has reached the end.  Would you like a message to the operator"
X,
X"to be attached to the next mount request (Yes or No)? ");
X      gets (buf);
X      if (comment = str_match (buf, -1, "yes", -1, 3)) {
X         printf ("Message? ");
X         gets (buf);
X      }
X   }
X   if (comment) {
X      mnt_list.comment.buffer_len   = strlen(buf);
X      mnt_list.comment.item_code    = MNT$_COMMENT;
X      mnt_list.comment.buffer_addr  = buf;
X      mnt_list.comment.ret_len_addr = 0;
X   }
X   else {
X      mnt_list.comment.buffer_len   = 0;   /* Terminate the terminator int. */
X      mnt_list.comment.item_code    = 0;
X      mnt_list.comment.buffer_addr  = 0;
X      mnt_list.comment.ret_len_addr = 0;
X   }
X
X   mnt_list.terminator = 0;
X
X/* mount the tape */
X   if (!no_tape) {
X      if (mount) {
X/*
X   "Trick" dismount whatever the user did and remount the tape as
X   foreign with a large enough block size.
X*/
X         if (((status = SYS$DISMOU(&tape_desc, DMT$M_NOUNLOAD)) &1) != 1) {
X            if (status != SS$_DEVNOTMOUNT)
X               LIB$STOP(status);
X         }
X         if (((status = SYS$MOUNT(&mnt_list)) &1) != 1)
X            LIB$STOP(status);
X      }
X      if (assign) {
X         if (((status = SYS$ASSIGN(&tape_desc,&channel,0,0)) &1) !=1)
X            LIB$STOP(status);
X      }
X   }
X   else if (assign) {
X      if ((channel = open (tape, 0, 0, "mrs=65534")) == -1) {
X         fprintf (stderr, "Can't open %s\n", tape);
X         exit(1);
X      }
X   }
X}
X
X
Xact_open ()
X/*-
X   Open the next disk file for tape info to be written into.  If the
X   directory flag is set then just report the file name and don't really
X   open the file.  If the verbose flag is set indicate the record attributes
X   used on the open.
X-*/
X{
X   int i, len, changed=0, per_count=0, arg_count, creat();
X   char *creat_args[30], *opts=file_opts;
X
X   len = strlen (file_name);
X   if (exclude_names[0] != NULL) {
X/* Search to see if this name is in the exclusion list. */
X      for (i=0; exclude_names[i] != NULL; ++i) {
X         if (wildcmp (exclude_names[i], -1, file_name, len)) {
X            active_flag = 0;
X            return;                  /* Don't count this file name. */
X         }
X      }
X   }
X   if (wild_names[0] == NULL) {
X      active_flag = 1;
X   }
X   else {
X      active_flag = 0;
X      for (i = 0; !active_flag && wild_names[i] != NULL; ++i) {
X         active_flag = wildcmp (wild_names[i], -1, file_name, len);
X      }
X   }
X   if (!active_flag)
X      return;        /* Skip this file. */
X
X   printf ("%s", file_name);
X
X/* Make the whole thing a table look-up if it seems reasonable later. */
X   for (i=0; i < len; i++) {
X      if (file_name[i] == '.') ++per_count;
X      if (!isalnum(file_name[i]) && file_name[i] != '$' &&
X          file_name[i] != '.' &&
X          file_name[i] != '_' && file_name[i] != '-' &&
X          file_name[i] != '&' || (per_count > 1 && file_name[i] == '.')) {
X         changed = 1;
X         file_name[i]='_';
X      }
X   }
X   if (changed /* && (directory_flag || verbose_flag) */) {
X      printf ("\t=====> %s\t", file_name);
X   }
X   if (*opts != '\0' && (yydebug || verbose_flag)) {
X         printf (" (opts: %.*s)", strlen(opts)-1, opts);
X   }
X  if (!directory_flag) {
X  /*
X      Open the file.  We have to use lib$callg since we don't know how
X      many file_opts there are.
X  */
X      arg_count = 2;
X      creat_args[1] = file_name;
X      creat_args[2] = (char *)0;
X      while (*opts) {
X         arg_count++;
X         creat_args[arg_count] = opts;
X         while (*opts != ',' && *opts) opts++;
X         if (*opts == ',') *opts++ = '\0';
X      }
X      creat_args[0] = arg_count;
X      file_id = lib$callg (creat_args, creat);
X   }
X   printf ("\n");
X}
X
X
Xact_vol1 ()
X/*-
X   Action routine to support the volume header.  All it does is let the
X   user know the volume label of the tape.
X-*/
X{
X   if (verbose_flag || yydebug) act_ignore ();  /* Print info out. */
X
X   printf ("Ansi Tape: Vol label (%.6s)\t%s\n", &yy_data[4],
X            ebcdic_flag ? "<<EBCDIC>>": "<<ASCII>>");
X}
X
X
Xcheck_device ()
X/*-
X   Routine to check that the device/disk name stored in "tape" is
X   really available.
X-*/
X{
X   struct {
X      item_desc dev_type;
X      int terminator;
X   }  dvi_list;
X
X   int status, dev_type, zero=0;
X   char buffer[255];
X   $DESCRIPTOR(tape_desc, tape);
X   $DESCRIPTOR(result_desc, buffer);
X
X/* set up dvi item list */
X   dvi_list.dev_type.buffer_len = 4;
X   dvi_list.dev_type.item_code = DVI$_DEVCLASS;
X   dvi_list.dev_type.buffer_addr = &dev_type;
X   dvi_list.dev_type.ret_len_addr = 0;
X
X   dvi_list.terminator = 0;
X
X/* See if the logical name stored in "tape" is a disk file. */
X   no_tape = -1;
X   status = SYS$GETDVIW (0, 0, &tape_desc, &dvi_list, 0, 0, 0, 0);
X   if (status & 1) {
X      if (dev_type == DC$_TAPE)
X         no_tape = 0;
X   }
X   else {
X      status = lib$find_file (&tape_desc, &result_desc, &zero, 0, 0, 0, 0);
X      if (status == RMS$_NORMAL)
X         no_tape = 1;
X   }
X   if (no_tape == -1) {
X      fprintf (stderr, "Device <%s> is not known\n", tape);
X      exit (1);
X   }
X}
X
X
Xint  ewrite (data, length, line_count, echo_state)
Xchar *data;
Xint length, line_count, echo_state;
X/*-
X   Routine to write data to the disk.  If echo_state is 1 then the
X   user is queried after seeing MORE_LINES worth of data.  In interactive
X   mode, files smaller than MORE_LINES are just saved.
X
X   Parameters:
X
X   echo_state:  echo state ( 0 - no echo, 1 - echo, 2 - echo off (was on))
X-*/
X{
X#define MORE_LINES 16
X   int i;
X
X   write (file_id, data, length);
X   if (echo_state == 1) {
X   /* Echo to the user. */
X      if (length > 79) length = 79;
X   /* Filter out any non-printables. */
X      for (i=0; i < length; i++) {
X         if ((data[i] & 0xff) < ' ' || (data[i] & 0xff) > '~') {
X            if (data[i] == '\n')
X               data[i] = ' ';
X            else if (data[i] != '\t')
X               data[i] = '``';
X         }
X      }
X      write (fileno(stdout), data, length);
X      write (fileno(stdout), "\n", 1);
X      if (line_count % MORE_LINES == MORE_LINES-1) {
X         write (fileno(stdout), "\n", 1);
X         echo_state = user_command();
X         write (fileno(stdout), "\n", 1);
X      }
X   }
X   if (echo_state == 4) {
X   /* Quit--do so by deleting the current file. */
X      close (file_id);
X      delete (file_name);
X      exit(1);
X   }
X   return echo_state;
X}
X
X
Xint find_pad (buf, ch, len)
Xchar *buf;
Xint ch, len;
X/*
X   Determine if there are pad characters, if so skip them, returning
X   the length of the buffer.
X*/
X{
X   int i;
X
X   for (i=len-1; i >= 0 && buf[i] == ch; --i);
X
X   return buf[i] == ch ? 0 : i+1;
X}
X
X
Xint get_num (buf)
Xunsigned char *buf;
X/*-
X   Routine to return the integer value for 'V' type records.
X-*/
X{
X   return 256*buf[0] + buf[1];
X}
X
X
Xint str_match (src, src_len, dst, dst_len, type)
Xchar *src, *dst;
Xint src_len, dst_len, type;
X/*-
X   Routine to determine if string "src" matches string
X   "dst".  The type flag indicates which type of match
X   to perform, eg case doesn't count, or src_len < dst_len
X   is allowed.  If the match is successful the routine
X   will return 1, otherwise 0 is returned.
X
X   Parameters:
X
X          src:  pointer to string to compare against dst.
X
X      src_len:  length of src, if USE_EOS, then src is '\0' terminated.
X
X          dst:  pointer to string to match with src.
X
X      dst_len:  length of dst, if USE_EOS, then dst is '\0' terminated.
X
X         type:  flag indicating what type of match to make (may
X                be or'ed together).   Bit values:
X                    0 - if set case is not important
X                    1 - if set allow src_len < dst_len
X-*/
X{
X#ifndef USE_EOS
X#define USE_EOS -1
X#endif
X
X   if (src_len == USE_EOS)
X      src_len = strlen(src);
X   if (dst_len == USE_EOS)
X      dst_len = strlen(dst);
X
X   if (!(type & 2) && (src_len != dst_len))
X      return (0);                        /* No match by length */
X
X   if (type & 1) {
X      while (src_len-- > 0) {
X         if (_tolower(*src) != _tolower(*dst))
X            return(0);
X         src++;
X         dst++;
X      }
X   }
X   else {
X      while (src_len-- > 0) {
X         if (*src != *dst)
X            return(0);
X         src++;
X         dst++;
X      }
X   }
X   return (1);                          /* Strings matched. */
X}
X
X
Xint str_to_integer (str, len, val)
Xchar *str;
Xint len, *val;
X/*-
X   Routine to convert a string to an integer, if the string has
X   characters other than {0123456789} in it a 0 will be returned,
X   otherwise a 1 is returned.
X
X   Parameters:
X
X          str:  Character string to convert (may or may not be '\0'
X                terminated).
X
X          len:  Length of character string.
X
X          val:  Pointer to an integer to store the value of the string.
X-*/
X{
X   int i=0;
X
X   if (i >=len) return (0);              /* String over before it began. */
X
X   for (*val = 0; i < len; i++) {
X      if (!isdigit(str[i])) return(0);   /* Bad character in string. */
X      *val = *val * 10 + str[i] - '0';
X   }
X   return (1);                           /* Made it through the string. */
X}
X
X
Xint user_command()
X/*-
X   Routine to prompt the user for next action (help, write, skip, more
X   or quit).  Help is handled locally.  The return values are as follows:
X      More   1
X      Write  2
X      Skip   3
X      Quit   4
X-*/
X{
X   char buf[100];
X   int done = 0;
X
X   while (!done) {
X      printf ("Command (Help, Write, Skip, More, Quit)? ");
X      gets (buf);
X
X      if (str_match (buf, -1, "help", -1, 3)) {
X         printf ("\n\n%s\n%s\n%s\n%s\n%s\n\n",
X"  Help\t-  show this message;",
X"  Write\t-  write the current file (save to disk) and go on to the next;",
X"  Skip\t-  skip this file (don't save to disk);",
X"  More\t-  show some more of this file (before making a decision);",
X"  Quit\t-  discard current file and terminate session (done).");
X      }
X      else if (str_match (buf, -1, "more", -1, 3)) {
X         done = 1;
X      }
X      else if (str_match (buf, -1, "write", -1, 3)) {
X         done = 2;
X      }
X      else if (str_match (buf, -1, "skip", -1, 3)) {
X         done = 3;
X      }
X      else if (str_match (buf, -1, "quit", -1, 3)) {
X         printf("\n%s\n%s",
V"Quit aborts the session.  The current file will be lost; the tape will remain"
X,
X"at its current position.  Is this what you want to do (Yes or No)? ");
X         gets (buf);
X         if (str_match (buf, -1, "yes", -1, 3)) {
X            done = 4;
X         }
X      }
X      else
X         printf ("\nUnknown selection, try again\n");
X   }
X   return done;
X}
X
X
Xint wildcmp (wilds, lwilds, name, lname)
Xchar *wilds, *name;
Xint lwilds, lname;
X/*-
X   Routine to compare two strings, allowing the first to contain '*' or
X   '%' wild cards.  Returns 1 if equal, 0 if not.
X
X   Parameters:
X
X        wilds:  Wild-card string.
X
X       lwilds:  Length of wild-card string, if -1 then assume string is '\0'
X                terminated.
X
X         name:  Name to match against wild-card string.
X
X        lname:  Length of name string, if -1 assume '\0' terminated.
X-*/
X{
X   int wflag = 0;
X
X   if (lwilds == -1) lwilds = strlen(wilds);
X   if (lname  == -1) lname  = strlen(name);
X
X   if (lwilds <= 0 || lname <= 0)
X      return 0;
X
X   while (lname > 0) {
X      while (*wilds == '*' && lwilds-- > 0) {
X         wflag = 1;
X         ++wilds;
X      }
X      if (wflag == 1) {
X         if (lwilds <= 0)
X            return 1;                       /* End of pattern is '*' */
X      /* "Absorb" characters until next match. */
X         while (*name != *wilds && lname-- > 0)
X            ++name;
X         if (lname <= 0)
X            return 0;                       /* Tail char not found. */
X         wflag = 0;
X      }
X      else if (*wilds != '%' && *wilds != *name)
X         return 0;                          /* Mismatched character. */
X
X  /* Position for next character comparison. */
X      ++wilds;
X      --lwilds;
X      ++name;
X      --lname;
X   }
X/* Gobble any left-over tail wild-cards in case they terminate the string. */
X   while (*wilds == '*' && lwilds-- > 0)
X      ++wilds;
X
X/* See if both reached end at the same time. */
X   if (lwilds > 0 || lname > 0)
X      return 0;
X   else
X      return 1;
X}
X
X
Xyyerror (s)
Xchar *s;
X/*-
X   Parser routine to print an error and die.  Both the parser and user
X   routines may make use of this utility.
X-*/
X{
X   fprintf (stderr, "%s\n", s);
X   exit(1);
X}
X
X
Xyylex()
X/*-
X   Read tokens off the "tape" so that the parser can "see" what records
X   of the tape are being used in the input stream.
X-*/
X{
X   static int first = 1;
X   int status, ret_val;
X   status_block iosb;
X   $DESCRIPTOR(src_desc, in_line);
X   $DESCRIPTOR(dst_desc, out_line);
X   $DESCRIPTOR(fill_desc, "``");
X   struct dsc$descriptor t_desc;
X
X   if (eof_flag)
X      return EOF;
X
-+-+-+-+-+ End of part 3 +-+-+-+-+-
-- 
	John Campbell               ...!arizona!naucse!jdc

	unix?  Sure send me a dozen, all different colors.

