/* $Revision Header *** Header built automatically - do not edit! *********** * * (C) Copyright 1990 by MXM * * Name .....: Print-Handler.c * Created ..: Wednesday 11-Apr-90 09:51 * Revision .: 6 * * Date Author Comment * ========= ======== ==================== * 11-Apr-90 Olsen Created this file! * **************************************************************************** * * Notez-bien: This version of Print-Handler will only compile under * Aztec 'C' 5.0. Some effort must be taken to adapt it * for Lattice 'C' 5.0. * * I've left all my debugs in and commented them out. This should * compile fine now. * * $Revision Header ********************************************************/ /* Function prototypes (no includes this time). */ struct DataSeg * CreateSeg(APTR,LONG); struct DataSeg * DeleteSeg(struct DataSeg *); VOID ReturnPacket(struct DosPacket *,ULONG,ULONG); struct DosPacket * TaskWait(VOID); LONG PrintIt(APTR,LONG); LONG PrintData(UBYTE *,LONG,struct PopSupport *); VOID * SendCustomMsg(LONG); VOID QueueEntryPoint(VOID); LONG _main(VOID); /* This structure is used to hold a fragment of the file to * be printed. */ struct DataSeg { struct DataSeg *NextSeg; APTR Buffer; LONG Length; }; /* Shared library structures. */ struct IntuitionBase *IntuitionBase; struct MXMBase *MXMBase; /*struct Library *FarBase;*/ extern struct ExecBase *SysBase; /* This is the maximum length of a printer line. */ #define MAXPRINT 1024 /* This is the maximum number of available slots. */ #define MAXSLOT 128 /* Handshake signal. */ #define SIG_SHAKE SIGBREAKF_CTRL_D /* Some more global data. */ struct Preferences *Preferences; struct IOStdReq *PrinterDevice; struct Process *QueueProc; struct Process *HandlerProc; struct DataSeg *DataSegs[MAXSLOT]; UBYTE Available[MAXSLOT]; UBYTE LineStack[MAXPRINT]; /* Working stats for the printer process. */ LONG LinesDone = 0,ColumnsDone = 0; /* _main(): * * This is the main entry point to the handler * process. */ LONG _main() { struct DosPacket *PrintPacket; struct DeviceNode *PrintNode; LONG OpenCount = 0,i; /* Mark all buffers as vacant. */ memset(Available,TRUE,MAXSLOT); HandlerProc = (struct Process *)SysBase -> ThisTask; /* Started from CLI? */ if(HandlerProc -> pr_CLI) return(-1); /* Wait for parameter packet. */ PrintPacket = TaskWait(); /* Pointer to our own DeviceNode. */ PrintNode = (struct DeviceNode *)BADDR(PrintPacket -> dp_Arg3); /* Open mxm.library. */ if(!(MXMBase = (struct MXMBase *)OpenLibrary("mxm.library",34))) { ReturnPacket(PrintPacket,DOSFALSE,PrintPacket -> dp_Res2); goto FallOff; } /* if(!(FarBase = OpenLibrary("farprint.library",0)))*/ /* {*/ /* ReturnPacket(PrintPacket,DOSFALSE,PrintPacket -> dp_Res2);*/ /* goto FallOff;*/ /* }*/ /* Extract global library vector. */ IntuitionBase = (struct IntuitionBase *)MXMBase -> IntuitionBase; /* Create the printer process. */ if(!(QueueProc = CreateFuncProc("Print-Handler.queue",10,QueueEntryPoint,4096))) { ReturnPacket(PrintPacket,DOSFALSE,PrintPacket -> dp_Res2); goto FallOff; } /* Wait for a reply. */ Wait(SIG_SHAKE); /* Process quietly removed itself. */ if(!QueueProc) { ReturnPacket(PrintPacket,DOSFALSE,PrintPacket -> dp_Res2); goto FallOff; } /* We're on the scene now. */ PrintNode -> dn_Task = &HandlerProc -> pr_MsgPort; /* Return the compliment. */ ReturnPacket(PrintPacket,DOSTRUE,PrintPacket -> dp_Res2); /* Go into loop. */ for(;;) { /* Wait for the packet. */ /* SendText("TaskWait");*/ PrintPacket = TaskWait(); /* SendText("Type = %ld",PrintPacket -> dp_Type);*/ switch(PrintPacket -> dp_Type) { /* Somebody Open()ed us. */ case ACTION_FINDINPUT: case ACTION_FINDOUTPUT: case ACTION_FINDUPDATE: { struct FileHandle *FileHandle = (struct FileHandle *)BADDR(PrintPacket -> dp_Arg1); /* SendText("Open");*/ /* Assume failure. */ FileHandle -> fh_Port = DOSFALSE; /* Look for an empty buffer. */ for(i = 0 ; i < MAXSLOT ; i++) { if(Available[i]) { FileHandle -> fh_Port = (struct MsgPort *)DOSTRUE; FileHandle -> fh_Arg1 = i; Available[i] = FALSE; /* SendText("Clean open! -> %ld.",i);*/ OpenCount++; break; } } ReturnPacket(PrintPacket,(LONG)FileHandle -> fh_Port,PrintPacket -> dp_Res2); break; } /* A FileHandle got closed. */ case ACTION_END: { OpenCount--; /* SendText("Close -> %ld",PrintPacket -> dp_Arg1);*/ SendCustomMsg(PrintPacket -> dp_Arg1); ReturnPacket(PrintPacket,DOSTRUE,PrintPacket -> dp_Res2); break; } /* We always read *nothing*. */ case ACTION_READ: { /* SendText("Read -> %ld",PrintPacket -> dp_Arg1);*/ ReturnPacket(PrintPacket,NULL,PrintPacket -> dp_Res2); break; } /* Something gets written to a FileHandle. */ case ACTION_WRITE: { char *Buffer = (char *)PrintPacket -> dp_Arg2; struct DataSeg *NextSlot; /* SendText("Write -> %ld Bytes %ld Buffer %lx",PrintPacket -> dp_Arg1,PrintPacket -> dp_Arg3,Buffer);*/ PrintPacket -> dp_Res1 = PrintPacket -> dp_Arg3; /* Add the new data. */ if(!DataSegs[PrintPacket -> dp_Arg1]) { if(!(DataSegs[PrintPacket -> dp_Arg1] = CreateSeg((APTR)Buffer,PrintPacket -> dp_Arg3))) { PrintPacket -> dp_Res2 = ERROR_NO_FREE_STORE; PrintPacket -> dp_Res1 = 0; } /* else*/ /* SendText("Created.");*/ } else { NextSlot = DataSegs[PrintPacket -> dp_Arg1]; while(NextSlot -> NextSeg) NextSlot = NextSlot -> NextSeg; if(!(NextSlot -> NextSeg = CreateSeg((APTR)Buffer,PrintPacket -> dp_Arg3))) { PrintPacket -> dp_Res2 = ERROR_NO_FREE_STORE; PrintPacket -> dp_Res1 = 0; } /* else*/ /* SendText("Appended.");*/ } ReturnPacket(PrintPacket,PrintPacket -> dp_Res1,PrintPacket -> dp_Res2); break; } /* We are to leave the town. */ case ACTION_DIE: { ReturnPacket(PrintPacket,DOSTRUE,0); goto FallOff; } /* Say what? */ default: { ReturnPacket(PrintPacket,DOSFALSE,ERROR_ACTION_NOT_KNOWN); break; } } } FallOff:PrintNode -> dn_Task = NULL; /* SendText("FallOff");*/ /* Tell printer process to shut down. */ if(QueueProc) { SendCustomMsg(-1); /* SendText("Handshake...");*/ Wait(SIG_SHAKE); } /* SendText("Close mxm");*/ /* Close the library. */ if(MXMBase) CloseLibrary((struct Library *)MXMBase); /* SendText("Close far");*/ /* if(FarBase)*/ /* CloseLibrary(FarBase);*/ } /* SendCustomMsg(Slot): * * Send a message to the printer process. */ VOID * SendCustomMsg(Slot) LONG Slot; { struct Message *TempMsg = (struct Message *)AllocRem(sizeof(struct Message),MEMF_PUBLIC | MEMF_CLEAR); if(TempMsg) { TempMsg -> mn_Node . ln_Name = (char *)Slot; TempMsg -> mn_ReplyPort = NULL; TempMsg -> mn_Length = sizeof(struct Message); /* SendText("SendCustomMsg -> %ld",Slot);*/ PutMsg(&QueueProc -> pr_MsgPort,TempMsg); } return((VOID *)TempMsg); } /* QueueEntryPoint(): * * The printer process. This revision now send the data * to be printed to the process rather than to process * the data itself. This saves some amount of time when * calling processes send their files while the printer * is still busy. */ VOID QueueEntryPoint() { struct MsgPort *PrinterPort; struct Message *QueueMsg; LONG GoOn,Slot,i; struct PopSupport PopSupport; geta4(); /* We want the error pop-ups to beep. */ PopSupport . ps_Flags = PS_BEEP; PopSupport . ps_TimeOut = 0; /* Open everything this process needs. */ if(!(PrinterPort = (struct MsgPort *)CreatePort(NULL,0))) goto FallOff; if(!(PrinterDevice = (struct IOStdReq *)CreateStdIO(PrinterPort))) goto FallOff; if(OpenDevice("printer.device",0,PrinterDevice,0)) goto FallOff; Preferences = &((struct PrinterData *)PrinterDevice -> io_Device) -> pd_Preferences; /* We're running. */ Signal((struct Task *)HandlerProc,SIG_SHAKE); /* SendText("Process running.");*/ /* Go into infinite loop. */ FOREVER { WaitPort(&QueueProc -> pr_MsgPort); while(QueueMsg = GetMsg(&QueueProc -> pr_MsgPort)) { GoOn = TRUE; if((Slot = (LONG)QueueMsg -> mn_Node . ln_Name) != -1) { /* SendText("Slot %ld",Slot);*/ while(DataSegs[Slot]) { if(GoOn) { if(!PrintData((UBYTE *)DataSegs[Slot] -> Buffer,DataSegs[Slot] -> Length,&PopSupport)) GoOn = FALSE; } DataSegs[Slot] = DeleteSeg(DataSegs[Slot]); } /* New: produce a working formfeed if last page * wasn't 100% occupied. */ if(Preferences -> PaperType == SINGLE && LinesDone < Preferences -> PaperLength) { LONG ToDo = Preferences -> PaperLength - LinesDone; for(i = 0 ; i < ToDo ; i++) PrintIt((APTR)"\n",1); } GoOn = TRUE; Available[Slot] = TRUE; } else GoOn = FALSE; FreeRem(QueueMsg); LinesDone = ColumnsDone = 0; if(!GoOn) goto FallOff; } } FallOff:if(PrinterDevice) { /* SendText("CloseDevice");*/ if(PrinterDevice -> io_Device) CloseDevice(PrinterDevice); /* SendText("DeleteStdIO");*/ DeleteStdIO(PrinterDevice); } /* SendText("DeletePort");*/ if(PrinterPort) DeletePort(PrinterPort); Forbid(); Signal((struct Task *)HandlerProc,SIG_SHAKE); QueueProc = NULL; } /* PrintIt(Buffer,Length): * * The real printer interface. */ LONG PrintIt(Buffer,Length) APTR Buffer; LONG Length; { if(Buffer && Length) { LONG Error; PrinterDevice -> io_Command = CMD_WRITE; PrinterDevice -> io_Data = Buffer; PrinterDevice -> io_Length = Length; Error = DoIO(PrinterDevice); return(Error); } return(IOERR_BADLENGTH); } /* PrintData(Buffer,Length,PopSupport): * * This one send the data to the printer. */ LONG PrintData(Buffer,Length,PopSupport) UBYTE *Buffer; LONG Length; struct PopSupport *PopSupport; { LONG i,InBuff = 0,PaperWidth = Preferences -> PrintRightMargin - Preferences -> PrintLeftMargin; /* SendText("Buffer %lx Length %ld",Buffer,Length);*/ memset(LineStack,0,MAXPRINT); if(Buffer) { for(i = 0 ; i < Length ; i++) { LineStack[InBuff++] = Buffer[i]; ColumnsDone++; if(ColumnsDone == PaperWidth || Buffer[i] == '\n') { if(ColumnsDone == PaperWidth || ColumnsDone == MAXPRINT) { LineStack[InBuff++] = '\n'; ColumnsDone++; } LineStack[InBuff] = 0; if(PrintIt((APTR)LineStack,InBuff)) PopRequest(NULL,"Print-Handler Problem:","Error copying text to printer,\nplease check cables and\nsupplies.",NULL,"Continue?",FALSE,PopSupport); if((++LinesDone) == Preferences -> PaperLength) { LinesDone = 0; if(Preferences -> PaperType == SINGLE) { if(!PopRequest(NULL,"Print-Handler Request:","Finished with current page,\nplease insert next sheet of\npaper.","Continue","Abort",TRUE,NULL)) return(FALSE); } } ColumnsDone = InBuff = 0; memset(LineStack,0,MAXPRINT); } } if(InBuff) PrintIt((APTR)LineStack,InBuff); } return(TRUE); } /* CreateSeg(Buffer,Length): * * Create a new data segment. */ struct DataSeg * CreateSeg(Buffer,Length) APTR Buffer; LONG Length; { struct DataSeg *NewSeg; /* SendText("CreateSeg Length %ld",Length);*/ if(NewSeg = (struct DataSeg *)AllocRem(sizeof(struct DataSeg),MEMF_PUBLIC | MEMF_CLEAR)) { if(NewSeg -> Buffer = (APTR)AllocRem(Length,MEMF_PUBLIC | MEMF_CLEAR)) { CopyMem(Buffer,NewSeg -> Buffer,Length); NewSeg -> Length = Length; /* SendText("Buffer %lx",NewSeg -> Buffer);*/ return(NewSeg); } FreeRem(NewSeg); } return(NULL); } /* DeleteSeg(OldSeg): * * Delete a data segment. */ struct DataSeg * DeleteSeg(OldSeg) struct DataSeg *OldSeg; { struct DataSeg *NextSeg = NULL; if(OldSeg) { NextSeg = OldSeg -> NextSeg; if(OldSeg -> Buffer && OldSeg -> Length) { FreeRem(OldSeg -> Buffer); OldSeg -> Buffer = NULL; OldSeg -> Length = 0; } FreeRem(OldSeg); } return(NextSeg); } /* ReturnPacket(Packet,res1,res2): * * Returns a packet to a handler. */ VOID ReturnPacket(Packet,Result1,Result2) struct DosPacket *Packet; ULONG Result1,Result2; { struct MsgPort *ReplyPort = Packet -> dp_Port; /* Fill in the results and fill in the * sender MsgPort. */ Packet -> dp_Res1 = Result1; Packet -> dp_Res2 = Result2; Packet -> dp_Port = &HandlerProc -> pr_MsgPort; /* Link Message & Packet together. */ Packet -> dp_Link -> mn_Node . ln_Name = (char *)Packet; Packet -> dp_Link -> mn_Node . ln_Succ = NULL; Packet -> dp_Link -> mn_Node . ln_Pred = NULL; /* Send the packet... */ PutMsg(ReplyPort,Packet -> dp_Link); } /* TaskWait(): * * Lets the process wait for a DOS-Packet. */ struct DosPacket * TaskWait() { struct Message *PrintMessage; /* Wait for the packet. */ WaitPort(&HandlerProc -> pr_MsgPort); /* Pick it up. */ PrintMessage = (struct Message *)GetMsg(&HandlerProc -> pr_MsgPort); /* Return real pointer. */ return((struct DosPacket *)PrintMessage -> mn_Node . ln_Name); }