Path: utzoo!attcan!uunet!husc6!purdue!i.cc.purdue.edu!j.cc.purdue.edu!ain From: ain@j.cc.purdue.edu (Patrick White) Newsgroups: comp.sources.amiga Subject: printspool (sources) Keywords: printer spooler, printspool Message-ID: <7237@j.cc.purdue.edu> Date: 13 Jun 88 23:00:29 GMT Organization: PUCC Land, USA Lines: 1288 Approved: ain@j.cc.purdue.edu (Patrick White) Submitted by: gagnon@larry.mcrcim.mcgill.edu (Francois Gagnon) Summary: A printer spooler. Poster Boy: Patrick White (ain@j.cc.purdue.edu) Archive Name: sources/amiga/volume5/printspool.s.sh.Z Tested. NOTES: I redid the binaries shar to extract the docs, but didn't touch the sources shar. -- Pat White (co-moderator comp.sources/binaries.amiga) ARPA/UUCP: j.cc.purdue.edu!ain BITNET: PATWHITE@PURCCVM PHONE: (317) 743-8421 U.S. Mail: 320 Brown St. apt. 406, West Lafayette, IN 47906 [How do you get to heaven? Go to Pluto and hang a left.] ======================================== # 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: # makefile # stdefs.h # Print_Spool.h # Print.c # Spool.c # This archive created: Mon Mar 28 21:46:51 1988 # By: Francois Gagnon (CAE Electronics Ltd.) cat << \SHAR_EOF > makefile # # Print_Spool V1.0 27-Mar-88 ) Francois Gagnon # # Options are for Manx Aztec-C V3.6a # makeall : Print Spool Print : Print.o ln Print -lc Spool : Spool.o ln Spool -lc Print.o : Print.c Print_Spool.h cc -E150 +x5 Print Spool.o : Spool.c Print_Spool.h cc Spool SHAR_EOF cat << \SHAR_EOF > stdefs.h /* stdefs.h V1.0.0 27-Mar-1988 ) Frangois Gagnon */ #define local static #define public #define byte unsigned char #define bool byte #define NUL '\0' #define remove unlink #define toupper( c) (islower(c) ? ((c) - ('a'-'A')) : (c)) #define memcpy( d, s, l) movmem( s, d, l) SHAR_EOF cat << \SHAR_EOF > Print_Spool.h /* Print_Spool.h V1.0.0 27-Mar-1988 ) Frangois Gagnon */ /* Copyright ) 1988 Frangois Gagnon, All Rights Reserved. The author does not make any warranty expressed or implied, or assumes any liability or responsiblity for the use of this software. Permission is hereby granted to copy, reproduce, redistribute or otherwise use this software as long as it is for non-profit. This notice and the above copyright notice must remain intact and appear on all copies. Permission is also granted to correct any problems with this software, but modifications and improvements are reserved by the author. */ /*****************************************/ /* Definition of the Command information */ /*****************************************/ #define PS_Insert 11 /* Insert a name in the list */ /* This command inserts a list of names into the print queue. If the */ /* spooler is in the Wait_State, it will go to Exec_State and will */ /* start to print the first file. */ #define PS_Update 12 /* Update names from the list */ /* This command updates the options and flags values of the files that */ /* match the specified pattern. The file being printed will be affected */ /* by this command but the value will only be used if multiple copies */ /* of the file are to be printed. A copy of the modified entries are */ /* sent back to the requesting program. */ #define PS_Remove 13 /* Remove names from the list */ /* This command removes the files that match the specified pattern. The */ /* file being printed will be affected by this command and the affected */ /* entries are sent back to the requesting program. */ #define PS_Report 14 /* Report the names of the list */ /* This command requests that the status of the spooler with a copy of */ /* the print queue be sent to the requesting program. */ #define PS_Return 15 /* Return when all completed */ /* This command toggles the flag indicating wheter the program must */ /* terminate its execution after the last file is printed. It will */ /* normally wait for a new file to print instead of terminating. It is */ /* still possible to modify the print queue even if the flag is set. */ /* Great care nust be taken not to loose messages. */ #define PS_Change 16 /* Change the paper format */ /* This command indicates that the format of the paper has been changed */ /* to the format required for the next file. */ ^L #define PS_Freeze 21 /* Freeze the printing activity */ /* This command requests that the spooler stops printing the current */ /* file immediately and waits for further commands. The printing can be */ /* restarted from the point it was stopped. This command will only be */ /* executed if the spooler is waiting for a file name or printing one. */ /* It will also overide a PS_Finish command by forgeting it was ever */ /* executed. */ #define PS_Finish 22 /* Finish the printing activity */ /* This command requests that the spooler stops after printing the */ /* current file and waits for further commands. This command will */ /* override a PS_Freeze command by resuming the printing. */ #define PS_Resets 23 /* Resets the printing activity */ /* This command requests that the spooler stops printing the current */ /* file immediately and waits for further commands. The File_Copy */ /* counter is not decremented. This command will override the PS_Freeze */ /* command. */ #define PS_Cancel 24 /* Cancel the printing activity */ /* This command requests that the spooler stops printing the current */ /* file immediately and waits for further commands. The File_Copy */ /* counter is decremented as if the file was completed. It will */ /* override the PS_Freeze command. */ #define PS_Resume 25 /* Resume the printing activity */ /* This command restarts the spooler activity after being stopped by */ /* one of the others control commands. The command will also cancel a */ /* PS_Finish which as not yet completed for the current file. */ /*****************************************/ /* Definition of the Options information */ /*****************************************/ #define Line_Density 0x03 /* 10, 12 or 17 chars per inch */ #define Line_Formats 0x04 /* 8 or 13 inches page wide */ #define Page_Density 0x08 /* 6 or 8 lines per inch */ #define Page_Formats 0x10 /* 8.5 or 11 inches page long */ #define Opts_Headers 0x20 /* Add headers to pages */ #define Opts_Numbers 0x40 /* Add numbers to lines */ #define Flag_Quality 0x01 /* Type of char printing */ #define Flag_Deleted 0x02 /* Delete after pinting */ #define Line_10 0x00 /* 10 chars per inch */ #define Line_12 0x01 /* 12 chars per inch */ #define Line_17 0x02 /* 17 chars per inch */ #define Line_8 0x00 /* 8 inchs wide */ #define Line_13 0x04 /* 13 inchs wide */ #define Page_6 0x00 /* 6 lines per inch */ #define Page_8 0x08 /* 8 lines per inch */ #define Page_85 0x00 /* 8.5 inchs long */ #define Page_11 0x10 /* 11 inchs long */ #define Flag_Updated 0x80 /* If update was successful */ #define Flag_Partial 0x80 /* If the result is partial */ ^L /*************************************/ /* Defintion of the File information */ /*************************************/ #define Name_Size 96 /* Maximum number of character */ #define Date_Size 20 /* Exact number of character */ typedef struct Detail_File { struct Detail_File *File_Next; char File_Name[Name_Size]; short File_Copy; byte File_Opts; byte File_Flag; char File_Date[Date_Size]; long File_Size; } File; /*****************************************/ /* Definition of the Spooler information */ /*****************************************/ #define Wait_State 0 /* Waiting for a file to print */ #define Page_State 1 /* Waiting to change the paper */ #define Open_State 2 /* Waiting to access the printer */ #define Exec_State 3 /* Is currently printing a file */ #define File_State 4 /* Will be stopped after the file */ #define Susp_State 5 /* Suspended between two files */ #define Stop_State 6 /* Stopped in the middle of a file */ typedef struct Status_Info { byte Vers_State; /* Current version of spooler */ byte Prog_State; /* Current state of the spooler */ byte Opts_State; /* Current options for printing */ bool Flag_State; /* If must terminate execution */ long Char_Print; /* Number of chars printed */ long Line_Print; /* Number of lines printed */ long Page_Print; /* Number of pages printed */ File *File_Print; /* List of files to print */ } Info; /*************************************/ /* Definition of Control information */ /*************************************/ #define SPOOLNAME "SPOOL" #define PROTOCOL 1 union Details { File *Insert, *Update; char Remove[Name_Size]; Info Status; }; struct Inform { struct Message Packet; short Number, Action; union Details Detail; }; SHAR_EOF cat << \SHAR_EOF > Print.c /* Print.c V1.0.0 27-Mar-88 ) Frangois Gagnon */ /* Copyright ) 1988 Frangois Gagnon, All Rights Reserved. The author does not make any warranty expressed or implied, or assumes any liability or responsiblity for the use of this software. Permission is hereby granted to copy, reproduce, redistribute or otherwise use this software as long as it is for non-profit. This notice and the above copyright notice must remain intact and appear on all copies. Permission is also granted to correct any problems with this software, but modifications and improvements are reserved by the author. */ #include #include #include #include #include #include #include #include #include #include "stdefs.h" #include "Print_Spool.h" /* Declarations of status messages */ local char FIND[] = "\nPrint: Unable to find Spool port.\n\n"; local char PROT[] = "\nPrint: Mismatched protocol versions.\n\n"; local char PORT[] = "\nPrint: Unable to create Print port.\n\n"; local char DATA[] = "\nPrint: Unable to allocate memory.\n\n"; local char EXEC[] = "\nPrint: Unknown or ambiguous command = %s.\n\n"; local char LOCK[] = "\nPrint: File not found = %s.\n\n"; local char TYPE[] = "\nPrint: Wrong file type = %s.\n\n"; local char SIZE[] = "\nPrint: File name too long = %s%s.\n\n"; /* Definition for Execution */ local struct Inform *Print_Data; local struct MsgPort *Spool_Port, *Print_Port; local struct FileInfoBlock *Print_Info; local File *Print_List = NULL, *Print_Last = NULL; local int Print_File = PS_Insert; local int Print_Opts = (Opts_Headers | Opts_Numbers); local int Print_Flag = 0; local int Print_Copy = 1; #define Options( Mask, Opts) (Print_Opts = (Print_Opts & ~Mask) + Opts) ^L /*****************************/ /* Define Available Commands */ /*****************************/ /* Add option commands */ #define PS_CPI10 30 #define PS_CPI12 31 #define PS_CPI17 32 #define PS_LPI6 33 #define PS_LPI8 34 #define PS_NARROW 35 #define PS_WIDE 36 #define PS_SHORT 37 #define PS_LONG 38 #define PS_HEADER 40 #define PS_NUMBER 41 #define PS_KEEP 42 #define PS_DELETE 43 #define PS_DRAFT 44 #define PS_LETTER 45 /* Define the data structure */ #define Print_Size 26 #define Print_Used 7 struct Print_Type { char Name[Print_Used]; byte Code; }; local struct Print_Type Print_Exec[Print_Size] = { { "CANCEL", PS_Cancel }, { "CHANGE", PS_Change }, { "CPI10", PS_CPI10 }, { "CPI12", PS_CPI12 }, { "CPI17", PS_CPI17 }, { "DELETE", PS_DELETE }, { "DRAFT", PS_DRAFT }, { "FINISH", PS_Finish }, { "FREEZE", PS_Freeze }, { "HEADER", PS_HEADER }, { "INSERT", PS_Insert }, { "KEEP", PS_KEEP }, { "LETTER", PS_LETTER }, { "LONG", PS_LONG }, { "LPI6", PS_LPI6 }, { "LPI8", PS_LPI8 }, { "NARROW", PS_NARROW }, { "NUMBER", PS_NUMBER }, { "REMOVE", PS_Remove }, { "REPORT", PS_Report }, { "RESET", PS_Resets }, { "RESUME", PS_Resume }, { "RETURN", PS_Return }, { "SHORT", PS_SHORT }, { "UPDATE", PS_Update }, { "WIDE", PS_WIDE }}; ^L /********************************/ /* Search Allowing Abbreviatoin */ /********************************/ local int Find_Command( Name) /*********************************/ register char Name[]; { register int Length, Result; auto int Test, Next; extern int strncmp(); for (Length = 0; Name[Length] != NUL; ++Length) Name[Length] = toupper( Name[Length]); Next = 1; Result = -1; do /* The name table must be sorted */ { Test = Next; if (++Result == Print_Size) { Next = -1; break; } Next = strncmp( Name, Print_Exec[Result].Name, Length); } while (Test > 0); if ((Test != 0) || (Next == 0)) return 0; return Print_Exec[Result - 1].Code; } ^L /******************************/ /* Initialization of Defaults */ /******************************/ #define INTUITIONNAME "intuition.library" public struct IntuitionBase *IntuitionBase; local void Default_Values() /******************************/ { auto struct Preferences PrefBuffer; auto int Temp; extern struct IntuitionBase *OpenLibrary(); extern struct Preferences *GetPrefs(); /* Fetch the information from the system */ IntuitionBase = OpenLibrary( INTUITIONNAME, 0L); if (IntuitionBase == NULL) return; GetPrefs( &PrefBuffer, (long) sizeof( struct Preferences)); CloseLibrary( IntuitionBase); /* Extract the information from the structure */ if (PrefBuffer.PrintPitch == ELITE) Print_Opts |= Line_12; else if (PrefBuffer.PrintPitch == FINE) Print_Opts |= Line_17; Temp = (PrefBuffer.PrintSpacing == EIGHT_LPI ? 8 : 6); if (PrefBuffer.PrintQuality == LETTER) Print_Flag |= Flag_Quality; if (PrefBuffer.PrintSpacing == EIGHT_LPI) Print_Opts |= Page_8; if (PrefBuffer.PaperSize == W_TRACTOR) Print_Opts |= Line_13; if (PrefBuffer.PaperLength / Temp == 11) Print_Opts |= Page_11; } /****************************/ /* Printing Utility Routine */ /****************************/ local char Value[3][3] = { "10", "12", "17" }; local void Show_File( Info_File) /***********************************/ register File *Info_File; { printf( "%3s%4s%4s%4s%3c%c%c%c%6d %6ld %s\n", Value[Info_File->File_Opts & Line_Density], (Info_File->File_Opts & Line_Formats ? "13" : "8"), (Info_File->File_Opts & Page_Density ? "8" : "6"), (Info_File->File_Opts & Page_Formats ? "11" : "8.5"), (Info_File->File_Opts & Opts_Headers ? 'T' : 'F'), (Info_File->File_Opts & Opts_Numbers ? 'T' : 'F'), (Info_File->File_Flag & Flag_Quality ? 'L' : 'D'), (Info_File->File_Flag & Flag_Deleted ? 'D' : 'K'), Info_File->File_Copy, Info_File->File_Size, Info_File->File_Name); } ^L /*********************************/ /* General Communication Routine */ /*********************************/ local int Request_Action( Action) /*************************************/ int Action; { extern struct MsgPort *FindPort(); extern struct Inform *GetMsg(); /* Prepare the message for sending */ Print_Data->Packet.mn_Node.ln_Type = NT_MESSAGE; Print_Data->Packet.mn_ReplyPort = Print_Port; Print_Data->Number = PROTOCOL; Print_Data->Action = Action; /* Send the request message across */ /* Making sure the port still exist */ Forbid(); if ((Spool_Port = FindPort( SPOOLNAME)) == NULL) { Permit(); fprintf( stderr, FIND); return TRUE; } PutMsg( Spool_Port, Print_Data); Permit(); /* Receive the result message */ do WaitPort( Print_Port); while ((Print_Data = GetMsg( Print_Port)) == NULL); /* Check the protocol version */ if (Print_Data->Number != PROTOCOL) { fprintf( stderr, PROT); return TRUE; } return FALSE; } ^L /*************************************/ /* Request the status of the Spooler */ /*************************************/ local char *State[] = { "\nSpool: Waiting for a file to print.\n", "\nSpool: Waiting for a change of paper.\n", "\nSpool: Waiting to access the printer.\n", "\nSpool: Printing a requested file.\n", "\nSpool: Printing but will pause after the file.\n", "\nSpool: Pausing between two files.\n", "\nSpool: Pausing in the middle of a file.\n" }; local void Request_Report() /******************************/ { register File *File_List, *File_Next; register byte Prog_Info; /* Request the wanted operation */ if (Request_Action( PS_Report)) return; /* Display the status information */ printf( State[Prog_Info = Print_Data->Detail.Status.Prog_State]); if (Print_Data->Detail.Status.Flag_State) printf( "Spool: Set to terminate its execution.\n"); if (Print_Data->Detail.Status.Opts_State & Flag_Partial) printf( "Spool: Partial list of files, unable to allocate memory.\n"); if ((Prog_Info == Exec_State) || (Prog_Info == File_State) || (Prog_Info == Stop_State) ) { printf( "Spool: Printing %ld chars ... %ld lines ... %ld pages.\n", Print_Data->Detail.Status.Char_Print, Print_Data->Detail.Status.Line_Print, Print_Data->Detail.Status.Page_Print); } /* Display the contents of the print queue */ if ((File_List = Print_Data->Detail.Status.File_Print) != NULL) { printf( "\ncpi ipl lpi ipp hnqd copy size report\n"); do { File_List = (File_Next = File_List)->File_Next; Show_File( File_Next); FreeMem( File_Next, (long) sizeof( File)); } while (File_List != NULL); } putchar( '\n'); } ^L /*************************************/ /* Request the removal of some files */ /*************************************/ local void Request_Remove( Name) /***********************************/ char Name[]; { register File *Temp_File, *Temp_Next; strncpy( Print_Data->Detail.Remove, Name, Name_Size); if (Request_Action( PS_Remove)) return; if ((Temp_File = Print_Data->Detail.Insert) != NULL) { printf( "\ncpi ipl lpi ipp hnqd copy size remove\n"); do { Temp_File = (Temp_Next = Temp_File)->File_Next; Show_File( Temp_Next); FreeMem( Temp_Next, (long) sizeof( File)); } while (Temp_File != NULL); } putchar( '\n'); } ^L /**************************************/ /* Perform the specified file request */ /**************************************/ local void Perform() /***********************/ { if (Print_List != NULL) { /* Execute the operation */ if (Print_File == PS_Insert) Print_Data->Detail.Insert = Print_List; if (Print_File == PS_Update) Print_Data->Detail.Update = Print_List; Print_Last->File_Next = NULL; if (Request_Action( Print_File)) { do { Print_List = (Print_Last = Print_List)->File_Next; FreeMem( Print_Last, (long) sizeof( File)); } while (Print_List != NULL); return; } if (Print_File == PS_Insert) Print_List = NULL; if (Print_File == PS_Update) { printf( "\ndone cpi ipl lpi ipp hnqd copy size update\n"); do { Print_List = (Print_Last = Print_List)->File_Next; printf( "%s", (Print_Last->File_Flag & Flag_Updated ? "TRUE " : "FALSE ")); Show_File( Print_Last); FreeMem( Print_Last, (long) sizeof( File)); } while (Print_List != NULL); putchar( '\n'); } } } ^L /*********************************/ /* File Search Utililty Routines */ /*********************************/ local int File_Match( Name, Data) /*************************************/ register char *Name, *Data; { auto char *Save_Name[10], *Save_Data[10]; register int Save; if ((*Data == NUL) || (*Name == NUL)) return FALSE; Save = -1; while ((*Data != NUL) || (*Name != NUL)) { if (*Data == '*') { if (*++Data == NUL) return TRUE; if ( ++Save == 10) return FALSE; Save_Name[Save] = Name; Save_Data[Save] = Data; continue; } if ( ((*Data == '?') && (*Name != NUL)) || (toupper(*Data) == toupper(*Name))) { ++Data; ++Name; continue; } if (*Name == NUL) --Save; if ( Save < 0) return FALSE; Name = ++Save_Name[Save]; Data = Save_Data[Save]; } return TRUE; } ^L local int File_Parent( File_Name, File_Path, File_Size, File_Info) /**********************************************************************/ char *File_Name, *File_Path; int File_Size; struct FileInfoBlock *File_Info; { extern struct FileLock *Lock(), *ParentDir(); auto struct FileLock *File_Lock, *File_Next; register int File_Save, File_Loop; if ((File_Lock = Lock( File_Name, SHARED_LOCK)) == NULL) return 0; File_Path[File_Loop = File_Size - 1] = NUL; do { if (!Examine( File_Lock, File_Info)) { UnLock( File_Lock); return 0; } File_Save = strlen( File_Info->fib_FileName) + 1; if ((File_Loop < File_Save) || (File_Loop < 4)) { UnLock( File_Lock); return -1; } if (File_Save == 1) strcpy( &File_Path[File_Loop - (File_Save = 4)], "RAM"); else strcpy( &File_Path[File_Loop - File_Save], File_Info->fib_FileName); File_Next = ParentDir( File_Lock); UnLock( File_Lock); File_Path[File_Loop - 1] = (File_Next == NULL ? ':' : '/'); File_Lock = File_Next; File_Loop -= File_Save; } while (File_Lock != NULL); if (File_Loop != 0) strcpy( File_Path, &File_Path[File_Loop]); return (File_Size - File_Loop); } ^L /**********************************/ /* Specific File Handling Routine */ /**********************************/ local int File_Insert() /***************************/ { extern void *AllocMem(); extern char *ctime(); register File *Temp_File; auto char *Temp_Date; auto time_t Temp_Time; Temp_File = AllocMem( (long) sizeof(File), MEMF_PUBLIC); if (Temp_File == NULL) { fprintf( stderr, DATA); return TRUE; } Temp_Time = Print_Info->fib_Date.ds_Days * 86400 + Print_Info->fib_Date.ds_Minute * 60 + Print_Info->fib_Date.ds_Tick / TICKS_PER_SECOND; Temp_Date = ctime( &Temp_Time); memcpy( Temp_File->File_Date, &Temp_Date[4], Date_Size); Temp_File->File_Opts = Print_Opts; Temp_File->File_Flag = Print_Flag; Temp_File->File_Copy = Print_Copy; Temp_File->File_Size = Print_Info->fib_Size; if (Print_List == NULL) Print_List = Temp_File; else Print_Last->File_Next = Temp_File; Print_Last = Temp_File; return FALSE; } ^L local void File_Search( Name) /********************************/ char *Name; { extern char *strchr(), *strrchr(); extern struct FileLock *Lock(); auto struct FileLock *File_Lock; auto int File_Size; auto char *File_Name, *File_Char; auto char File_Path[Name_Size]; if ((strchr( Name, '*') == NULL) && (strchr( Name, '?') == NULL)) { /* Take care of simple file name */ File_Size = File_Parent( Name, File_Path, Name_Size, Print_Info); if (File_Size <= 0) { if (File_Size == 0) fprintf( stderr, LOCK, Name); else fprintf( stderr, SIZE, Name, ""); return; } File_Path[File_Size - 2] = NUL; if ((File_Lock = Lock( File_Path, SHARED_LOCK)) == NULL) { fprintf( stderr, LOCK, Name); return; } if (!Examine( File_Lock, Print_Info)) fprintf( stderr, LOCK, Name); else if (Print_Info->fib_DirEntryType >= 0) fprintf( stderr, TYPE, Print_Info->fib_FileName); else if (!File_Insert()) strcpy( Print_Last->File_Name, File_Path); } else { /* Extract the directory part */ if (((File_Name = strrchr( Name, '/')) == NULL) && ((File_Name = strchr( Name, ':')) == NULL) ) File_Name = Name; else memcpy( File_Path, Name, ++File_Name - Name); File_Path[File_Name - Name] = NUL; /* Initialize the search */ File_Size = File_Parent( File_Path, File_Path, Name_Size, Print_Info); if (File_Size <= 0) { if (File_Size == 0) fprintf( stderr, LOCK, Name); else fprintf( stderr, SIZE, Name, ""); return; } if ((File_Lock = Lock( File_Path, SHARED_LOCK)) == NULL) { fprintf( stderr, LOCK, File_Path); return; } ^L if (!Examine( File_Lock, Print_Info)) fprintf( stderr, LOCK, File_Path); else if (Print_Info->fib_DirEntryType < 0) fprintf( stderr, TYPE, Print_Info->fib_FileName); else { /* Search for the matching files */ while (ExNext( File_Lock, Print_Info)) { if ((Print_Info->fib_DirEntryType < 0) && File_Match( Print_Info->fib_FileName, File_Name) ) { if (File_Size + strlen( Print_Info->fib_FileName) > Name_Size) fprintf( stderr, SIZE, File_Path, Print_Info->fib_FileName); else if (!File_Insert()) { strcpy( Print_Last->File_Name, File_Path); strcpy( &Print_Last->File_Name[File_Size - 1], Print_Info->fib_FileName); } } } } } UnLock( File_Lock); } ^L /************************/ /* Execute the Commands */ /************************/ local void Exec_Action( Exec) /********************************/ char Exec[]; { extern int atoi(); auto int Code; if (isdigit( *Exec)) Print_Copy = atoi( Exec); else switch( Code = Find_Command( Exec)) { /* Take care of the options */ case PS_CPI10 : Options( Line_Density, Line_10); break; case PS_CPI12 : Options( Line_Density, Line_12); break; case PS_CPI17 : Options( Line_Density, Line_17); break; case PS_LPI6 : Options( Page_Density, Page_6); break; case PS_LPI8 : Options( Page_Density, Page_8); break; case PS_NARROW : Options( Line_Formats, Line_8); break; case PS_WIDE : Options( Line_Formats, Line_13); break; case PS_SHORT : Options( Page_Formats, Page_85); break; case PS_LONG : Options( Page_Formats, Page_11); break; case PS_HEADER : Print_Opts ^= Opts_Headers; break; case PS_NUMBER : Print_Opts ^= Opts_Numbers; break; case PS_KEEP : Print_Flag &= ~Flag_Deleted; break; case PS_DELETE : Print_Flag |= Flag_Deleted; break; case PS_DRAFT : Print_Flag &= ~Flag_Quality; break; case PS_LETTER : Print_Flag |= Flag_Quality; break; /* Take care of the actions */ case PS_Insert : case PS_Update : case PS_Remove : if (Print_File != Code) Perform(); Print_File = Code; break; case PS_Report : Perform(); Request_Report(); break; case PS_Return : case PS_Change : case PS_Freeze : case PS_Finish : case PS_Resets : case PS_Cancel : case PS_Resume : Perform(); Request_Action( Code); break; /* Take care of unknown commands */ default : fprintf( stderr, EXEC, Exec); break; } } ^L /*****************************/ /* This is the Print program */ /*****************************/ public void main( argc, argv) /*******************************/ int argc; char *argv[]; { extern struct MsgPort *CreatePort(); extern void *AllocMem(); printf( "Print V1.0 27-Mar-88 ) Frangois Gagnon\n"); /* Allocate Initial Structure */ Print_Port = CreatePort( NULL, 0L); if (Print_Port == NULL) { fprintf( stderr, PORT); exit(1); } Print_Data = AllocMem( (long) sizeof(struct Inform), MEMF_PUBLIC); if (Print_Data == NULL) { fprintf( stderr, DATA); goto Abort1; } Print_Info = AllocMem( (long) sizeof(struct FileInfoBlock), MEMF_PUBLIC); if (Print_Info == NULL) { fprintf( stderr, DATA); goto Abort2; } Default_Values(); /* Analyze the given arguments */ if (argc == 1) Request_Report(); else { while (++argv, --argc) { if ((*argv)[0] == '-') Exec_Action( &(*argv)[1]); else if (Print_File == PS_Remove) Request_Remove( *argv); else File_Search( *argv); } if (Print_List != NULL) Perform(); } /* Deallocate Initial Structure */ Abort3: FreeMem( Print_Info, (long) sizeof(struct FileInfoBlock)); Abort2: FreeMem( Print_Data, (long) sizeof(struct Inform)); Abort1: DeletePort( Print_Port); } SHAR_EOF cat << \SHAR_EOF > Spool.c /* Spool.c V1.0.0 27-Mar-88 ) Frangois Gagnon */ /* Copyright ) 1988 Frangois Gagnon, All Rights Reserved. The author does not make any warranty expressed or implied, or assumes any liability or responsiblity for the use of this software. Permission is hereby granted to copy, reproduce, redistribute or otherwise use this software as long as it is for non-profit. This notice and the above copyright notice must remain intact and appear on all copies. Permission is also granted to correct any problems with this software, but modifications and improvements are reserved by the author. */ #include #include #include #include #include #include #include #include "stdefs.h" #include "Print_Spool.h" ^L /*********************************/ /* Local Constants and Variables */ /*********************************/ /* Define constant used in the program */ #define Flag_Test (Line_Formats | Page_Formats) #define Flag_Line (Line_Density | Line_Formats) #define Flag_Page (Page_Density | Page_Formats) #define Flag_Used (Page_Density | Page_Formats | Opts_Headers) #define Opts_Page(Opts) ((Opts & Flag_Page) >> 3) #define Opts_Used(Opts) ((Opts & Flag_Used) >> 3) local int Line_Size[8] = { 80, 96, 132, 80, 136, 164, 232, 136 }; local int Page_Size[4] = { 51, 68, 66, 88 }; local int Page_Used[8] = { 48, 64, 63, 84, 48, 63, 63, 83 }; local char Line_Code[4] = { '0', '2', '4', '0' }; /* Declarations of status messages */ local char HEAD[] = "\nSpool V1.0 27-Mar-88 ) Frangois Gagnon\n\n"; local char LOGS[] = "Spool: Unable to access log file.\n"; local char EXEC[] = "Spool: Spool is already running.\n"; local char INIT[] = "Spool: Unable to create a port.\n"; local char OPEN[] = "Unable to open %s for input.\n"; local char COPY[] = "Printed %s ... %ld chars ... %ld lines ... %ld pages.\n"; local char BACK[] = "Reset %s after %ld chars ... %ld lines ... %ld pages.\n"; local char STOP[] = "Canceled %s after %ld chars ... %ld lines ... %ld pages.\n"; local char MOVE[] = "Removed %s after %ld chars ... %ld lines ... %ld pages.\n"; /* Definition for Execution */ local FILE *Spool_File; local char *Spool_Logs = "RAM:Spool.log"; local struct Inform *Info_Port; local struct MsgPort *Data_Port; local Info Status = { 1, Wait_State, 0, FALSE, 0, 0, 0, NULL }; local FILE *From_File, *Dest_File = NULL; local short Line_Limit, Line_Count; local int Char_Saved; /* Definition for Manipulation */ local File **Temp_Move, *Temp_File; local File **Temp_Skip, *Temp_Test; local byte Temp_Opts; /* Simple typing optimization */ #define Next_Char() { Char_Saved = fgetc( From_File); ++Status.Char_Print; } ^L /******************************/ /* File Name Pattern Matching */ /******************************/ local int File_Match( Name, Data) /*************************************/ register char *Name, *Data; { auto char *Save_Name[10], *Save_Data[10]; register int Save; if ((*Data == NUL) || (*Name == NUL)) return FALSE; Save = -1; while ((*Data != NUL) || (*Name != NUL)) { if (*Data == '*') { if (*++Data == NUL) return TRUE; if ( ++Save == 10) return FALSE; Save_Name[Save] = Name; Save_Data[Save] = Data; continue; } if ( ((*Data == '?') && (*Name != NUL)) || (toupper(*Data) == toupper(*Name))) { ++Data; ++Name; continue; } if (*Name == NUL) --Save; if ( Save < 0) return FALSE; Name = ++Save_Name[Save]; Data = Save_Data[Save]; } return TRUE; } ^L /******************************/ /* Initialization of Defaults */ /******************************/ #define INTUITIONNAME "intuition.library" public struct IntuitionBase *IntuitionBase; local void Default_Values() /******************************/ { auto struct Preferences PrefBuffer; auto int Temp; extern struct IntuitionBase *OpenLibrary(); extern struct Preferences *GetPrefs(); /* Fetch the information from the system */ IntuitionBase = OpenLibrary( INTUITIONNAME, 0L); if (IntuitionBase == NULL) return; GetPrefs( &PrefBuffer, (long) sizeof( struct Preferences)); CloseLibrary( IntuitionBase); /* Extract the information from the structure */ Temp = (PrefBuffer.PrintSpacing == EIGHT_LPI ? 8 : 6); if (PrefBuffer.PaperLength / Temp == 11) Status.Opts_State |= Page_11; if (PrefBuffer.PaperSize == W_TRACTOR) Status.Opts_State |= Line_13; } /**********************************/ /* Stop Printing The Current File */ /**********************************/ local int Stop_Printing( Spool_Show) /****************************************/ char *Spool_Show; { extern FILE *fopen(); if ((Status.Prog_State != Exec_State) && (Status.Prog_State != File_State) && (Status.Prog_State != Stop_State) ) return FALSE; if (Line_Count != Line_Limit) putc( '\f', Dest_File); fclose( From_File); if (Status.Prog_State == Exec_State) Status.Prog_State = Wait_State; else Status.Prog_State = Susp_State; if ((Spool_File = fopen( Spool_Logs, "a")) == NULL) Spool_File = stderr; fprintf( Spool_File, Spool_Show, Status.File_Print->File_Name, Status.Char_Print, Status.Line_Print, Status.Page_Print); if (Spool_File != stderr) fclose( Spool_File); return TRUE; } ^L /********************************/ /* Execute all pending commands */ /********************************/ local void Exec_Print() /**************************/ { extern struct Inform *GetMsg(); extern File *AllocMem(); extern int strncmp(); while ((Info_Port = GetMsg( Data_Port)) != NULL) { if (Info_Port->Number != PROTOCOL) Info_Port->Number = PROTOCOL; else switch( Info_Port->Action) { case PS_Insert : Temp_Skip = &Status.File_Print; while (*Temp_Skip) Temp_Skip = &(*Temp_Skip)->File_Next; *Temp_Skip = Info_Port->Detail.Insert; Info_Port->Detail.Insert = NULL; break; case PS_Update : for (Temp_Test = Info_Port->Detail.Update; Temp_Test != NULL; Temp_Test = Temp_Test->File_Next) { for (Temp_File = Status.File_Print; Temp_File != NULL; Temp_File = Temp_File->File_Next) { if (strncmp( Temp_Test->File_Name, Temp_File->File_Name, Name_Size) == 0) { if ((Temp_Test->File_Copy == 0) && (Temp_File == Status.File_Print) ) Stop_Printing( STOP); Temp_File->File_Opts = Temp_Test->File_Opts; Temp_File->File_Flag = Temp_Test->File_Flag; Temp_File->File_Copy = Temp_Test->File_Copy; Temp_File->File_Size = Temp_Test->File_Size; Temp_Test->File_Flag |= Flag_Updated; break; } } } break; ^L case PS_Remove : Temp_Move = &Temp_File; Temp_Skip = &Status.File_Print; while ((Temp_Test = *Temp_Skip) != NULL) { if (File_Match( Temp_Test->File_Name, Info_Port->Detail.Remove)) { if (Temp_Skip == &Status.File_Print) Stop_Printing( MOVE); *Temp_Move = Temp_Test; *Temp_Skip = Temp_Test->File_Next; Temp_Move = &Temp_Test->File_Next; } else Temp_Skip = &Temp_Test->File_Next; } *Temp_Move = NULL; Info_Port->Detail.Insert = Temp_File; break; case PS_Report : Info_Port->Detail.Status = Status; Temp_Skip = &Info_Port->Detail.Status.File_Print; for (Temp_File = Status.File_Print; Temp_File != NULL; Temp_File = Temp_File->File_Next) { Temp_Test = AllocMem( (long) sizeof( File), MEMF_PUBLIC); if (Temp_Test == NULL) { Info_Port->Detail.Status.Opts_State |= Flag_Partial; } else { *(*Temp_Skip = Temp_Test) = *Temp_File; Temp_Skip = &Temp_Test->File_Next; } } *Temp_Skip = NULL; break; case PS_Return : Status.Flag_State = !Status.Flag_State; break; case PS_Change : if (Status.File_Print != NULL) { Status.Opts_State &= ~Flag_Test; Status.Opts_State |= Status.File_Print->File_Opts & Flag_Test; } break; case PS_Freeze : switch( Status.Prog_State) { case Wait_State : case Page_State : case Open_State : Status.Prog_State = Susp_State; break; case Exec_State : case File_State : Status.Prog_State = Stop_State; break; } break; ^L case PS_Finish : switch( Status.Prog_State) { case Wait_State : case Page_State : case Open_State : Status.Prog_State = Susp_State; break; case Exec_State : case Stop_State : Status.Prog_State = File_State; break; } break; case PS_Resets : Stop_Printing( BACK); Status.Prog_State = Susp_State; break; case PS_Cancel : if (Stop_Printing( STOP)) --Status.File_Print->File_Copy; Status.Prog_State = Susp_State; break; case PS_Resume : if (Status.Prog_State == Susp_State) Status.Prog_State = Wait_State; if (Status.Prog_State == Stop_State) Status.Prog_State = Exec_State; if (Status.Prog_State == File_State) Status.Prog_State = Exec_State; break; } Info_Port->Packet.mn_Node.ln_Type = NT_REPLYMSG; ReplyMsg( Info_Port); } } ^L /******************************************/ /* Perform according to the current state */ /******************************************/ local int Exec_Spool() /**************************/ { extern FILE *fopen(); switch( Status.Prog_State) { case Wait_State : case Page_State : case Open_State : /* Eliminate Old File Information */ while ((Temp_File = Status.File_Print) != NULL) { if (Temp_File->File_Copy != 0) break; Status.File_Print = Temp_File->File_Next; if (Temp_File->File_Flag & Flag_Deleted) remove( Temp_File->File_Name); FreeMem( Temp_File, (long) sizeof( Temp_File)); } /* Wait if there is nothing to do */ if (Temp_File == NULL) { Status.Prog_State = Wait_State; if (Dest_File != NULL) { fclose( Dest_File); Dest_File = NULL; } if (Status.Flag_State) { Forbid(); if ((Info_Port = GetMsg( Data_Port)) == NULL) { DeletePort( Data_Port); Permit(); return FALSE; } PutMsg( Data_Port, Info_Port); Permit(); } else WaitPort( Data_Port); break; } /* Check the format of the paper */ Temp_Opts = (Status.Opts_State ^ Temp_File->File_Opts); if (Temp_Opts & Flag_Test) { if (Dest_File != NULL) { fclose( Dest_File); Dest_File = NULL; } Status.Prog_State = Page_State; WaitPort( Data_Port); break; } /* Request access to the printer */ if ((Dest_File == NULL) && ((Dest_File = fopen( "PRT:", "w")) == NULL) ) { Status.Prog_State = Open_State; Delay( 5L * TICKS_PER_SECOND); break; } ^L /* Request access to the data file */ From_File = fopen( Status.File_Print->File_Name, "r"); if (From_File == NULL) { Status.File_Print->File_Copy = 0; Status.Prog_State = Wait_State; Spool_File = fopen( Spool_Logs, "a"); if (Spool_File == NULL) Spool_File = stderr; fprintf( Spool_File, OPEN, Status.File_Print->File_Name); if (Spool_File != stderr) fclose( Spool_File); break; } /* Initialize all control variables */ Status.Opts_State = Status.File_Print->File_Opts; Status.Char_Print = Status.Line_Print = Status.Page_Print = 0; Line_Limit = Page_Used[Opts_Used(Status.Opts_State)]; Line_Count = Line_Limit; /* Initialize the printer */ fprintf( Dest_File, "\033c\033#1\033#5\033[%cw\033[1;%ds\033[%cz\033[%dt\033[%c\"z", Line_Code[Status.Opts_State & Line_Density], Line_Size[Status.Opts_State & Flag_Line], (Status.Opts_State & Page_Density ? '0' : '1'), Page_Size[Opts_Page(Status.Opts_State)], (Status.File_Print->File_Flag & Flag_Quality ? '2' : '1')); /* Start printing the specified file */ Status.Prog_State = Exec_State; Char_Saved = fgetc( From_File); ^L case Exec_State : case File_State : /* Print the file one line at a time */ if (Char_Saved == EOF) { Stop_Printing( COPY); --Status.File_Print->File_Copy; break; } /* Deal with form feed characters */ if (Char_Saved == '\f') { if (Line_Count != Line_Limit) { putc( '\f', Dest_File); Line_Count = Line_Limit; } Next_Char(); break; } /* Deal with page counters and headers */ if (Line_Count == Line_Limit) { ++Status.Page_Print; Line_Count = 0; if (Status.Opts_State & Opts_Headers) { fprintf( Dest_File, "%-20.20s %-42.42s Page %3ld\n\n\n", Status.File_Print->File_Date, Status.File_Print->File_Name, Status.Page_Print); Line_Count = 3; } } /* Time to print the line */ ++Status.Line_Print; ++Line_Count; if (Status.Opts_State & Opts_Numbers) fprintf( Dest_File, "%6ld: ", Status.Line_Print); while ((Char_Saved != EOF) && (Char_Saved != '\n') && (Char_Saved != '\f') ) { putc( Char_Saved, Dest_File); Next_Char(); } if (Char_Saved == '\n') Next_Char(); fputs( (Line_Count == Line_Limit ? "\n\f" : "\n"), Dest_File); break; case Susp_State : /* Wait for new comamnds */ if (Dest_File != NULL) { fclose( Dest_File); Dest_File = NULL; } case Stop_State : WaitPort( Data_Port); break; } return TRUE; } ^L /*****************************/ /* This is the Spool program */ /*****************************/ public void main( argc, argv) /*******************************/ int argc; char *argv[]; { extern struct MsgPort *FindPort(), *CreatePort(); extern FILE *fopen(); fprintf( stderr, HEAD); if (FindPort( SPOOLNAME) != NULL) { fprintf( stderr, EXEC); exit( 1); } if (argc > 1) Spool_Logs = argv[1]; if ((Spool_File = fopen( Spool_Logs, "a")) == NULL) { fprintf( stderr, LOGS, Spool_Logs); exit(1); } fprintf( Spool_File, HEAD); fclose( Spool_File); if ((Data_Port = CreatePort( SPOOLNAME, 0L)) == NULL) { fprintf( stderr, INIT); exit( 1); } Default_Values(); do Exec_Print(); while (Exec_Spool()); } SHAR_EOF # End of shell archive exit 0