Example #1
0
/*
 *  Routine to read in the start of the emudesk.inf file,
 *  expected to contain the #E and #Z lines.
 */
static void sh_rdinf(void)
{
    WORD    fh;
    LONG    size, ret;
    char    *pfile;
    char    tmpstr[MAX_LEN];

    infbuf[0] = 0;

    strcpy(tmpstr, INF_FILE_NAME);
    pfile = tmpstr;
    *pfile += dos_gdrv();                   /* set the drive        */

    ret = dos_open(pfile, ROPEN);
    if (ret < 0L)
        return;
    fh = (WORD)ret;

    /* NOTA BENE: all required info MUST be within INF_SIZE
     * bytes from the beginning of the file
     */
    size = dos_read(fh, INF_SIZE, infbuf);
    dos_close(fh);
    if (size < 0L)      /* if read error, force empty buffer */
        size = 0L;
    infbuf[size] = 0;
}
Example #2
0
void sh_curdir(BYTE *ppath)
{
        WORD    drive;
                                                /* remember current     */
                                                /*  directory           */
        drive = dos_gdrv();
        LBSET(ppath++, (drive + 'A') );
        LBSET(ppath++, ':');
        LBSET(ppath++, '\\');
        dos_gdir( drive+1, ppath );
}
Example #3
0
static BYTE *fs_pspec(BYTE *pstr, BYTE *pend)
{
        pend = fs_back(pstr, pend);
        if (*pend == '\\')
          pend++;
        else
        {
          strcpy(pstr, "A:\\*.*");
          pstr[0] += (BYTE) dos_gdrv();
          pend = pstr + 3;
        }
        return(pend);
}
Example #4
0
VOID get_path(BYTE *tmp_path, BYTE *spec)
{
	WORD	cur_drv;

#if GEMDOS
	cur_drv = Dgetdrv();
#else
	cur_drv = dos_gdrv();
#endif
	tmp_path[0] = cur_drv + 'A';
	tmp_path[1] = ':';
	tmp_path[2] = '\\';
#if GEMDOS
	Dgetpath((char *)ADDR(&tmp_path[3]), cur_drv+1);
#else
	dos_gdir(cur_drv+1, ADDR(&tmp_path[3]));
#endif
	if (strlen(tmp_path) > 3)
		strcat(tmp_path, "\\");
	else
		tmp_path[2] = '\0';
	strcat(tmp_path, spec);
}
Example #5
0
/*
*       Routine to read in the start of the emudesk.inf file,
*       expected to contain the #E and #Z lines.
*/
static void sh_rdinf(void)
{
        WORD    fh, size;
        char    *pfile;
        char    tmpstr[MAX_LEN];

        infbuf[0] = 0;

        strcpy(tmpstr, INF_FILE_NAME);
        pfile = tmpstr;
        *pfile += dos_gdrv();                   /* set the drive        */

        fh = dos_open(pfile, ROPEN);
        if ( !fh || DOS_ERR)
          return;
                                                /* NOTA BENE all required info */
                                                /*  MUST be within INF_SIZE    */
                                                /*  bytes from beg of file     */
        size = dos_read(fh, INF_SIZE, (LONG)infbuf);
        dos_close(fh);
        if (DOS_ERR)
          return;
        infbuf[size] = 0;
}
Example #6
0
void gem_main(void)
{
    WORD    i;
    const BITBLK *tmpadbi;

    sh_rdinf();                 /* get start of emudesk.inf */
    if (!gl_changerez)          /* can't be here because of rez change,       */
        process_inf1();         /*  so see if .inf says we need to change rez */

    if (gl_changerez) {
        switch(gl_changerez) {
#if CONF_WITH_SHIFTER
        case 1:                     /* ST(e) or TT display */
            Setscreen(-1L,-1L,gl_nextrez-2,0);
            initialise_palette_registers(gl_nextrez-2,0);
            break;
#endif
#if CONF_WITH_VIDEL
        case 2:                     /* Falcon display */
            Setscreen(-1L, -1L, FALCON_REZ, gl_nextrez);
            initialise_palette_registers(FALCON_REZ,gl_nextrez);
            break;
#endif
        }
        gsx_wsclear();              /* avoid artefacts that may show briefly */
    }

    totpds = NUM_PDS;
    ml_ocnt = 0;

    gl_changerez = FALSE;

    ini_dlongs();               /* init longs */
    cli();
    takecpm();                  /* take the 0efh int. */

    /* init event recorder  */
    gl_recd = FALSE;
    gl_rlen = 0;
    gl_rbuf = 0x0L;
    /* initialize pointers to heads of event list and thread list */
    elinkoff = (BYTE *) &(D.g_intevb[0].e_link) - (BYTE *) &(D.g_intevb[0]);

    /* link up all the evb's to the event unused list */
    eul = NULLPTR;
    ev_init(&D.g_intevb[0], NUM_IEVBS);
    if (totpds > 2)
        ev_init(&D.g_extevb[0], NUM_EEVBS);

    /* initialize sync blocks */
    wind_spb.sy_tas = 0;
    wind_spb.sy_owner = NULLPTR;
    wind_spb.sy_wait = 0;

    /*
     * init processes - TODO: should go in gempd or gemdisp.
     */

    /* initialize list and unused lists   */
    nrl = drl = NULLPTR;
    dlr = zlr = NULLPTR;
    fph = fpt = fpcnt = 0;

    /* init initial process */
    for(i=totpds-1; i>=0; i--)
    {
        rlr = pd_index(i);
        if (i < 2)
        {
            rlr->p_uda = &D.g_intuda[i];
            rlr->p_cda = &D.g_intcda[i];
        }
        else
        {
            rlr->p_uda = &D.g_extuda[i-2];
            rlr->p_cda = &D.g_extcda[i-2];
        }
        rlr->p_qaddr = (LONG)(&rlr->p_queue[0]);
        rlr->p_qindex = 0;
        memset(rlr->p_name, ' ', 8);
        rlr->p_appdir[0] = '\0'; /* by default, no application directory */
        /* if not rlr then initialize his stack pointer */
        if (i != 0)
            rlr->p_uda->u_spsuper = &rlr->p_uda->u_supstk;
        rlr->p_pid = i;
        rlr->p_stat = 0;
    }
    curpid = 0;
    rlr->p_pid = curpid++;
    rlr->p_link = NULLPTR;

    /* end of process init */

    /* restart the tick     */
    sti();

    /*
     * screen manager process init. this process starts out owning the mouse
     * and the keyboard. it has a pid == 1
     */
    gl_dacnt = 0;
    gl_mowner = ctl_pd = iprocess("SCRENMGR", ctlmgr);

    /* load gem resource and fix it up before we go */
    gem_rsc_init();
    {
        /* get mice forms       */
        ad_armice = *(LONG *)&rs_bitblk[MICE00];
        ad_hgmice = *(LONG *)&rs_bitblk[MICE02];

        /* init button stuff    */
        gl_btrue = 0x0;
        gl_bdesired = 0x0;
        gl_bdely = 0x0;
        gl_bclick = 0x0;

        gl_logdrv = dos_gdrv() + 'A';   /* boot directory       */
        gsx_init();                     /* do gsx open work station */

        /* load all desk acc's  */
        if (totpds > 2)
            ldaccs();

        /* fix up icons         */
        for(i=0; i<3; i++) {
            tmpadbi = &rs_bitblk[NOTEBB+i];
            memcpy((char *)&bi, tmpadbi, sizeof(BITBLK));
            gsx_trans(bi.bi_pdata, bi.bi_wb, bi.bi_pdata, bi.bi_wb, bi.bi_hl);
        }

        /* take the critical err handler int. */
        cli();
        takeerr();
        sti();

        /* go into graphic mode */
        sh_tographic();

        /* take the tick int.   */
        cli();
        gl_ticktime = gsx_tick(tikaddr, &tiksav);
        sti();

        /* set init. click rate: must do this after setting gl_ticktime */
        ev_dclick(3, TRUE);

        /* fix up the GEM rsc. file now that we have an open WS */
        gem_rsc_fixit();

        /* get st_desk ptr */
        ad_stdesk = (LONG) rs_trees[DESKTOP];

        /* init. window vars. */
        wm_start();

        /* startup gem libs */
        fs_start();

        /* remember current desktop directory */
        sh_curdir(D.s_cdir);

        /* process emudesk.inf part 2 */
        process_inf2();

        /* off we go !!!        */
        dsptch();

        /* let them run         */
        all_run();

        /*
         * init for shell loop up thru here it is okay for system to
         * overlay this initialization code
         */
        sh_init();

        /*
         * main shell loop. From here on down data should not overlay
         * this code
         */
        sh_main();

        /* give back the tick   */
        cli();
        gl_ticktime = gsx_tick(tiksav, &tiksav);
        sti();

        /* close workstation    */
        gsx_wsclose();
    }

    /* return GEM's 0xEF int*/
    cli();
    givecpm();
    sti();
}
Example #7
0
/*
 *  This function is called from accdesk_start (in gemstart.S) which
 *  is itself called from gem_main() below.
 *
 *  It runs under a separate process which terminates on shutdown or
 *  resolution change (see accdesk_start).  This ensures that all
 *  memory allocated to or by desk accessories is automatically freed
 *  on resolution change.
 */
