[comp.sys.amiga] MsgPorts, DOS, ACTION_SCREEN_MODE help needed

NU105451@NDSUVM1.BITNET (Walter Reed) (10/19/87)

I am working on a version of MicroEmacs that would support either opening
a new window or useing the current window and setting its mode to RAW.
My problem is that I don't know how to get a processes message port.
I have the original RKM's (1985 edition) and they offer no help to this
particular subject.  I did locate in the dos tech ref manual the structures
on file handles (which i find out from Input() & Output()) and can find
the processID but I can't find ANY info on how to find a msgport when you
know the file handle.
Can anyone offer any help on the subject?
     Thanks,
            Walter Reed
     

bryce@hoser.berkeley.edu (Bryce Nesbitt) (10/20/87)

In article <378NU105451@NDSUVM1> NU105451@NDSUVM1.BITNET (Walter Reed) writes:
>I am working on a version of MicroEmacs that would support either opening
>a new window or useing the current window and setting its mode to RAW.
>My problem is that I don't know how to get a processes message port...

Here's a wish that Commodore would distribute AmigaMail free, in electronic
form a few months after the paper version.

>I did locate in the dos tech ref manual the structures
>on file handles (which i find out from Input() & Output()) and can find
>the processID but I can't find ANY info on how to find a msgport when you
>know the file handle.

You were "oh soo close".   The MsgPort of a CON: or RAW: window is stored
in the fh_Type field of the FileHandle.  You could have learned this by
reading the libraries/dosextens.h include file.

There are three general ways of finding a msgport to send packets to:

1. If it is CON: or RAW: Extract it from a filehandle.  It's in the fh_Type
   field.  Don't forget that file handles are, you guessed it, BPTRs!  You
   need some wild and wooly code like:
theport = (struct MsgPort *)( ((struct FileHandle *)(myhandle<<2))->fh_type );

2. Use DeviceProc("XXX:"), use for devices such as DF0: or RAM:.  Not valid
   for CON: or RAW: since each invocation of those gets a new handler and
   associated port.... "CON:" alone is not unique.

3. Look at pr_ConsoleTask.  This will find the console handler for your
   CLI window, only if indeed you happen to have been run from the CLI.

ACTION_SCREEN_MODE is 994L  and takes a single argument, -1L for RAW:
and 0L for CON:.  You will normally send this to your process's
pr_ConsoleTask, after verifying that you were started from a CLI.
argc will be zero for programs started from the Workbench, or you
can check the pr_CLI field in your Process structure.  It will be zero
for Workbench spawns.  Don't use it in this case!

You may also want to know about CSI ?7l and CSI ?7h.  These turn on and
off the auto-wrap at the end of lines.  And CSI 20l and CSI 20h.  These turn
off and on LF to CR/LF translation.


(use FindTask(0L) to get a pointer to your Process, use that to access
pr_ConsoleTask and pr_CLI.  Read all about the Process structure in the
include file libraries/dosextens.h)

