home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / EDITOR / MG2A_SRC.ZIP / SYS / AMIGA / TTYMENU.C < prev    next >
Encoding:
C/C++ Source or Header  |  1988-08-23  |  16.8 KB  |  619 lines

  1. /*
  2.  * ttymenu.c
  3.  *
  4.  * Incorporates the browser, for rummaging around on disks,
  5.  * and the usual Emacs editing command menu
  6.  *
  7.  *    Copyright (c) 1986, Mike Meyer
  8.  *    Mic Kaczmarczik did a few things along the way.
  9.  *
  10.  * Permission is hereby granted to distribute this program, so long as
  11.  * this source file is distributed with it, and this copyright notice
  12.  * is not removed from the file.
  13.  *
  14.  */
  15.  
  16. #include <exec/types.h>
  17. #include <libraries/dos.h>
  18. #include <libraries/dosextens.h>
  19. #include <intuition/intuition.h>
  20. #undef    TRUE
  21. #undef    FALSE
  22. #include "def.h"
  23. #ifndef    NO_MACRO
  24. #include "macro.h"
  25. #endif    
  26.  
  27. extern struct Menu        *AutoMenu ;
  28. extern struct Window        *EmW ;
  29.  
  30. #ifdef    LATTICE
  31. static VOID    Add_Devices(ULONG) ;
  32. #else
  33. static VOID    Add_Devices() ;
  34. #endif
  35.  
  36. #define MNUM(menu,item,sub) (SHIFTMENU(menu)|SHIFTITEM(item)|SHIFTSUB(sub))
  37.  
  38. #ifdef    BROWSER
  39. #define LONGEST_NAME    80    /* Longest file name we can deal with    */
  40.  
  41. # ifdef    LATTICE
  42. char *strchr(char *, int);
  43. # else
  44. char *index();            /* find first instance of c in s    */
  45. #define    strchr(s, c) index(s, c)
  46. # endif
  47.  
  48. # ifdef    MENU
  49. #define    FIRSTMENU    1
  50. # else
  51. #define    FIRSTMENU    0
  52. # endif
  53.  
  54. #endif    BROWSER
  55.  
  56. #ifdef    MENU
  57. /*
  58.  * When ttgetc() sees a menu selection event, it stuffs the sequence
  59.  * KMENU <menu><item><subitem> into the input buffer
  60.  *
  61.  * The menu item names are chosen to be relatively close to the extended
  62.  * function names, so a user can usually figure out the key binding of
  63.  * a menu item by searching through the "display-bindings" buffer
  64.  * for something that's close.
  65.  */
  66.  
  67. /*
  68.  * Commands for managing files and buffers
  69.  */
  70.  
  71. extern    int    filevisit();
  72. extern    int    poptofile();
  73. extern    int    fileinsert();
  74. extern    int    filesave();
  75. extern    int    filewrite();
  76. #ifndef    NO_DIRED
  77. extern    int    dired();
  78. #endif
  79. extern    int    usebuffer();
  80. extern    int    poptobuffer();
  81. extern    int    killbuffer();
  82. extern    int    listbuffers();
  83. extern    int    savebuffers();
  84. extern    int    quit();
  85.  
  86. static struct MenuBinding FileItems[] = {
  87.     { "Find File         C-x C-f",    filevisit    },
  88.     { "Pop To File       C-x 4 f",    poptofile    },
  89.     { "Insert File       C-x i",    fileinsert    },
  90.     { "Save File         C-x C-s",    filesave    },
  91.     { "Write File        C-x C-w",    filewrite    },
  92. #ifndef    NO_DIRED
  93.     { "Dired         C-x d",    dired        },
  94. #endif
  95.     { "Switch To Buffer  C-x b",    usebuffer    },
  96.     { "Pop To Buffer     C-x 4 b",    poptobuffer    },
  97.     { "Kill Buffer       C-x k",    killbuffer    },
  98.     { "List Buffers      C-x C-b",    listbuffers    },
  99.     { "Save Buffers      C-x s",    savebuffers    },
  100.     { "Save And Exit     C-x C-c",    quit        }
  101. };
  102.  
  103. /*
  104.  * Commands for various editing functions
  105.  */
  106.  
  107. extern    int    yank();
  108. extern    int    openline();
  109. extern    int    killline();
  110. extern    int    deblank();
  111. extern    int    justone();
  112. extern    int    indent();
  113. extern    int    twiddle();
  114. extern    int    quote();
  115.  
  116. static struct MenuBinding EditItems[] = {
  117.     { "Yank                 C-y",    yank        },
  118.     { "Blank Line           C-o ",    openline    },
  119.     { "Kill Line            C-k",    killline    },
  120.     { "Delete Blank Lines   C-x C-o",deblank    },
  121.     { "Delete Blanks        M-SPC",    justone        },
  122.     { "Newline And Indent   C-j",    indent        },
  123.     { "Transpose Characters C-t",    twiddle        },
  124.     { "Quoted Insert        C-q",    quote        }
  125. };
  126.  
  127. /*
  128.  * Movement commands
  129.  */
  130.  
  131. extern    int    forwpage();
  132. extern    int    backpage();
  133. extern    int    gotobol();
  134. extern    int    gotobob();
  135. extern    int    gotoeol();
  136. extern    int    gotoeob();
  137. extern    int    gotoline();
  138. extern    int    showcpos();
  139.  
  140. static struct MenuBinding MoveItems[] = {
  141.     { "Scroll Up       C-v",    forwpage    },
  142.     { "Scroll Down     M-v",    backpage    },
  143.     { "Start Of Line   C-a",    gotobol        },
  144.     { "Start Of Buffer M-<",    gotobob        },
  145.     { "End Of Line     C-e",    gotoeol        },
  146.     { "End Of Buffer   M->",    gotoeob        },
  147.     { "Goto Line",            gotoline    },
  148.     { "Show Cursor     C-x =",    showcpos    }
  149. };
  150.  
  151. /*
  152.  * Commands for searching and replacing
  153.  */
  154.  
  155. extern    int    forwisearch();
  156. extern    int    backisearch();
  157. extern    int    searchagain();
  158. extern    int    forwsearch();
  159. extern    int    backsearch();
  160. extern    int    queryrepl();
  161.  
  162. static struct MenuBinding SearchItems[] = {
  163.     { "I-Search Forward  C-s",    forwisearch    },
  164.     { "I-Search Backward C-r",    backisearch    },
  165.     { "Search Again",        searchagain    },
  166.     { "Search Forward    M-s",    forwsearch    },
  167.     { "Search Backward   M-r",    backsearch    },
  168.     { "Query Replace     M-%",    queryrepl    }
  169. };
  170.  
  171. /*
  172.  * Commands that manipulate words
  173.  */
  174. extern    int    forwword();
  175. extern    int    backword();
  176. extern    int    delfword();
  177. extern    int    delbword ();
  178. extern    int    capword();
  179. extern    int    lowerword();
  180. extern    int    upperword();
  181.  
  182. static struct MenuBinding WordItems[] = {
  183.     { "Forward Word       M-f",    forwword    },
  184.     { "Backward Word      M-b",    backword    },
  185.     { "Kill Word          M-d",    delfword    },
  186.     { "Backward Kill Word M-DEL",    delbword     },
  187.     { "Capitalize Word    M-c",    capword        },
  188.     { "Downcase Word      M-l",    lowerword    },
  189.     { "Upcase Word        M-u",    upperword    }
  190. };
  191.  
  192. /*
  193.  * Commands relating to paragraphs
  194.  */
  195. extern    int    gotoeop();
  196. extern    int    gotobop();
  197. extern    int    fillpara();
  198. extern    int    setfillcol();
  199. extern    int    killpara();
  200. extern    int    fillmode();
  201.  
  202. static struct MenuBinding ParaItems[] = {
  203.     { "Forward Paragraph  M-]",    gotoeop        },
  204.     { "Backward Paragraph M-[",    gotobop        },
  205.     { "Fill Paragraph     M-q",    fillpara    },
  206.     { "Set Fill Column    C-x f",    setfillcol    },
  207.     { "Kill Paragraph",        killpara    },
  208.     { "Auto Fill Mode",        fillmode    }
  209. };
  210.  
  211. /*
  212.  * Region stuff
  213.  */
  214. extern    int    setmark();
  215. extern    int    swapmark();
  216. extern    int    killregion();
  217. extern    int    copyregion();
  218. extern    int    lowerregion();
  219. extern    int    upperregion();
  220.  
  221. static struct MenuBinding RegionItems[] = {
  222.     { "Set Mark            C-@",    setmark        },
  223.     { "Exch Point And Mark C-x C-x",swapmark    },
  224.     { "Kill Region         C-w",    killregion    },
  225.     { "Copy Region As Kill M-w",    copyregion    },
  226.     { "Downcase Region     C-x C-l",lowerregion    },
  227.     { "Upcase Region       C-x C-u",upperregion    }
  228. };
  229.  
  230. /*
  231.  * Commands for manipulating windows
  232.  */
  233.  
  234. extern    int    splitwind();
  235. extern    int    delwind();
  236. extern    int    onlywind();
  237. extern    int    nextwind();
  238. #ifdef    PREVWIND
  239. extern    int    prevwind();
  240. #endif
  241. extern    int    enlargewind();
  242. extern    int    shrinkwind();
  243. extern    int    refresh();
  244. extern    int    reposition();
  245. extern    int    togglewindow();
  246. #ifdef    CHANGE_FONT
  247. extern    int    setfont();
  248. #endif
  249.  
  250. static struct MenuBinding WindowItems[] = {
  251.     { "Split Window         C-x 2", splitwind    },
  252.     { "Delete Window        C-x 0",    delwind        },
  253.     { "Delete Other Windows C-x 1",    onlywind    },
  254.     { "Next Window          C-x o",    nextwind    },
  255. #ifdef    PREVWIND
  256.     { "Up Window",            prevwind    },
  257. #endif
  258.     { "Enlarge Window       C-x ^",    enlargewind    },
  259.     { "Shrink Window",        shrinkwind    },
  260.     { "Redraw Display",        refresh        },
  261.     { "Recenter             C-l",    reposition    },
  262.     { "Toggle Border",        togglewindow    },
  263. #ifdef    CHANGE_FONT
  264.     { "Set Font",            setfont        }
  265. #endif
  266. };
  267.  
  268. /*
  269.  * Miscellaneous commands
  270.  */
  271.  
  272. extern    int    definemacro();
  273. extern    int    finishmacro();
  274. extern    int    executemacro();
  275. extern    int    extend();
  276. extern    int    bindtokey();
  277. extern    int    desckey();
  278. extern    int    wallchart();
  279. extern    int    showversion();
  280. extern    int    spawncli();
  281.  
  282. static struct MenuBinding MiscItems[] = {
  283.     { "Start Kbd Macro   C-x (",    definemacro    },
  284.     { "End Kbd Macro     C-x )",    finishmacro    },
  285.     { "Call Kbd Macro    C-x e",    executemacro    },
  286.     { "Execute Command   M-x",    extend        },
  287.     { "Global Set Key",        bindtokey    },
  288.     { "Describe Key      C-h c",    desckey        },
  289.     { "Describe Bindings C-h b",    wallchart    },
  290.     { "Emacs Version",        showversion    },
  291.     { "New CLI           C-z",    spawncli    }
  292. };
  293.  
  294. /*
  295.  * The following table contains the titles, number of items, and
  296.  * pointers to, the individual menus.
  297.  */
  298.  
  299. static struct MenuInfo EMInfo[] = {
  300.     { "File  ",        NITEMS(FileItems),    &FileItems[0]    },
  301.     { "Edit  ",        NITEMS(EditItems),    &EditItems[0]    },
  302.     { "Move  ",         NITEMS(MoveItems),    &MoveItems[0]    },
  303.     { "Search  ",        NITEMS(SearchItems),    &SearchItems[0] },
  304.     { "Word  ",        NITEMS(WordItems),    &WordItems[0]    },
  305.     { "Paragraph  ",    NITEMS(ParaItems),    &ParaItems[0]    },
  306.     { "Region  ",        NITEMS(RegionItems),    &RegionItems[0]    },
  307.     { "Window  ",        NITEMS(WindowItems),    &WindowItems[0] },
  308.     { "Miscellaneous  ",    NITEMS(MiscItems),    &MiscItems[0]    }
  309. };
  310.  
  311. /* There are three cases to deal with; the menu alone, the Browser
  312.  * alone, and both of them together.  We #define some things to make
  313.  * life a little easier to deal with
  314.  */
  315. # ifdef    BROWSER
  316. #  define Edit_Menu_Init() Menu_Add("Edit ", TRUE, FALSE) 
  317. #  define Edit_Menu_Add(n) Menu_Item_Add(n,(USHORT)ITEMENABLED,0L,(BYTE)0,FALSE)
  318. #  define Edit_Item_Add(n) Menu_SubItem_Add(n,(USHORT)ITEMENABLED,0L,(BYTE)0,FALSE)
  319. # else
  320. #  define Edit_Menu_Init() cinf = NULL    /* harmless */
  321. #  define Edit_Menu_Add(n) n[strlen(n)-1] = '\0'; Menu_Add(n, TRUE, FALSE)
  322. #  define Edit_Item_Add(n) Menu_Item_Add(n,(USHORT)ITEMENABLED,0L,(BYTE)0,FALSE)
  323. # endif    BROWSER
  324.  
  325. #endif    MENU
  326.  
  327. /*
  328.  * Initialize the Emacs menu
  329.  */
  330.  
  331. struct Menu * InitEmacsMenu(EmW)
  332. struct Window *EmW;
  333. {
  334. #ifdef    MENU
  335.     register struct MenuInfo *cinf;
  336.     register struct MenuBinding *lastbinding, *cb;
  337.     struct MenuInfo *lastinfo;
  338. #endif
  339.  
  340.     Menu_Init() ;            /* init the menu        */
  341.  
  342. #ifdef    MENU
  343.     Edit_Menu_Init() ;        /* Set up for editing menu    */
  344.     lastinfo = &EMInfo[NITEMS(EMInfo)];    /* loop sentinel    */    
  345.     for (cinf = EMInfo; cinf < lastinfo; cinf++) {
  346.         Edit_Menu_Add(cinf->Name);
  347.         lastbinding = &cinf->Items[cinf->NumItems];
  348.         for (cb = cinf->Items; cb < lastbinding; cb++)
  349.             Edit_Item_Add(cb->Command);
  350.     }
  351. #endif    MENU
  352.  
  353. #ifdef    BROWSER
  354.     Menu_Add("Disks ", TRUE, FALSE) ;/* name is already there */
  355.     Add_Devices(DLT_DEVICE);    /* devices first */
  356.     Add_Devices(DLT_VOLUME);    /* mounted volume names next */
  357.     Add_Devices(DLT_DIRECTORY);    /* assigned directories last */
  358. #endif    BROWSER
  359.     return     AutoMenu ;
  360. }
  361.  
  362. /*
  363.  * amigamenu() -- handles a menu pick.
  364.  */
  365.  
  366. amigamenu(f, n) {
  367.     unsigned short        menunum, itemnum, subnum, Menu_Number;
  368.     char            *name;
  369.     register PF        fp;
  370.  
  371. #ifdef    BROWSER
  372.     register unsigned short    level, i, dirp;
  373.     register char        *cp;
  374.     int            stat;
  375.     struct MenuItem        *ItemAddress() ;
  376.  
  377.     /* State variables that describe the current directory */
  378.     static char        Dir_Name[LONGEST_NAME] ;
  379.     static unsigned short    Menu_Level = 0 ;
  380. #endif
  381.  
  382. #ifndef    NO_MACRO
  383.     if (inmacro) 
  384.         return (FALSE);    /* menu picks aren't recorded */
  385. #endif
  386.  
  387.     /* read the menu, item, and subitem codes from the input stream */
  388.     menunum = getkey(FALSE) - MN_OFFSET;
  389.     itemnum = getkey(FALSE) - MN_OFFSET;
  390.     subnum = getkey(FALSE) - MN_OFFSET;
  391.  
  392. #ifndef    NO_MACRO
  393.     if (macrodef) {        /* menu picks can't be practically recorded */
  394.         ewprintf("Can't record menu selections");
  395.         return (FALSE);
  396.     }
  397. #endif
  398.  
  399.     Menu_Number = (USHORT)
  400.         (SHIFTMENU(menunum) | SHIFTITEM(itemnum) | SHIFTSUB(subnum));
  401.  
  402. #ifndef    BROWSER
  403. # ifdef    MENU
  404.     fp = EMInfo[menunum].Items[itemnum].Function;
  405.     return (*(fp)(f, n));
  406. # endif
  407. #else    /* we're using the Browser */
  408. # ifdef    MENU
  409.     /* Handle commands from the Edit menu when using the Browser */
  410.     if (0 == menunum) {
  411.         fp = EMInfo[itemnum].Items[subnum].Function;
  412.         return ((*fp)(f, n));
  413.     }
  414. # endif
  415.     /* Here when a selection was made in a Browser menu */
  416.     name = (char *)((struct IntuiText *)
  417.         (ItemAddress(AutoMenu,(ULONG) Menu_Number) -> ItemFill))
  418.         -> IText ;
  419.     level = MENUNUM(Menu_Number) - FIRSTMENU;
  420.  
  421.     /* Got what we want, so clear the menu to avoid confusing the user */
  422.     ClearMenuStrip(EmW) ;
  423.  
  424.     /* set dirp to FALSE if the name is not a directory or disk */
  425.     dirp = (strchr(name, '/') != NULL || strchr(name, ':') != NULL) ;
  426.  
  427.     /* First, set the directory name right */
  428.     if (level > Menu_Level)            /* Not possible, die */
  429.         panic("impossible menu_level in amigamenu");
  430.     else if (level == 0)            /* picked a new disk */
  431.         Dir_Name[0] = '\0' ;
  432.     else if (level < Menu_Level) {        /* Throw away some levels */
  433.         for (i = 1, cp = strchr(Dir_Name, ':'); i < level; i++) {
  434.             if (cp == NULL) return FALSE;
  435.             cp = strchr(cp, '/') ;
  436.             }
  437.         if (cp == NULL) panic("broken file name in amigamenu");
  438.         *++cp = '\0' ;
  439.         }
  440.     /* else Menu_Level == level, chose a file a current level */
  441.  
  442.     /* Now, fix up the menu and it's state variable */
  443.     while (Menu_Level > level) {
  444.         Menu_Level-- ;
  445.         Menu_Pop() ;
  446.         }
  447.  
  448.     /* If we added a file, visit it, else add a
  449.      * new directory level to the menu.
  450.      */
  451.     if (!dirp)
  452.         stat = Display_File(Dir_Name, name) ;
  453.     else {
  454.         Menu_Level++ ;
  455.         (void) strncat(Dir_Name, name,
  456.             LONGEST_NAME - strlen(Dir_Name) - 1) ;
  457.         stat = Add_Dir(Dir_Name, name) ;
  458.     }
  459.     SetMenuStrip(EmW, AutoMenu) ;
  460.     return stat ;
  461. #endif    BROWSER
  462. }
  463.  
  464. #ifdef    BROWSER
  465. /*
  466.  * Display_File - Go fetch a the requested file into a window.
  467.  */
  468. Display_File(dir, file) char *dir, *file; {
  469.     register BUFFER    *bp, *findbuffer();
  470.     int        s;
  471.     char        File_Name[LONGEST_NAME], *fn, *adjustname();
  472.  
  473.     (void) strcpy(File_Name, dir);
  474.     (void) strncat(File_Name, file, LONGEST_NAME - strlen(File_Name) - 1) ;
  475.     fn = adjustname(File_Name);
  476.     if ((bp = findbuffer(fn)) == NULL) return FALSE;
  477.     curbp = bp;
  478.     if (showbuffer(bp, curwp, WFHARD) != TRUE) return FALSE;
  479.     if (bp->b_fname[0] == 0)
  480.         return (readin(fn));        /* Read it in.    */
  481.     return TRUE;
  482.     }
  483. /*
  484.  * Add_Dir - given a dir and a name, add the menu name with the files in
  485.  *    dir as entries.  Use AllocMem() in order to make
  486.  *      sure the file info block is on a longword boundary.
  487.  */
  488. static
  489. Add_Dir(dir, name) char *dir, *name; {
  490.     register char            *last_char ;
  491.     register struct FileLock    *my_lock, *Lock() ;
  492.     unsigned short            count ;
  493.     int                stat = FALSE;
  494.     static char            Name_Buf[LONGEST_NAME] ;
  495.     char                *AllocMem();
  496.     struct    FileInfoBlock        *File_Info;
  497.  
  498.     if ((File_Info = (struct FileInfoBlock *)
  499.         AllocMem((LONG)sizeof(struct FileInfoBlock), 0L)) == NULL)
  500.         return (FALSE);
  501.  
  502.     /* Fix up the trailing / if it needs it */
  503.     last_char = &dir[strlen(dir) - 1] ;
  504.     if (*last_char == '/') *last_char = '\0' ;
  505.  
  506.     /* Now, start on the directory */
  507.     if ((my_lock = Lock(dir, ACCESS_READ)) == NULL) goto out;
  508.  
  509.     if (!Examine(my_lock, File_Info)) goto out;
  510.     if (File_Info -> fib_DirEntryType < 0L)
  511.         goto out;
  512.  
  513.     if (Menu_Add(name, TRUE, TRUE) == 0) goto out;
  514.     for (count = 0; ExNext(my_lock, File_Info) 
  515.             || IoErr() != ERROR_NO_MORE_ENTRIES; count++)
  516.         if (File_Info -> fib_DirEntryType < 0L) {
  517.             if (Menu_Item_Add(File_Info -> fib_FileName,
  518.                 (USHORT)ITEMENABLED, 0L, (BYTE)0, TRUE)
  519.                     == MNUM(NOMENU, NOITEM, NOSUB))
  520.                     break ;
  521.             }
  522.         else {
  523.             (void) strcpy(Name_Buf, File_Info -> fib_FileName) ;
  524.             (void) strcat(Name_Buf, "/") ;
  525.             if (Menu_Item_Add(Name_Buf,
  526.                 (USHORT) ITEMENABLED, 0L, (BYTE)0, TRUE)
  527.                      == MNUM(NOMENU, NOITEM, NOSUB))
  528.                 break ;
  529.             }
  530.     if (count == 0) Menu_Item_Add("EMPTY", (USHORT)0, 0L, (BYTE)0, FALSE) ;
  531.  
  532.     /* Put everything back */
  533.     if (*last_char == '\0') *last_char = '/' ;
  534.     stat = TRUE;
  535. out:
  536.     UnLock(my_lock) ;
  537.     FreeMem(File_Info, (LONG) sizeof(struct FileInfoBlock));
  538.     return stat;
  539.     }
  540.  
  541. /*
  542.  * Add all the devices currently known by the system
  543.  * to the current menu, based on the type of device
  544.  * list entry desired.  Disable multitasking while
  545.  * we look inside the device list, so we don't fly off
  546.  * into space while traversing it.
  547.  */
  548. struct DosLibrary    *DosBase;
  549. extern APTR        OpenLibrary();
  550.  
  551. static VOID
  552. Add_Devices(devtype)
  553. ULONG devtype;
  554. {
  555.     register struct DeviceList    *devlist;
  556.     struct RootNode            *rootnode;
  557.     struct DosInfo            *dosinfo;
  558.     UBYTE                buffer[80];
  559.     int                ramflag = 0;
  560.  
  561.     /* if you've gotten this far, none of these will be null. */
  562.     DosBase = (struct DosLibrary *) OpenLibrary(DOSNAME,0L);
  563.  
  564.     Forbid();            /* let's be careful out there... */
  565.     rootnode = (struct RootNode *) DosBase->dl_Root;
  566.     dosinfo = (struct DosInfo *) BADDR(rootnode->rn_Info);
  567.     devlist = (struct DeviceList *) BADDR(dosinfo->di_DevInfo);
  568.  
  569.     while (devlist) {
  570.         /* select by specified device type */
  571.         if (devlist->dl_Type != devtype) {
  572.             devlist = (struct DeviceList *) BADDR(devlist->dl_Next);
  573.             continue;
  574.         }
  575.  
  576.         /* convert device's name into AmigaDOS name and concat a ":" */
  577.         btocstr((BPTR) devlist->dl_Name,buffer,sizeof(buffer));
  578.         strcat(buffer,":");
  579.  
  580.         /* Always add volumes and assigned directories. However,
  581.          * disks should be the only devices added to the list. Magic
  582.          * disk test courtesy of Phillip Lindsay, Commodore-Amiga Inc.
  583.          */
  584.         if (devtype != DLT_DEVICE)
  585.             Menu_Item_Add(buffer, (USHORT)ITEMENABLED,
  586.                     0L, (BYTE)0, TRUE);
  587.         else if (devlist->dl_Task) {    /* why does this work? */
  588.             Menu_Item_Add(buffer, (USHORT)ITEMENABLED,
  589.                     0L, (BYTE)0, TRUE);
  590.             if (!strcmp(buffer,"RAM:")) ramflag = 1;
  591.         }
  592.         devlist = (struct DeviceList *) BADDR(devlist->dl_Next);
  593.     }
  594.     /* if ramdisk isn't loaded yet, add it anyway */
  595.     if ((devtype == DLT_DEVICE) && !ramflag)
  596.         Menu_Item_Add("RAM:",(USHORT)ITEMENABLED, 0L, (BYTE) 0, FALSE);
  597.     Permit();
  598.     CloseLibrary(DosBase);
  599. }
  600.  
  601. btocstr(bp,buf,bufsiz)
  602. BPTR bp;
  603. char *buf;
  604. int bufsiz;
  605. {
  606.     register UBYTE    *cp;
  607.     register int    len, i;
  608.  
  609.     cp = (UBYTE *) BADDR(bp);
  610.     len = (int) *(cp++);
  611.     len = (len > bufsiz) ? bufsiz : len;    /* truncate if necessary */
  612.     for (i = 0; i < len; i++)
  613.         buf[i] = *(cp++);
  614.     buf[i] = '\0';
  615.     return (len < bufsiz);            /* return FALSE if truncated */
  616. }
  617.  
  618. #endif    BROWSER
  619.