[vox-tech] a better scanf?? (C-programming question)

Mike Simons vox-tech@lists.lugod.org
Fri, 18 Apr 2003 18:07:34 -0400


--sXc4Kmr5FA7axrvy
Content-Type: multipart/mixed; boundary="t0UkRYy7tHLRMCai"
Content-Disposition: inline


--t0UkRYy7tHLRMCai
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

On Fri, Apr 18, 2003 at 04:48:50AM -0700, Andy Campbell wrote:
> >   Non-blocking with select/poll/busy-looping, reading into a
> > buffer, followed by sscanf when a return key is found will certainly
> > handle the second case... examples if that's what you want.
>=20
> I am trying to implement this but am unsuccessfull. Could you show me whe=
re=20
> some examples are?? Thank you!!

Andy,

  Attached is a very simple command line interactive program... it's just
an example.  It does non-blocking IO with stdin, parses complete lines
when they are found with sscanf.  It accepts input from users or files (if=
=20
stdin is redirected from a file).  This program uses standard cooked
input mode, so all the nice line editing keys (^W, backspace, ^U, ^C,
etc) work...

sample run:
=3D=3D=3D
msimons@salomon:~$ ./a.out=20
blah
don't understand line: "blah"
set foo=3D123;
gotcha: store 123 into variable "foo"
set foo=3Dbar;
don't understand line: "set foo=3Dbar;"
set foo=3D123; junk
gotcha: store 123 into variable "foo"
garbage after command: " junk"
quit;
quitting soon
msimons@salomon:~$
=3D=3D=3D

  In this code I set TIMEOUT high... because I have nothing to do
besides wait for use input, if you are doing some CPU bound stuff that
you want to check for user commands sometimes you would want to change
timeout to 0, and call this poll code once per major CPU loop...
  for user-interactiveness reasons, if you are doing CPU bound things=20
you should probably be using threads, one to watch for use input.

    Good Luck,
      Mike

--
GPG key: http://simons-clan.com/~msimons/gpg/msimons.asc
Fingerprint: 524D A726 77CB 62C9 4D56  8109 E10C 249F B7FA ACBE

--t0UkRYy7tHLRMCai
Content-Type: text/x-csrc; charset=us-ascii
Content-Disposition: attachment; filename="poll1.c"
Content-Transfer-Encoding: quoted-printable

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/poll.h>
#include <unistd.h>

/* size of user command buffer */
#define BUFFER_SIZE 4096

/* time to wait at poll call for data...=20
   FIXME: you may want 0 here,=20
especially if doing other things that don't use poll to trigger,
like calculations in the background... */
#define TIMEOUT 1000000

int main(void)
{
  int file =3D fileno(stdin);                         /* file number of std=
in */
  int result;                                      /* return code from poll=
 */
  struct pollfd pd[] =3D { { file, POLLIN, 0 } };            /* data for po=
ll */

  char buffer[BUFFER_SIZE];                        /* buffer for user input=
 */
  char *end =3D buffer;                         /* last position that is fu=
ll */

  int done =3D 0;                                         /* loop should st=
op */
  int error =3D 0;                                     /* some error happen=
ed */

  while (!done && !error)
  { /* looping time */
    if (((result =3D poll(pd, 1, TIMEOUT)) > 0))
    { /* have data to read */
      if (pd[0].revents =3D=3D POLLHUP)
        fprintf(stderr, "%s:%d %s warning: "
                "End of file reached with no 'quit' command\n",
          __FILE__, __LINE__, __FUNCTION__),
        error =3D 2;
      else if (pd[0].revents !=3D POLLIN)
        fprintf(stderr, "%s:%d %s warning: "
                "Unexpected poll result returned 0x%04X, "
                "expected one of 0x%04X\n",
          __FILE__, __LINE__, __FUNCTION__, pd[0].revents, pd[0].events),
        error =3D 2;
      else
      { /* poll result expected, read some data */
        int size;

        if ((size =3D read(file, end, sizeof(buffer) - (end - buffer))) <=
=3D 0)
        { /* read failed some how */
          if ((size =3D=3D -1) && (errno !=3D EINTR))
            fprintf(stderr, "%s:%d %s error: "
                    "While reading, %d: %s\n",
              __FILE__, __LINE__, __FUNCTION__, errno, strerror(errno)),
            error =3D 1;
          else if (size =3D=3D 0)
            fprintf(stderr, "%s:%d %s warning: "
                   "End of file reached with no 'quit' command\n",
              __FILE__, __LINE__, __FUNCTION__),
            error =3D 2;
        =20
          done =3D 1;
        }
        else
        { /* read is good, check for more commands */
          char *last;                   /* last character of this data line=
 */
          char *offset =3D buffer;        /* first chracter of this data li=
ne */

          end +=3D size;                           /* increment stop positi=
on */
  =20
          while ((last =3D memchr(offset, '\n', end - offset)))
          { /* found a newline */
            int status =3D 0;
            int var;
            int start;
            int stop;
  =20
            *last =3D '\0';                            /* null terminate li=
ne */
           =20
            if ((sscanf(offset, "quit;%n", &status) =3D=3D 0) && status)
              printf("quitting soon\n"), done =3D 1;
            else if ((sscanf(offset, "set %n%*[^=3D]%n=3D%d;%n",=20
                     &start, &stop, &var, &status) =3D=3D 1) && status)
              printf("gotcha: store %d into variable \"%.*s\"\n",=20
                     var, stop - start, offset + start);

            if ((status) && (status !=3D (last - offset)))
            /* could use 'status' to check for more commands on this line */
              printf("garbage after command: \"%.*s\"\n",=20
                     last - offset - status, offset + status);
            else if (!status)
              printf("don't understand line: \"%.*s\"\n",=20
                     last - offset, offset);

            offset =3D last + 1;
          }

          if (offset !=3D buffer)
          {
            memcpy(buffer, offset, end - offset);
            end -=3D offset - buffer;
          }
          else if (end =3D=3D (buffer + sizeof(buffer)))
            fprintf(stderr, "%s:%d %s error: "
                    "Comamnd line too long can't be more than %d bytes\n",
              __FILE__, __LINE__, __FUNCTION__, sizeof(buffer)),
            error =3D 2;
        }
      }
    }
  }

  return error;
}

#if 0
  if (fcntl(file, F_SETFL, O_NONBLOCK, 1))
  { /* setting non-blocking mode failed */
    fprintf(stderr, "%s:%d %s error: "
            "Failed to set non-blocking on stdin, %d: %s\n",
            __FILE__, __LINE__, __FUNCTION__, errno, strerror(errno));
    return 1;
  }
#endif


--t0UkRYy7tHLRMCai--

--sXc4Kmr5FA7axrvy
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.6 (GNU/Linux)
Comment: For info see http://www.gnupg.org

iD8DBQE+oHcm4Qwkn7f6rL4RAtu3AJ96GvN6oxWRXaMwEZRI1phdSU0ZDQCeMxW7
tffJGbRaDq11tsfX01alq+s=
=pK5u
-----END PGP SIGNATURE-----

--sXc4Kmr5FA7axrvy--