|\ /|  . Ack! (NAK, SOH, EOT)
{o O} . bryce@hoser.berkeley.EDU -or- ucbvax!hoser!bryce
 (") 	The CBS nightly news:
  U	Dan Rather, paraphrased: "Mr. Analyst, do you think we will continue
	to see a drop in the market like today's?"
	Market Analyst: "Well, that can only happen for three more days."	

higgin@cbmvax.UUCP (Paul Higginbottom SALES) (10/20/87)

in article <378NU105451@NDSUVM1>, NU105451@NDSUVM1.BITNET (Walter Reed) says:
> I am working on a version of MicroEmacs that would support either opening
> a new window or useing the current window and setting its mode to RAW.
> My problem is that I don't know how to get a processes message port.
> I have the original RKM's (1985 edition) and they offer no help to this
> particular subject.  I did locate in the dos tech ref manual the structures
> on file handles (which i find out from Input() & Output()) and can find
> the processID but I can't find ANY info on how to find a msgport when you
> know the file handle.
> Can anyone offer any help on the subject?
>      Thanks,
>             Walter Reed

It's real ugly.  First of all pointers to file handle structures are
not what they seem.  They're BCPL'ised so you'll have to monkey with it
to access the real fields.  Plus, the fields defined in the DOS include
file don't seem to match the documentation, and I think it's the
fh_Type field that is in fact the Process ID in the handle.

So you need to do:

	struct FileHandle *realfh;
	struct Process *proc;

	/* will the real file handle please stand forward */
	realfh = (struct FileHandle *)((ULONG)fh << 2);
	proc = realfh->fh_Type;

This may have mistakes ... I don't have my source handy.

Manx 3.4a by the way, has set_raw() or something like it which does
the whole job.  Secondly, you don't need to get process id's from
the Input() returned filehandle, just use your own... i.e:

	extern struct Task *FindTask();

	struct Process *me;

	me = (struct Process *)FindTask(NULL);
	dos_packet(me->pr_ConsoleTask, ACTION_SCREEN_MODE, -1L);

Or something similar.

	Paul.


Disclaimer: the above could be complete baloney.

cmcmanis%pepper@Sun.COM (Chuck McManis) (10/20/87)

In article <378NU105451@NDSUVM1> NU105451@NDSUVM1.BITNET (Walter Reed) writes:
>I am working on a version of MicroEmacs that would support either opening
>a new window or useing the current window and setting its mode to RAW.

The following code I cooked up (pun intended) to emulate the curses functions
for putting the console into raw() or cooked() (they call it noraw()) modes.
Note that it depends on knowing how the structure FILE * stores the internal
amiga file handle. So this version will only work with the Lattice C compiler
If someone would port it to Aztec C and post it that would be appreciated. 
Anyway, it's short so I'll include it here. It's a shar file so cut off the 
message and feed it to the unix shell, or the Amiga shar program (shar -u) 
available on one of the Fish disks. Don't forget to remove the signature at 
the end of the message.

--Chuck

#       This is a shell archive.
#       Remove everything above and including the cut line.
#       Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:    Shell Archiver
#       Run the following text with /bin/sh to create:
#       testraw.c
#       raw.c
#       sendpacket.c
# This archive created: Tue Jun 16 01:47:01 1987
cat << \SHAR_EOF > testraw.c
/*
 *       testraw.c
 *
 *   This program shows how to use the functions raw() and cooked() to
 * control the way characters are read from a Level 2 file pointer.
 * These are only useful if the file pointer points at an instance of
 * the console.device, which means one of 'stdin', 'stdout', or 'stderr'
 * or a console opened with fp = fopen("CON:x/y/wid/len/Title","w+");
 * like this example does. 
 *
 * Written : 16-Jun-87 By Chuck McManis, do with it what you will.
 *
 */

#include <stdio.h>
#ifndef u_char
#define u_char  unsigned char
#endif

void main()
 
{
  FILE  *win;
  char  c;
  long  i;

  printf("This program shows how to use raw mode file pointers.\n");
  printf("First we open the window...\n");
  win = fopen("CON:10/10/400/100/Test Console","w+");
  setnbf(win); /* This is IMPORTANT, set file pointer to 'unbuffered' */
  fprintf(win,"Using the default mode, type some characters ... \n");  
  i = 0;
  while ((c = fgetc(win)) != 'Q') {
    i = (i + 1) % 25;
    if (i == 0) printf("\n");
    printf(" %02x",(u_char) c);
  }
  printf("\n************\n");
  fprintf(win,"Now switching to 'raw' mode ...\n");
  if (raw(win) != 0) perror("raw");
  i = 0;
  while ((c = fgetc(win)) != 'Q') {
    i = (i + 1) % 25;
    if (i == 0) printf("\n");
    printf(" %02x",(u_char) c);
  }
  printf("\n************\n");
  fprintf(win,"Now back to 'cooked' mode ... \n");
  if (cooked(win) != 0) perror("cooked");
  i = 0;
  while ((c = fgetc(win)) != 'Q') {
    i = (i + 1) % 25;
    if (i == 0) printf("\n");
    printf(" %02x",(u_char) c); 
  }
}
SHAR_EOF
cat << \SHAR_EOF > raw.c 
/* 
 *      raw.c
 *
 *    This is a routine for setting a given stream to raw or cooked mode.
 * This is useful when you are using Lattice C to produce programs that
 * want to read single characters with the "getch()" or "fgetc" call.
 *
 * Written : 18-Jun-87 By Chuck McManis. 
 *           If you use it I would appreciate credit for it somewhere.
 */
#include <exec/types.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <stdio.h>
#include <ios1.h>
#include <error.h>

/* New Packet in 1.2 */
#define ACTION_SCREEN_MODE      994L

extern  int     errno;          /* The error variable */
 
/*
 * Function raw() - Convert the specified file pointer to 'raw' mode. This
 * only works on TTY's and essentially keeps DOS from translating keys for
 * you, also (BIG WIN) it means getch() will return immediately rather than
 * wait for a return. You lose editing features though.
 */
long
raw(fp)

FILE *fp;
 
{
  struct MsgPort        *mp; /* The File Handle message port */
  struct FileHandle     *afh;
  struct UFB            *ufb;
  long                  Arg[1],res;

  ufb = (struct UFB *) chkufb(fileno(fp));  /* Step one, get the file handle */
  afh = (struct FileHandle *)(ufb->ufbfh); 

  if (!IsInteractive(afh)) {    /* Step two, check to see if it's a console */
    errno = ENOTTY;
    return(-1);
  }
                              /* Step three, get it's message port. */
  mp  = ((struct FileHandle *)(BADDR(afh)))->fh_Type;
  Arg[0] = -1L;
  res = SendPacket(mp,ACTION_SCREEN_MODE,Arg,1); /* Put it in RAW: mode */
  if (res == 0) {
    errno = ENXIO;
    return(-1);
  }
  return(0);
}
 
/*
 * Function - cooked() this function returns the designate file pointer to
 * it's normal, wait for a <CR> mode. This is exactly like raw() except that
 * it sends a 0 to the console to make it back into a CON: from a RAW:
 */

long
cooked(fp)
 
FILE *fp;
 
{
  struct MsgPort        *mp; /* The File Handle message port */
  struct FileHandle     *afh;
  struct UFB            *ufb;
  long                  Arg[1],res;
 
  ufb = (struct UFB *) chkufb(fileno(fp));
  afh = (struct FileHandle *)(ufb->ufbfh);
  if ( ! IsInteractive(afh)) {
    errno = ENOTTY;
    return(-1);
  }
  mp  = ((struct FileHandle *)(BADDR(afh)))->fh_Type;
  Arg[0] = 0;
  res = SendPacket(mp,ACTION_SCREEN_MODE,Arg,1);
  if (res == 0) {
    errno = ENXIO;
    return(-1);
  }
  return(0);
}
SHAR_EOF
cat << \SHAR_EOF > sendpacket.c
/*
 *      Sendpacket.c 
 *
 *  An invaluable addition to your Amiga.lib file. This code sends a packet
 * the given message port. This makes working around DOS lots easier.
 * 
 * Note, I didn't write this, those wonderful folks at CBM did. I do suggest
 * however that you may wish to add it to Amiga.Lib, to do so, compile it
 * and say 'oml lib:amiga.lib -r sendpacket.o' 
 */

#include <exec/types.h>
#include <exec/ports.h>
#include <exec/memory.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
 
/*
 * Function - SendPacket written by Phil Lindsay, Carolyn Scheppner, and
 * Andy Finkel. This function will send a packet of the given type to the
 * Message Port supplied.
 */
 
long
SendPacket(pid,action,args,nargs)
 
struct MsgPort *pid;  /* process indentifier ... (handlers message port ) */
long action,          /* packet type ... (what you want handler to do )   */
     args[],          /* a pointer to a argument list */
     nargs;           /* number of arguments in list  */
{
  struct MsgPort        *replyport;
  struct StandardPacket *packet;
 
  long  count, *pargs, res1;
 
  replyport = (struct MsgPort *) CreatePort(NULL,0);
  if(!replyport) return(0);
 
  /* Allocate space for a packet, make it public and clear it */
  packet = (struct StandardPacket *) 
    AllocMem((long)sizeof(struct StandardPacket),MEMF_PUBLIC|MEMF_CLEAR);
  if(!packet) {
    DeletePort(replyport);
    return(0);
  }
 
  packet->sp_Msg.mn_Node.ln_Name = (char *)&(packet->sp_Pkt);
  packet->sp_Pkt.dp_Link         = &(packet->sp_Msg);
  packet->sp_Pkt.dp_Port         = replyport;
  packet->sp_Pkt.dp_Type         = action;
 
  /* copy the args into the packet */
  pargs = &(packet->sp_Pkt.dp_Arg1);       /* address of first argument */
  for(count=0;count < nargs;count++) 
    pargs[count]=args[count];
 
  PutMsg(pid,packet); /* send packet */

  WaitPort(replyport);
  GetMsg(replyport); 
 
  res1 = packet->sp_Pkt.dp_Res1;
 
  FreeMem(packet,(long)sizeof(struct StandardPacket));
  DeletePort(replyport); 

  return(res1);
}
SHAR_EOF
#       End of shell archive
exit 0
--Chuck McManis
uucp: {anywhere}!sun!cmcmanis   BIX: cmcmanis  ARPAnet: cmcmanis@sun.com
These opinions are my own and no one elses, but you knew that didn't you.

carolyn@cbmvax.UUCP (10/30/87)

In article <378NU105451@NDSUVM1> NU105451@NDSUVM1.BITNET (Walter Reed) writes:
>I am working on a version of MicroEmacs that would support either opening
>a new window or useing the current window and setting its mode to RAW.
>My problem is that I don't know how to get a processes message port.

   You want the MsgPort ("ProcessID" in BCPLese) of the CON: window.

-----

/* sendpkt code - A. Finkel, P. Lindsay, C. Scheppner  CBM */

LONG setRawCon(toggle)
LONG toggle;     /* DOSTRUE (-1L)  or  DOSFALSE (0L) */
   {
   struct MsgPort *conid;
   struct Process *me;
   LONG myargs[8] ,nargs, res1;

   me = (struct Process *) FindTask(NULL);
   conid = (struct MsgPort *) me->pr_ConsoleTask;

   myargs[0]=toggle;
   nargs = 1;
   res1 = (LONG)sendpkt(conid,ACTION_SCREEN_MODE,myargs,nargs);
   return(res1);
   }


LONG findWindow() /* inits conWindow and conUnit (global vars) */
   {
   struct InfoData *id;
   struct MsgPort  *conid;
   struct Process  *me;
   LONG myargs[8] ,nargs, res1;

   /* Alloc to insure longword alignment */
   id = (struct InfoData *)AllocMem(sizeof(struct InfoData),
                                       MEMF_PUBLIC|MEMF_CLEAR);
   if(! id) return(0);
   me = (struct Process *) FindTask(NULL);
   conid = (struct MsgPort *) me->pr_ConsoleTask;

   myargs[0]=((ULONG)id) >> 2;
   nargs = 1;
   res1 = (LONG)sendpkt(conid,ACTION_DISK_INFO,myargs,nargs);
   conWindow = (struct Window *)id->id_VolumeNode;
   conUnit = (struct ConUnit *)
                 ((struct IOStdReq *)id->id_InUse)->io_Unit;
   FreeMem(id,sizeof(struct InfoData));
   return(res1);
   }


LONG sendpkt(pid,action,args,nargs)
struct MsgPort *pid;  /* process indentifier ... (handlers message port ) */
LONG action,          /* packet type ... (what you want handler to do )   */
     args[],          /* a pointer to a argument list */
     nargs;           /* number of arguments in list  */
   {
   struct MsgPort        *replyport;
   struct StandardPacket *packet;
 
   LONG  count, *pargs, res1;

   replyport = (struct MsgPort *) CreatePort(NULL,0);
   if(!replyport) return(NULL);

   packet = (struct StandardPacket *) 
      AllocMem((long)sizeof(struct StandardPacket),MEMF_PUBLIC|MEMF_CLEAR);
   if(!packet) 
      {
      DeletePort(replyport);
      return(NULL);
      }

   packet->sp_Msg.mn_Node.ln_Name = (char *)&(packet->sp_Pkt);
   packet->sp_Pkt.dp_Link         = &(packet->sp_Msg);
   packet->sp_Pkt.dp_Port         = replyport;
   packet->sp_Pkt.dp_Type         = action;

   /* copy the args into the packet */
   pargs = &(packet->sp_Pkt.dp_Arg1);       /* address of first argument */
   for(count=0;count < nargs;count++) 
      pargs[count]=args[count];
 
   PutMsg(pid,packet); /* send packet */

   WaitPort(replyport);
   GetMsg(replyport); 

   res1 = packet->sp_Pkt.dp_Res1;

   FreeMem(packet,(long)sizeof(struct StandardPacket));
   DeletePort(replyport); 

   return(res1);
   }

/* end */


-- 
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Carolyn Scheppner -- CATS   >>Commodore Amiga Technical Support<<
                     UUCP  ...{allegra,ihnp4,rutgers}!cbmvax!carolyn 
                     PHONE 215-431-9180
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=