/*
 *  This program will create new text for a specified menu item.
 *  The new text will reside in a node linked on to the UserData
 *  field of the window it resides in.
 *
 *  Problem: the new text will never be de-allocated unless by
 *  this program (ie it stays around and waits for the window to
 *  close). Or by another program that looks at the window->UserData
 *  field. Use the RESTORE program I've included with this one to
 *  unlink the new menuitems before closing the window.
 *
 *  ((c)) 1987, John Russell. Unlimited distribution, but donations to
 *  starving programmers welcome.
 *
 */

#include "intuition/intuition.h"
#include "stdio.h"
#include "exec/memory.h"

char *name = "John Russell";
char *address = "5 Alderdice Place";
char *province = "St. John's, Newfoundland, Canada";
char *postal_code = "A1B 2P8";
char *phone = "(709) 726-7847";

void copy();
char *gets();   /* I couldn't seem to get this to "clip" properly */

struct IntuitionBase *IntuitionBase;

struct node {
    struct node *next;      /* link to next node */
    char text[46];          /* buffer for menu text */
    char *old_text;         /* save location for program's pointer */
    short old_item_width;   /* save location for hitbox width */
    struct MenuItem *altered;   /* pointer to menuitem we alter */
} *node,*ptr,*findnode();

main(argc, argv)
int argc;
char *argv[];
{
    struct Window *window;
    struct Screen *screen;
    struct MenuItem *item;
    struct Menu *menu,*main_menu;
    int x,text;
    short width;
    char line_buf[100]; /* buffer for gets() to handle too-long strings */

    text = argc-1; /* *argv[text] == text to assign */

    if ((IntuitionBase=(struct IntuitionBase *)
        OpenLibrary("intuition.library",0L))==NULL) {
            puts("Where is Intuition gone???\n");
            exit(0);
    }

/* print instructions if wrong number of arguments */

    if ((argc > 6) || (argc < 5)) {
        puts("Usage: menutext <window> <menunum> <itemnum>\n\
       [ <subitemnum> ] <new_text | \"-ask\">");
        puts("\nEG - menutext FooBar 1 4 testing\n\
     menutext VT100 2 1 3 high_speed\n\
     menutext Notepad 1 1 -ask");
        exit(0);
    }

    Forbid();

    screen = IntuitionBase->FirstScreen; /* address of Workbench screen structure */

    while (screen) {     /* do all screens */

        window = screen->FirstWindow;

        while (window) {    /* do all windows */

            if (compare(argv[1],window->Title)==0) {  /* search for name */

                x=atoi(argv[2]);  /* menu # */
                menu = window->MenuStrip;
                main_menu = menu; /* main menu of window for SetMenuStrip */

                while (--x > 0) {  /* scan menu list */
                    if ((menu = menu->NextMenu) == NULL)
                        goto quit;
                }

                x = atoi(argv[3]);  /* item # */
                item = menu->FirstItem;
submenu:
                while (--x > 0) {  /* scan item list */
                    if ((item = item->NextItem) == NULL)
                        goto quit;
                }

                if (argc==6) { /* descend into sub-menu? */
                    argc=0;
                    item=item->SubItem;
                    x=atoi(argv[4]); /* sub-item # */
                    goto submenu;
                }

                ClearMenuStrip(window); /* disable menu structure */

/*
 *  First check to see if this menu item has already been redefined, by
 *  scanning the list from window->UserData. If it has, do no node creation
 *  or re-linking, just copy the text over the node's old text.
 *
 *  If this is the first time the menu item has received new text, create
 *  a new node, record which menu item is being altered, and preserve a
 *  pointer to the original text used by the program, so we can undo all
 *  of this later. Also record how wide the original hitbox was for future
 *  reference.
 *
 *  A new hitbox width is created if a new, longer string is put into the
 *  menu. If a keyboard shortcut exists for that item, the hitbox is widened
 *  to take that into account.
 *
 */

                if ( (node = findnode(window,item)) == NULL) {

                    node = (struct node *)
                        AllocMem(sizeof(struct node),MEMF_CHIP|MEMF_CLEAR);
                    node->next = window->UserData;  /* insert in first place */
                    window->UserData = node;  /* link into window structure */
                    node->altered = item;
                    node->old_text = item->ItemFill->IText; /* save old text */
                    node->old_item_width = item->Width; /* save old width */
                    item->ItemFill->IText = node->text; /* change menu itself */

                }

                if (compare(argv[text],"-ask")) {
                    copy(argv[text],node->text);    /* special strncpy() */
                }
                else {
                    printf("Enter new menu text: ");
                    gets(line_buf,45);  /* "45" ignored? seems that way */
                    copy(line_buf,node->text);
                }

/* alter width if necessary, so you don't have long menutexts with very */
/* short complemented or boxed areas. font-size is fixed at 8 because */
/* the "TextAttr" structure is not in the Intuition manual, and the RKM */
/* is not handy. */

                width = ((length(node->text)) * 8) +
                        (item->Flags & COMMSEQ ? COMMWIDTH : 0);

                if (width > node->old_item_width) {
                    item->Width = width;    /* don't shorten, just lengthen */
                }

/* debugging info left in. This program, although it works fine, can be */
/* (and will be) revised extensively. */

                ptr = window->UserData;

                printf("Replacing menutext \"%s\" with \"%s\"\n\n",
                    node->old_text,node->text);

                printf("Current changed definitions:\n");

                while (ptr) {
                    printf("\tOld text: %s\n\tNew text: %s\n\n",
                        ptr->old_text,ptr->text);
                    ptr = ptr->next;
                }

                SetMenuStrip(window,main_menu); /* give it back */
            }
        window = window->NextWindow;
        }
    screen = screen->NextScreen;
    }

    quit:
    Permit();
    CloseLibrary(IntuitionBase);

}

compare(string1,string2) /* if spaces in windowname, only check first word */
char *string1,*string2;
{
    while ((*string1 != '\0') && (*string1 != ' ')) {
        if (*string1++ != *string2++) /* space and null both end conditions */
            return(1);
    }
    return(0);  /* return weird values like strcmp() */
}

void copy(string1,string2)  /* modified strncpy */
char *string1,*string2;
{
    int count = 44;   /* (44 + space + null) will fill available buffer */

    while ((*string1 != '\0') && count) {
        *string2++ = *string1++;
        count--;
    }
    *string2++ = ' ';   /* always end string with space + null */
    *string2++ = '\0';  /* otherwise menus with shortcuts are messy */
}

struct node *findnode(window,item) /* does item already have attached node? */
struct Window *window;
struct MenuItem *item;
{
    struct node *ptr;

    ptr = window->UserData;

    while (ptr) {
        if (ptr->altered == item) /* if desired item already redefined */
            return(ptr);  /* this is the node to use */

        ptr = ptr->next;
    }

    return(NULL);   /* search failed, send message to create and link node */
}

length(string)  /* I hate (and don't really trust) std C string functions */
char *string;
{
    int x=0;

    while (*string++)
        x++;

    return(x);
}

