home *** CD-ROM | disk | FTP | other *** search
- /*
- * WBTitle
- *
- * Version 1.0
- *
- * Public Domain Software
- *
- * This program replaces the Amiga's Workbench title bar so that it
- * shows all types of memory available: Chip, Public, VM, and Retina.
- */
-
- #include <string.h>
- #include <ctype.h>
-
- #include <exec/types.h>
- #include <exec/memory.h>
- #include <intuition/intuition.h>
- #include <dos/dos.h>
-
- #include <proto/exec.h>
- #include <proto/intuition.h>
- #include <proto/dos.h>
- #include <proto/retina.h>
- #include <proto/vmm.h>
-
- #include <clib/alib_protos.h>
-
- // The SetWindowTitles function offset
- #define SWTOffset -276
-
- enum {
- JMPINSTR = 0x4ef9
- };
-
- typedef struct JmpEntry {
- UWORD Instr;
- APTR Func;
- } JmpEntry;
-
- static BOOL Replace(void);
- static void Restore(void);
- static void __asm new_SetWindowTitles(register __a0 struct Window *,
- register __a1 UBYTE *, register __a2 UBYTE *,
- register __a6 struct Library *);
- static void NumberToString(ULONG number);
- static void format_number(ULONG number);
- static void no_lead_triple(ULONG number);
- static void lead_triple(ULONG number);
-
- // Global variables
- struct RetinaBase *RetinaBase;
- struct Library *VMMBase;
-
- // Local variables
- static char verstring[] = "$VER: WBTitle 1.0 " __AMIGADATE__;
- static char port_name[] = "WBTitle";
-
- static void __asm (*old_SetWindowTitles)(register __a0 struct Window *,
- register __a1 UBYTE *,
- register __a2 UBYTE *,
- register __a6 struct Library *);
- static JmpEntry *SWTEntry;
- static char *chip_str, *fast_str, *public_str, *total_str, *virtual_str;
- static char *retina_str, *memorder_str, *prefix_str, *suffix_str, *labels_str;
- static char *comma_str, *mem_str, *last_str, *buff_ptr;
- static char num_buf[14], comma;
- static int units, num_size, mem_str_len, prefix_str_len;
- static BOOL sep1000, labels_after;
-
- /*
- * The main method for replacing an Amiga OS function as safe as
- * possible is to place the function with a jump table that is
- * allocated. While the function is replaced, the jump table simply
- * jumps to my routine:
- *
- * jmp _new_SetWindowTitles
- *
- * When the user asks the program to quit, we can't simply put the
- * pointer back that SetFunction() gives us since someone else might
- * have replaced the function. So, we first see if the pointer we
- * get back points to the out jump table. If so, then we _can_ put
- * the pointer back like normal (no one has replaced the function
- * while we has it replaced). But if the pointer isn't mine, then
- * we have to replace the jump table function pointer to the old
- * function pointer:
- *
- * jmp _old_SetWindowTitles
- *
- * Finally, we only deallocate the jump table _if_ we did not have
- * to change the jump table.
- */
-
- main(int argc, char *argv[])
- {
- struct MsgPort *port;
-
- // FindPort() Forbid()
- Forbid();
-
- port = FindPort(port_name);
- if (port) {
- struct MsgPort *reply_port;
-
- // Create a reply port
- reply_port = CreateMsgPort();
- if (reply_port) {
- struct Message msg;
-
- // Set fields in message structure
- msg.mn_ReplyPort = reply_port;
- msg.mn_Length = sizeof(struct Message);
-
- // Send the message
- PutMsg(port, &msg);
-
- // Finished with port, so stop FindPort() Forbid()
- Permit();
-
- // Wait for a reply
- do {
- WaitPort(reply_port);
- } while (GetMsg(reply_port) == NULL);
-
- // Clear and Delete reply_port Forbid()
- Forbid();
-
- // Clear any messages
- while (GetMsg(reply_port));
-
- // Delete the reply port
- DeleteMsgPort(reply_port);
-
- // Clear and Delete reply_port stop Forbid()
- Permit();
- } else {
- // Finished with port, so stop FindPort() Forbid()
- Permit();
- }
- } else if (port = CreateMsgPort()) {
- struct Message *msg;
- char **ttypes;
-
- // Finished with port, so stop FindPort() Forbid()
- Permit();
-
- // Setup quitting port
- port->mp_Node.ln_Name = port_name;
- port->mp_Node.ln_Pri = -120;
-
- // Add quitting port to public list
- AddPort(port);
-
- // Open the Retina library
- RetinaBase = (struct RetinaBase *)OpenLibrary("retina.library", 0);
-
- // Check on VMM; look for port, and alloc signal
- if (FindPort("VMM_Port")) {
- VMMBase = OpenLibrary("vmm.library", 0);
- }
-
- // Setup to read some arguements
- ttypes = ArgArrayInit(argc, argv);
-
- // Read some arguments
- prefix_str = ArgString(ttypes, "PREFIX", "Amiga Workbench ");
- suffix_str = ArgString(ttypes, "SUFFIX", "");
- labels_str = ArgString(ttypes, "LABELS", "AFTER");
-
- chip_str = ArgString(ttypes, "CHIP", " Chip ");
- fast_str = ArgString(ttypes, "FAST", " Fast ");
- public_str = ArgString(ttypes, "PUBLIC", " Public ");
- total_str = ArgString(ttypes, "TOTAL", " Total ");
- virtual_str = ArgString(ttypes, "VIRTUAL", " Virtual ");
- retina_str = ArgString(ttypes, "RETINA", " Retina ");
-
- memorder_str = ArgString(ttypes, "MEMORDER", "CVPR");
- sep1000 = (ArgString(ttypes, "THOUSANDSEP", NULL) != NULL);
- units = ArgInt(ttypes, "UNITS", 1);
- comma_str = ArgString(ttypes, "SEPERATOR", NULL);
- if (comma_str && comma_str[0]) {
- comma = comma_str[0];
- } else {
- comma = ',';
- }
-
- labels_after = (stricmp(labels_str, "BEFORE") != 0);
- if (units < 0) {
- units = 1;
- }
-
- // Compute the size of numbers
- {
- ULONG maxnum = 0xffffffff;
-
- // Compute the number of digits
- maxnum /= units;
- while (maxnum) {
- maxnum /= 10;
- num_size++;
- }
-
- // Compute the number of commas
- if (sep1000) {
- int com = num_size;
- while (com > 3) {
- num_size++;
- com -= 3;
- }
- }
- }
-
- // Compute the size of the mem string
- {
- ULONG i = 0;
- char ch;
-
- // Add in the prefix string size
- mem_str_len = prefix_str_len = strlen(prefix_str);
-
- // Add in the memory parts
- while (ch = toupper(memorder_str[i])) {
- switch (ch) {
- case 'C':
- mem_str_len += strlen(chip_str) + num_size;
- break;
- case 'F':
- mem_str_len += strlen(fast_str) + num_size;
- break;
- case 'P':
- mem_str_len += strlen(public_str) + num_size;
- break;
- case 'T':
- mem_str_len += strlen(total_str) + num_size;
- break;
- case 'V':
- if (VMMBase) {
- mem_str_len += strlen(virtual_str) + num_size;
- }
- break;
- case 'R':
- if (RetinaBase) {
- mem_str_len += strlen(retina_str) + num_size;
- }
- break;
- }
- i++;
- }
-
- // Add in the suffix string size
- mem_str_len += strlen(suffix_str);
- }
-
- if (mem_str_len > 0) {
- // Allocate the memory
- mem_str = AllocMem(mem_str_len + 1, MEMF_PUBLIC);
- if (mem_str) {
- strcpy(mem_str, prefix_str);
- last_str = &mem_str[prefix_str_len];
-
- // Attempt to replace function
- if (Replace()) {
- // Wait for someone to signal me to quit
- do {
- WaitPort(port);
- msg = GetMsg(port);
- } while (msg == NULL);
- ReplyMsg(msg);
-
- // Restore function
- Restore();
- }
- FreeMem(mem_str, mem_str_len + 1);
- }
- }
-
- // Cleanup from reading arguments
- ArgArrayDone();
-
- // Remove port from public access
- RemPort(port);
-
- // Clear and Delete port Forbid()
- Forbid();
-
- // Clear the port of messages
- while (msg = GetMsg(port)) {
- ReplyMsg(msg);
- }
-
- // Closedown quitting port
- DeleteMsgPort(port);
-
- // Clear and Delete port stop Forbid()
- Permit();
- }
- }
-
- static BOOL Replace(void)
- {
- // Allocate the jump table
- SWTEntry = AllocMem(sizeof(JmpEntry), 0);
- if (SWTEntry) {
- // Replacement Forbid()
- Forbid();
-
- // Replace the function with pointer to jump table
- old_SetWindowTitles = SetFunction((struct Library *)IntuitionBase,
- SWTOffset, (ULONG (*)())SWTEntry);
-
- // Setup the jump table
- SWTEntry->Instr = JMPINSTR;
- SWTEntry->Func = new_SetWindowTitles;
-
- // Clear the cpu's cache so the execution cache is valid
- CacheClearU();
-
- // Stop the replacement Forbid()
- Permit();
-
- return TRUE;
- } else {
- return FALSE;
- }
- }
-
- static void Restore(void)
- {
- BOOL my_table;
- ULONG (*func)();
-
- // Fix back Forbid()
- Forbid();
-
- // Put old pointer back and get current pointer at same time
- func = SetFunction((struct Library *)IntuitionBase, SWTOffset,
- (ULONG (*)())old_SetWindowTitles);
-
- // Check to see if the pointer we get back is ours
- if ((JmpEntry *)func != SWTEntry) {
- // If not, leave jump table in place
- my_table = FALSE;
- SetFunction((struct Library *)IntuitionBase, SWTOffset,
- func);
- SWTEntry->Func = old_SetWindowTitles;
- } else {
- // If so, free the jump table
- my_table = TRUE;
- FreeMem(SWTEntry, sizeof(JmpEntry));
- }
-
- // Clear the cpu's cache so the execution cache is valid
- CacheClearU();
-
- // Stop fix back Forbid()
- Permit();
-
- // Let the user know if the jump table couldn't be freed
- if (!my_table) {
- DisplayBeep(NULL);
- }
-
- // Wait 5 seconds to try and guarantee that all tasks have
- // finished executing inside my replacement function before
- // quitting. There's no real way to guarantee, though.
- Delay(250);
- }
-
- static void __saveds __asm new_SetWindowTitles(
- register __a0 struct Window *window,
- register __a1 UBYTE *win_title,
- register __a2 UBYTE *scr_title,
- register __a6 struct Library *lib)
- {
- if (scr_title && (scr_title != (UBYTE *)0xffffffff) &&
- (*scr_title == 'A') && strstr(scr_title, "graphics mem")) {
- ULONG i = 0;
- char ch;
-
- // Set last_str to nothing
- *last_str = 0;
-
- // Add in the memory parts
- while (ch = toupper(memorder_str[i])) {
- switch (ch) {
- case 'C':
- if (!labels_after) {
- strcat(last_str, chip_str);
- }
- NumberToString(AvailMem(MEMF_CHIP));
- strcat(last_str, num_buf);
- if (labels_after) {
- strcat(last_str, chip_str);
- }
- break;
- case 'F':
- if (!labels_after) {
- strcat(last_str, fast_str);
- }
- NumberToString(AvailMem(MEMF_FAST));
- strcat(last_str, num_buf);
- if (labels_after) {
- strcat(last_str, fast_str);
- }
- break;
- case 'P':
- if (!labels_after) {
- strcat(last_str, public_str);
- }
- NumberToString(AvailMem(MEMF_PUBLIC));
- strcat(last_str, num_buf);
- if (labels_after) {
- strcat(last_str, public_str);
- }
- break;
- case 'T':
- if (!labels_after) {
- strcat(last_str, total_str);
- }
- NumberToString(AvailMem(0));
- strcat(last_str, num_buf);
- if (labels_after) {
- strcat(last_str, total_str);
- }
- break;
- case 'V':
- if (VMMBase) {
- if (!labels_after) {
- strcat(last_str, virtual_str);
- }
- NumberToString(AvailVMem(0));
- strcat(last_str, num_buf);
- if (labels_after) {
- strcat(last_str, virtual_str);
- }
- }
- break;
- case 'R':
- if (RetinaBase) {
- if (!labels_after) {
- strcat(last_str, retina_str);
- }
- NumberToString(Retina_AvailMem(0));
- strcat(last_str, num_buf);
- if (labels_after) {
- strcat(last_str, retina_str);
- }
- }
- break;
- }
- i++;
- }
- strcat(last_str, suffix_str);
- old_SetWindowTitles(window, win_title, mem_str, lib);
- } else {
- old_SetWindowTitles(window, win_title, scr_title, lib);
- }
- }
-
- /*
- * Convert the number to a string in the format the user specified.
- * The string generated is 0 terminated.
- *
- * Uses global variables: buff_ptr, num_buff
- */
-
- static void NumberToString(ULONG number)
- {
- number /= units;
- if (sep1000) {
- buff_ptr = num_buf;
- format_number(number);
- *buff_ptr = 0;
- } else {
- stcul_d(num_buf, number);
- }
- }
-
- static void format_number(ULONG number)
- {
- if (number > 1000) {
- format_number(number / 1000);
- lead_triple(number % 1000);
- } else {
- no_lead_triple(number);
- }
- }
-
- static void no_lead_triple(ULONG number)
- {
- if (number > 10) {
- no_lead_triple(number / 10);
- *buff_ptr++ = ((number % 10) | 0x30);
- } else {
- *buff_ptr++ = (number | 0x30);
- }
- }
-
- static void lead_triple(ULONG number)
- {
- *buff_ptr++ = comma;
- *buff_ptr++ = ((number / 100) | 0x30);
- number %= 100;
- *buff_ptr++ = ((number / 10) | 0x30);
- number %= 10;
- *buff_ptr++ = (number | 0x30);
- }
-