void run_accs_and_desktop(void)
{
    WORD i;
    BOOL isgem;

    /* load gem resource and fix it up before we go */
    gem_rsc_init();

    /* get mice forms */
    ad_armice = (MFORM *)rs_bitblk[MICE00].bi_pdata;
    ad_hgmice = (MFORM *)rs_bitblk[MICE02].bi_pdata;

    /* init button stuff */
    gl_btrue = 0x0;
    gl_bdesired = 0x0;
    gl_bdely = 0x0;
    gl_bclick = 0x0;

    gl_logdrv = dos_gdrv() + 'A';   /* boot directory       */
    gsx_init();                     /* do gsx open work station */

    load_accs(num_accs);            /* load up to 'num_accs' desk accessories */

    /* fix up icons */
    for (i = 0; i < 3; i++) {
        memcpy(&bi, &rs_bitblk[NOTEBB+i], sizeof(BITBLK));
        gsx_trans(bi.bi_pdata, bi.bi_wb, bi.bi_pdata, bi.bi_wb, bi.bi_hl);
    }

    /* take the critical err handler int. */
    disable_interrupts();
    takeerr();
    enable_interrupts();

    sh_tographic();                 /* go into graphic mode */

    /* take the tick interrupt */
    disable_interrupts();
    gl_ticktime = gsx_tick(tikaddr, &tiksav);
    enable_interrupts();

    /* set initial click rate: must do this after setting gl_ticktime */
    ev_dclick(3, TRUE);

    /* fix up the GEM rsc file now that we have an open WS */
    gem_rsc_fixit();

    wm_start();                     /* initialise window vars */
    fs_start();                     /* startup gem libs */
    sh_curdir(D.s_cdir);            /* remember current desktop directory */
    isgem = process_inf2();         /* process emudesk.inf part 2 */

    dsptch();                       /* off we go !!! */
    all_run();                      /* let them run  */

    sh_init();                      /* init for shell loop */
    sh_main(isgem);                 /* main shell loop */

    /* give back the tick   */
    disable_interrupts();
    gl_ticktime = gsx_tick(tiksav, &tiksav);
    enable_interrupts();

    /* close workstation    */
    gsx_wsclose();
}
Example #8
0
/*
*	Initializes the spooler. Assigns the ted infos to the proper objects
*	and the strings to the proper ted infos.
*/
LONG ini_spol(VOID)
{
	LONG		tree;
	WORD		i, j;

	tree = (LONG)ADDR(&the_spol[0]);

	j = 0;
	for (i=0; i < SPOL_OBS; i++)
	{
		rsrc_obfix((OBJECT FAR *)tree, i);
		if (the_spol[i].ob_type == G_STRING)
		{
#ifdef TURBO_C
			the_spol[i].ob_spec.free_string = ADDR(spol_str[j]);
#else
			the_spol[i].ob_spec = ADDR(spol_str[j]);
#endif
			*spol_str[j] = NULL;
			j++;
		}
		if (the_spol[i].ob_type == G_BUTTON) 
		{
#ifdef TURBO_C
			the_spol[i].ob_spec.free_string = ADDR(spol_str[j]);
#else
			the_spol[i].ob_spec = ADDR(spol_str[j]);
#endif
			j++;
		}
	}

	if (color == 2)
	{
#if TURBO_C
		the_spol[0].ob_spec.index = 0x173L;
#else
		the_spol[0].ob_spec = 0x0173L;
#endif
	}  
	else if (color >= 3)
	{
#ifdef TURBO_C
		the_spol[0].ob_spec.index = 0x0175L;
#else
		the_spol[0].ob_spec = 0x0175L;
#endif
	}  

	for (i=0; i<NUM_SPOL; i++)
	{
		gl_sppfn[i] = NULL;
		*gl_splst[i] = NULL;
		gl_spdel[i] = FALSE;
		gl_sptab[i] = FALSE;
	}
	gl_spnxt = 0;

	the_spol[ADDNAME].ob_state = NORMAL;
	the_spol[REMNAME].ob_state = DISABLED;

 	strcpy("A:\*.*", &gl_fspec[0]);
#if GEMDOS
	gl_fspec[0] += Dgetdrv();
#else
	gl_fspec[0] += dos_gdrv();
#endif

	spol_setup();
	return(tree);
}
Example #9
0
/*
 *  Initialize the application list by reading in the EMUDESK.INF
 *  file, either from memory or from the disk if the shel_get
 *  indicates no message is there.
 */
void app_start(void)
{
    WORD i, x, y;
    ANODE *pa;
    WSAVE *pws;
    BYTE *pcurr, *ptmp, *pauto = NULL;
    WORD envr, xcnt, ycnt, xcent, wincnt, dummy;

    /* remember start drive */
    gl_stdrv = dos_gdrv();

    G.g_pbuff = gl_buffer;

    for (i = NUM_ANODES - 2; i >= 0; i--)
        G.g_alist[i].a_next = &G.g_alist[i + 1];
    G.g_ahead = (ANODE *) NULL;
    G.g_aavail = G.g_alist;
    G.g_alist[NUM_ANODES - 1].a_next = (ANODE *) NULL;

    app_rdicon();

    G.g_wicon = (12 * gl_wschar) + (2 * G.g_iblist[0].ib_xtext);
    G.g_hicon = G.g_iblist[0].ib_hicon + gl_hschar + 2;

    xcnt = G.g_wdesk / (G.g_wicon+MIN_WINT);/* icon count */
    G.g_icw = G.g_wdesk / xcnt;             /* width */

    ycnt = G.g_hdesk / (G.g_hicon+MIN_HINT);/* icon count */
    G.g_ich = G.g_hdesk / ycnt;             /* height */

    shel_get(gl_afile, SIZE_AFILE);
    if (gl_afile[0] != '#')                 /* invalid signature    */
    {                                       /*   so read from disk  */
        LONG ret;
        WORD fh;
        char inf_file_name[16];
        strcpy(inf_file_name, INF_FILE_NAME);
        inf_file_name[0] += gl_stdrv;         /* Adjust drive letter  */
        ret = dos_open(inf_file_name, 0x0);
        if (ret >= 0L)
        {
            fh = (WORD) ret;
            ret = dos_read(fh, SIZE_AFILE, gl_afile);
            G.g_afsize = (ret < 0L) ? 0L : ret;
            dos_close(fh);
            gl_afile[G.g_afsize] = '\0';
        }
    }

    /* If there's still no desktop.inf data, use built-in now: */
    if (gl_afile[0] != '#')
    {
        LONG drivemask;
        char *text;
        int icon_index = 0;
        int drive_x = 0, drive_y = 0;
        int trash_x, trash_y;
        int icon_type;
        char drive_letter;

        /* Environment and Windows */
        strcat(gl_afile, desk_inf_data1);

        /* Scan for valid drives: */
        drivemask = dos_sdrv(dos_gdrv());
        for (i = 0; i < BLKDEVNUM; i++)
        {
            if (drivemask&(1L<<i))
            {
                x = strlen(gl_afile);
                drive_x = icon_index % xcnt; /* x position */
                drive_y = icon_index / xcnt; /* y position */
                icon_type = (i > 1) ? 0 /* Hard disk */ : 1 /* Floppy */;
                drive_letter = 'A' + i;
                rsrc_gaddr(R_STRING, STDISK, (void **)&text);
                sprintf(gl_afile + x, "#M %02X %02X %02X FF %c %s %c@ @\r\n",
                        drive_x, drive_y, icon_type, drive_letter, text, drive_letter);
                icon_index++;
            }
        }

        /* Copy core data part 2 */
        strcat(gl_afile, desk_inf_data2);

        /* add Trash icon to end */
        x = strlen(gl_afile);
        trash_x = 0;            /* Left */
        trash_y = ycnt-1;       /* Bottom */
        if (drive_y >= trash_y) /* if the last drive icon overflows over */
            trash_x = xcnt-1;   /*  the trash row, force trash to right  */
        rsrc_gaddr(R_STRING, STTRASH, (void **)&text);
        sprintf(gl_afile + x, "#T %02X %02X 03 FF   %s@ @\r\n",
                trash_x, trash_y, text);
        G.g_afsize = strlen(gl_afile);
    }

    wincnt = 0;
    inf_rev_level = 0;
    pcurr = gl_afile;

    while(*pcurr)
    {
        if (*pcurr++ != '#')            /* look for start of line */
            continue;

        switch(*pcurr)
        {
        case 'R':                       /* revision level */
            pcurr++;
            pcurr = scan_2(pcurr,&inf_rev_level);
            break;
        case 'Z':                       /* autorun: Z nn pathname@ */
            pcurr = scan_str(pcurr+5,&pauto);   /* save pathname in buffer */
            break;                              /* (a bit wasteful)        */
        case 'T':                       /* Trash */
        case 'M':                       /* Media (Hard/Floppy)  */
        case 'G':                       /* GEM Application      */
        case 'Y':                       /* GEM App. with parms  */
        case 'F':                       /* File (DOS w/o parms) */
        case 'P':                       /* Parm (DOS w/ parms)  */
        case 'D':                       /* Directory            */
        case 'I':                       /* Executable file icon     */
        case 'N':                       /* Non-executable file icon */
            pa = app_alloc(TRUE);
            if (!pa)                    /* paranoia */
                return;
            pcurr = app_parse(pcurr, pa);
            if ((pa->a_type == AT_ISFILE) && pauto)
            {                           /* autorun exists & not yet merged */
                if (strcmp(pauto,pa->a_pappl) == 0)
                {
                    pa->a_flags |= AF_AUTORUN;  /* it's this program */
                    pauto = NULL;               /*  (and no other)   */
                }
            }
            break;
        case 'W':                       /* Window               */
            pcurr++;
            if (wincnt < NUM_WNODES)
            {
                pws = &G.g_cnxsave.cs_wnode[wincnt];
                pcurr = scan_2(pcurr, &dummy);
                pcurr = scan_2(pcurr, &pws->vsl_save);
/* BugFix       */
                pcurr = scan_2(pcurr, &pws->x_save);
                pws->x_save *= gl_wchar;
                pcurr = scan_2(pcurr, &pws->y_save);
                pws->y_save *= gl_hchar;
                pcurr = scan_2(pcurr, &pws->w_save);
                pws->w_save *= gl_wchar;
                pcurr = scan_2(pcurr, &pws->h_save);
                pws->h_save *= gl_hchar;
/* */
                pcurr = scan_2(pcurr, &pws->obid_save);
                ptmp = pws->pth_save;
                pcurr++;
                while(*pcurr != '@')
                    *ptmp++ = *pcurr++;
                *ptmp = '\0';
                wincnt += 1;
            }
            break;
        case 'E':                       /* Environment */
            pcurr++;
            pcurr = scan_2(pcurr, &envr);
            G.g_cnxsave.cs_view = ( (envr & INF_E1_VIEWTEXT) != 0);
            G.g_cnxsave.cs_sort = ( (envr & INF_E1_SORTMASK) >> 5);
            G.g_cnxsave.cs_confdel = ( (envr & INF_E1_CONFDEL) != 0);
            G.g_cnxsave.cs_confcpy = ( (envr & INF_E1_CONFCPY) != 0);
            G.g_cnxsave.cs_dblclick = envr & INF_E1_DCMASK;

            pcurr = scan_2(pcurr, &envr);
            G.g_cnxsave.cs_confovwr = ( (envr & INF_E2_ALLOWOVW) == 0);
            G.g_cnxsave.cs_mnuclick = ( (envr & INF_E2_MNUCLICK) != 0);
            menu_click(G.g_cnxsave.cs_mnuclick, 1); /* tell system */
            if (envr & INF_E2_IDTDATE)
                G.g_cnxsave.cs_datefmt = DATEFORM_IDT;
            else
                G.g_cnxsave.cs_datefmt = (envr & INF_E2_DAYMONTH) ? DATEFORM_DMY : DATEFORM_MDY;
            if (envr & INF_E2_IDTTIME)
                G.g_cnxsave.cs_timefmt = TIMEFORM_IDT;
            else
                G.g_cnxsave.cs_timefmt = (envr & INF_E2_24HCLOCK) ? TIMEFORM_24H : TIMEFORM_12H;
            sound(FALSE, !(envr & INF_E2_SOUND), 0);

            pcurr = scan_2(pcurr, &dummy);  /* skip video stuff */
            pcurr = scan_2(pcurr, &dummy);

            pcurr = scan_2(pcurr, &envr);
            if (envr & INF_E5_NOSORT)
                G.g_cnxsave.cs_sort = CS_NOSORT;
            break;
        }
    }

    for (pa = G.g_ahead; pa; pa = pa->a_next)
    {
        if (pa->a_flags & AF_ISDESK)
        {
            x = pa->a_xspot * G.g_icw;
            y = pa->a_yspot * G.g_ich + G.g_ydesk;
            snap_disk(x, y, &pa->a_xspot, &pa->a_yspot, 0, 0);
        }
    }

    /* set up outlines for dragging files displayed as icons */
    G.g_nmicon = 9;     /* number of points */
    memset(G.g_xyicon, 0, sizeof(G.g_xyicon));
    xcent = (G.g_wicon - G.g_iblist[0].ib_wicon) / 2;
    G.g_xyicon[0] = xcent;
    G.g_xyicon[2] = xcent;
    G.g_xyicon[3] = G.g_hicon-gl_hschar-2;
    G.g_xyicon[5] = G.g_hicon-gl_hschar-2;
    G.g_xyicon[7] = G.g_hicon;
    G.g_xyicon[8] = G.g_wicon;
    G.g_xyicon[9] = G.g_hicon;
    G.g_xyicon[10] = G.g_wicon;
    G.g_xyicon[11] = G.g_hicon-gl_hschar-2;
    G.g_xyicon[12] = G.g_wicon-xcent;
    G.g_xyicon[13] = G.g_hicon-gl_hschar-2;
    G.g_xyicon[14] = G.g_wicon-xcent;
    G.g_xyicon[16] = xcent;

    /* set up outlines for dragging files displayed as text */
    G.g_nmtext = 5;     /* number of points */
    memset(G.g_xytext, 0, sizeof(G.g_xytext));
    G.g_xytext[2] = gl_wchar * DRAG_BOX_WIDTH;
    G.g_xytext[4] = gl_wchar * DRAG_BOX_WIDTH;
    G.g_xytext[5] = gl_hchar;
    G.g_xytext[7] = gl_hchar;
}
Example #10
0
/*
*       File Selector input routine that takes control of the mouse
*       and keyboard, searchs and sort the directory, draws the file 
*       selector, interacts with the user to determine a selection
*       or change of path, and returns to the application with
*       the selected path, filename, and exit button.
*/
WORD fs_input(BYTE *pipath, BYTE *pisel, WORD *pbutton, BYTE *pilabel)
{
        register WORD   touchob, value, fnum;
        WORD            curr, count, sel;
        WORD            mx, my;
        LONG            tree;
        ULONG           bitmask;
        BYTE            *ad_fpath, *ad_fname, *ad_ftitle;
        WORD            drive; 
        WORD            dclkret, cont, newlist, newsel, newdrive;
        register BYTE   *pstr;
        GRECT           pt;
        BYTE            locstr[LEN_ZPATH+1], mask[LEN_ZFNAME+1], selname[LEN_FSNAME];
        OBJECT          *obj;
        TEDINFO         *tedinfo;

        curr = 0;
        count = 0;
                                        /* get out quick if path is     */
                                        /*   nullptr or if pts to null. */
        if (pipath == NULL)
          return(FALSE);
                                        /* if path string is empty, */
                                        /*   set reasonable default */
        if (*pipath == '\0') {
          strcpy(pipath,"A:\\*.*");
          *pipath += dos_gdrv();
        }
                                        /* get memory for the filename buffer */
                                        /*  & the array that points to it     */
        for (nm_files = MAX_NM_FILES; nm_files >= MIN_NM_FILES; nm_files /= 2)
        {
          ad_fsnames = (BYTE *)dos_alloc(nm_files*(LEN_FSNAME+sizeof(BYTE *)));
          if (ad_fsnames)
            break;
        }
        if (!ad_fsnames)
          return(FALSE);
        g_fslist = (LONG *)(ad_fsnames+nm_files*LEN_FSNAME);

        strcpy(locstr, pipath);

        tree = ad_fstree;
                                                /* init strings in form */
        obj = ((OBJECT *)tree) + FTITLE;
        tedinfo = (TEDINFO *)obj->ob_spec;
        ad_ftitle = (BYTE *)tedinfo->te_ptext;
        set_mask(mask, locstr);                 /* save caller's mask */
        strcpy(ad_ftitle, mask);                /*  & copy to title line */

        obj = ((OBJECT *)tree) + FSDIRECT;
        tedinfo = (TEDINFO *)obj->ob_spec;
        ad_fpath = (BYTE *)tedinfo->te_ptext;
        inf_sset(tree, FSDIRECT, locstr);

        obj = ((OBJECT *)tree) + FSSELECT;
        tedinfo = (TEDINFO *)obj->ob_spec;
        ad_fname = (BYTE *)tedinfo->te_ptext;
        fmt_str(pisel, selname);                /* selname[] is without dot */
        inf_sset(tree, FSSELECT, selname);

        obj = ((OBJECT *)tree) + FSTITLE;
        obj->ob_spec = pilabel ? (LONG)pilabel : (LONG)rs_str(ITEMSLCT);

                                                /* set drive buttons */
        obj = ((OBJECT *)tree) + DRIVE_OFFSET;
        for (drive = 0, bitmask = 1; drive < NM_DRIVES; drive++, bitmask <<= 1, obj++)
        {
          if (drvbits & bitmask)
            obj->ob_state &= ~DISABLED;
          else
            obj->ob_state |= DISABLED;
        }
        select_drive(tree,locstr[0]-'A',0);
                                                /* set clip and start   */
                                                /*   form fill-in by    */
                                                /*   drawing the form   */
        gsx_sclip(&gl_rfs);     
        fm_dial(FMD_START, &gl_rfs);
        ob_draw(tree, ROOT, 2);
                                                /* init for while loop  */
                                                /*   by forcing initial */
                                                /*   fs_newdir call     */
        sel = 0;
        newsel = FALSE;
        cont = newlist = TRUE;
        while( cont )
        {
          touchob = (newlist) ? 0x0 : fm_do(tree, FSSELECT);
          gsx_mxmy(&mx, &my);
        
          if ( newlist )
          {
            fs_sel(sel, NORMAL);
            if ( (touchob == FSOK) ||
                 (touchob == FSCANCEL) )
              ob_change(tree, touchob, NORMAL, TRUE);
            inf_sset(tree, FSDIRECT, locstr);
            pstr = fs_pspec(locstr, NULL);        
            strcpy(pstr, mask);
            fs_newdir(locstr, mask, tree, &count);
            curr = 0;
            sel = touchob = 0;
            newlist = FALSE;
          }

          value = 0;
          dclkret = ((touchob & 0x8000) != 0);
          switch( (touchob &= 0x7fff) )
          {
            case FSOK:
            case FSCANCEL:
                cont = FALSE;
                break;
            case FUPAROW:
            case FDNAROW:
                value = 1;
                break;
            case FSVSLID:
                ob_actxywh(tree, FSVELEV, &pt);
                /* anemic slidebars
                  pt.g_x -= 3;
                  pt.g_w += 6;
                */
                if ( !inside(mx, my, &pt) )
                  {
                  touchob = (my <= pt.g_y) ? FUPAROW : FDNAROW;
                  value = NM_NAMES;
                  break;
                  }
                /* drop through */
            case FSVELEV:
                fm_own(TRUE);
                value = gr_slidebox(tree, FSVSLID, FSVELEV, TRUE);
                fm_own(FALSE);
                value = curr - mul_div(value, count-NM_NAMES, 1000);
                if (value >= 0)
                  touchob = FUPAROW;
                else
                {
                  touchob = FDNAROW;
                  value = -value;
                }
                break;
            case F1NAME:
            case F2NAME:
            case F3NAME:
            case F4NAME:
            case F5NAME:
            case F6NAME:
            case F7NAME:
            case F8NAME:
            case F9NAME:
                fnum = touchob - F1NAME + 1;
                if ( fnum > count )
                  break;
                if ( (sel) && (sel != fnum) )
                  fs_sel(sel, NORMAL);
                if ( sel != fnum)
                {
                  sel = fnum;
                  fs_sel(sel, SELECTED);
                }
                                                /* get string and see   */
                                                /*   if file or folder  */
                inf_sget(tree, touchob, selname);
                if (selname[0] == ' ')          /* a file was selected  */
                {                               /* copy to selection    */
                  newsel = TRUE;
                  if (dclkret)
                    cont = FALSE;
                }
                else                            /* a folder was selected:  */
                {                               /* insert name before mask */
                  pstr = fs_pspec(locstr, NULL);
                  unfmt_str(selname+1, pstr);
                  pstr += strlen(pstr);
                  *pstr++ = '\\';
                  strcpy(pstr, mask);
                  newlist = TRUE;
                }
                break;
            case FCLSBOX:
                pstr = fs_back(locstr, NULL);
                if (*pstr-- != '\\')    /* ignore strange path string */
                  break;
                if (*pstr != ':')       /* not at root of drive, so back up */
                {
                  pstr = fs_back(locstr, pstr);
                  if (*pstr == '\\')    /* we must have at least X:\ */
                    strcpy(pstr+1, mask);
                }
                newlist = TRUE;
                break;
            default:
                drive = touchob - DRIVE_OFFSET;
                if ((drive < 0) || (drive >= NM_DRIVES))/* not for us */
                  break;
                if (drive == locstr[0] - 'A')           /* no change */
                  break;
                obj = ((OBJECT *)tree) + touchob;
                if (obj->ob_state & DISABLED)           /* non-existent drive */
                  break;
                strcpy(locstr, "A:\\*.*");
                locstr[0] += drive;
                newdrive = TRUE;
                break;
          }
          if (!newlist && !newdrive
           && path_changed(locstr))                     /* path changed manually */
          {
            if (ad_fpath[0] != locstr[0])               /* drive has changed */
              newdrive = TRUE;
            else
              newlist = TRUE;
            strcpy(locstr, ad_fpath);
          }
          if (newdrive)
          {
            select_drive(tree, touchob-DRIVE_OFFSET,1);
            newdrive = FALSE;
            newlist = TRUE;
          }
          if (newlist)
          {
            inf_sset(tree, FSDIRECT, locstr);
            set_mask(mask, locstr);                 /* set mask         */
            selname[1] = '\0';                      /* selected is empty */
            newsel = TRUE;
          }
          if (newsel)
          {
            strcpy(ad_fname, selname + 1);
            ob_draw(tree, FSSELECT, MAX_DEPTH);
            if (!cont)
              ob_change(tree, FSOK, SELECTED, TRUE);
            newsel = FALSE;
          }
          if (value)
            curr = fs_nscroll(tree, &sel, curr, count, touchob, value);
        }
                                                /* return path and      */
                                                /*   file name to app   */
        strcpy(pipath, locstr);
        unfmt_str(ad_fname, selname);
        strcpy(pisel, selname);
                                                /* start the redraw     */
        fm_dial(FMD_FINISH, &gl_rfs);
                                                /* return exit button   */
        *pbutton = inf_what(tree, FSOK, FSCANCEL);
        dos_free((LONG)ad_fsnames);

        return( TRUE );
}