home *** CD-ROM | disk | FTP | other *** search
- /* Adjustable Ram Disk
-
- (c) Copyright 1986 by Gary Cramblitt. All Rights Reserved.
-
- v2.2 1 Jul 86 Initial version
- v2.3 24 Aug 86 Bug. FAT media byte not updated properly.
- v2.4 29 Aug 86 If current drive is memory disk drive, reset current
- directory on exit.
- v2.5 30 Aug 86 Increase FAT to permit max size of 2043K;
- Increase size of root directory to 128 entries;
- Start code for /E option (Expanded Memory Support)
- v3.0 30 Aug 86 Finish code for /E option.
-
- For program usage, see the last routine.
-
- This program is coded in DeSmet C v2.4. Any function beginning
- with underscore (_) is a non-standard routine from the DeSmet library.
- They are:
- _showcs()
- Synopsis: unsigned _showcs()
-
- Returns the current value of CS.
-
- _showds()
- Synopsis: unsigned _showds()
-
- Returns the current value of DS (= SS in DeSmet C).
-
- _peek()
- Synopsis: char _peek(offset,segment)
- char *offset;
- unsigned segment;
- Returns the byte at specified far address.
-
- _doint()
- Synopsis: set any or all of the externs
- _rax,_rbx,_rcx,_rdx,_rsi,_rdi,_res,_rds
- followed by
- _doint(interrupt number);
- Performs the specified interrupt with the specified
- registers set from the externs.
-
- After the call, _rax, etc. can be used. _carryf
- and _zerof are extern char variables set to 1 if
- the carry or zero flag is set.
-
- In addition, the following routines are semi_standard, and may have
- slightly different implementations with your compiler:
-
- strncmp()
- Synopsis: char *strncmp(leftstring,rightstring,max)
- char *leftstring, *rightstring
- int max
- strncmp() compares up to a specified number of chars
- in two strings. It returns 0 if the specified number
- of characters in the string are the same.
-
- free()
- Synopsis: int free(pointer)
- char *pointer
- free memory previously allocated (by calloc). Called
- "cfree" in K&R.
- */
-
- /* ==== Definitions ==== */
-
- /* ---- Overall Definitions ---- */
-
- #define true 1
- #define false 0
- #define max_size 2043 /* max memory disk size */
-
- /*
- ---- To compile without LOTUS/INTEL/Microsoft Expanded Memory
- support, change the "1" to "0" in the next statement. This
- will save about 2500 bytes in the .EXE file.
- */
-
- #define em_support 1 /* compile for EM support */
-
- /*
- The following symbols must correspond to the same symbols in
- file amdisk.asm. If one is changed, so must the other.
- This is because the first memory block may not be
- deallocated.
- */
-
- #define min_size 64 /* minimum 64K = 128 sectors */
- #define sec_per_blk 64 /* increment in 32K blocks */
-
- /*
- ---- Disk definitions. Note: These constants should be made into
- variables or functions if this program's algorithms need to
- be generalized to disks of any type, especially high density disks.
- Since this program works only in conjunction with amdisk.asm,
- is OK to make them constants here.
- */
-
- #define bytes_per_sec 512 /* 512 bytes per sector */
- #define par_per_sec (512/16)
- /* 32 paragraphs per sector */
- #define sec_per_K (1024/512)
- /* sectors per 1024 bytes */
- #define dir_per_sec (512/sizeof(struct dir_entry))
- /* directory entries per sector */
- #define em_pag_per_blk 2 /* two 16K EM pages per mem block */
-
- /* ---- Program Segment Prefix ---- */
-
- #define environment_segment 0x2c /* segment address of the environment */
-
- /* ---- DOS interrupts ---- */
-
- #define dosi_dosf 0x21 /* DOS function interrupt */
- #define dosi_dsk_read 0x25 /* DOS absolute disk read interrupt */
- #define dosi_dsk_write 0x26 /* DOS absolute disk write interrupt */
-
- /* ---- User interrupts ---- */
-
- #define usri_emm 0x67 /* LOTUS/INTEL/Microsoft Expanded
- Memory Manager */
- /* ---- DOS functions ---- */
-
- #define dosf_seldisk 0x0e /* set default disk */
- #define dosf_getdisk 0x19 /* get current default disk */
- #define dosf_getver 0x30 /* get DOS version number */
- #define dosf_keepprc 0x31 /* keep process (term and stay resident) */
- #define dosf_drvfre 0x36 /* get disk free space */
- #define dosf_chdir 0x3b /* set default directory */
- #define dosf_openh 0x3d /* open file handle */
- #define dosf_closeh 0x3e /* close file handle */
- #define dosf_ioctl 0x44 /* IOCTL */
- #define dosf_cwd 0x47 /* get current directory */
- #define dosf_alloc 0x48 /* allocate memory block */
- #define dosf_dealloc 0x49 /* deallocate memory block */
- #define dosf_setblk 0x4a /* modify memory block */
-
- /* ---- LOTUS/INTEL/Microsoft Expanded Memory Manager functions ---- */
-
- #define emm_status 0x40 /* get manager status */
- #define emm_get_PFseg 0x41 /* get page frame segment */
- #define emm_get_pages 0x42 /* get number of pages */
- #define emm_get_handle 0x43 /* get handle and allocate memory */
- #define emm_map_memory 0x44 /* map memory */
- #define emm_fre_handle 0x45 /* free handle and memory */
- #define emm_get_ver 0x46 /* get EMM version */
- #define emm_sav_map 0x47 /* save mapping context */
- #define emm_res_map 0x48 /* restore mapping context */
- #define emm_num_handles 0x4b /* get number of EMM handles */
- #define emm_hdl_pages 0x4c /* get pages owned by handle */
- #define emm_all_pages 0x4d /* get pages for all handles */
- #define emm_pag_map 0x4e /* get or set page map */
-
- #define nor_flg 0 /* memory block is in normal memory */
- #define em_flg 1 /* memory block is in expaned memory */
-
- /*
- ---- DOS Errors ----
- These codes are returned by program and can be tested with DOS
- IF statement.
- */
-
- #define dose_noerr 0 /* no error */
- #define dose_invfunc 1 /* invalid function */
- #define dose_arena 7 /* arena trashed */
- #define dose_noram 8 /* not enough memory */
- #define dose_invdrv 15 /* invalid drive */
-
- /* ---- Directory definitions ---- */
-
- #define never_used 0 /* directory entry never used */
- #define erased 0xe5 /* file has been erased */
- #define dir_bit 0x10 /* this bit indicates subdirectory */
-
- /* ---- FAT definitions ---- */
-
- #define available 0 /* cluster is available for use */
- #define bad 0xff7 /* cluster is bad */
- #define last_low 0xff8 /* last cluster for the file */
- #define last_high 0xfff /* last cluster for the file */
-
- extern unsigned _rax, _rbx, _rcx, _rdx, _rsi, _rdi, _res, _rds;
- extern char _carryf, _zerof;
-
- /* ---- Directory entry ---- */
-
- struct dir_entry {
- union dir_name {
- char name[8];
- unsigned char status;
- } u_name;
- char ext[3];
- unsigned char attr;
- unsigned char reserved[10];
- unsigned int time;
- unsigned int date;
- unsigned int first_cluster;
- unsigned long size;
- };
-
- /* ==== Global Data Storage ==== */
-
- unsigned int pgm_seg; /* CS at start of program saved here */
- int drive_number; /* memory disk drive number A=0, B=1, etc */
- int mdisk_size; /* user's desired memory disk size in K */
- int mdisk_secs; /* user's desired memory disk size in sectors */
- int mdisk_chg; /* the difference between disk's current size
- and the desired size (in sectors) */
- int free_secs; /* unused sectors in the memory disk */
- int first_dir_sector;
- int last_dir_sector; /* loc of directory */
- int first_fat_sector;
- int last_fat_sector; /* loc of FAT */
- int free_cluster; /* ptr to first free cluster */
- int first_data_sector; /* first sector after the last FAT */
-
- /* ---- Memory Disk Boot Record ---- */
-
- struct boot_record {
- unsigned char jmp[3]; /* non-bootable (no jump instruction ) */
- char ident[8]; /* identification */
- unsigned int bytes_in_sector;/* bytes/sector */
- unsigned char sec_per_cluster;/* sectors/cluster */
- unsigned int bpb_reserved; /* reserved sectors */
- unsigned char bpb_fats; /* number of FAT's */
- unsigned int bpb_root; /* directory entries in root */
- unsigned int bpb_total; /* total number of sectors */
- unsigned char bpb_media; /* media byte = number of mem blocks */
- unsigned int bpb_fat_size; /* sectors/FAT */
-
- unsigned int sec_per_track; /* sectors/track */
- unsigned int heads; /* number of heads */
- unsigned int hidden; /* hidden sectors */
-
- struct mem_blk_table_entry {
- unsigned char typ; /* type of blk: 0 = normal 1 = EM */
- unsigned int par; /* paragraph address of block */
- unsigned int siz; /* number of sectors in the memory block */
- unsigned int hdl; /* expanded memory handle */
- } mem_blk_table[max_size/sec_per_blk];
- char rest_of_record[bytes_per_sec - sizeof(struct boot_record)];
- } boot_sec;
-
- /* ---- Memory disk default pathname ----- */
-
- struct pathname {
- char drv;
- char colon;
- char slash;
- char dir[64];
- } mdisk_pathname; /* Ram disk's current pathname */
-
- /* ---- Default drive ---- */
-
- unsigned char default_drive;
-
- /* ---- Expanded Memory Manager ----- */
-
- unsigned int em_PFseg; /* EMM's page frame segment */
- int em_requested; /* true if to expand using EM */
- char em_device_name[] = "EMMXXXX0"; /* EMM device name */
-
- /* ---- File Allocation Table ----*/
-
- unsigned char *fat;
-
- /* ---- Declare types of library functions which return non-integer values */
-
- char *calloc(); /* allocates memory for given number of things */
- char *strncmp(); /* comapares 2 strings of specified length */
- unsigned _showcs(); /* returns current CS register */
- char _peek(); /* returns a byte given segment and offset */
-
- /* ==== MAIN ROUTINE ==== */
-
- main(argc, argv)
- int argc;
- char *argv[];
-
- {
- int err_code; /* exit error code ( 0 if no error ) */
- int result;
- int j;
- int k;
- int m;
-
- /*
- ---- Begin by saving the CS, which points to just after the 256-byte
- PSP. By subtracting 16, we get the segment pointer for the
- program segment. This is, of course, highly DeSmet C dependent
- code. Hopefully, your compiler has some mechanism for getting
- the program segment pointer.
- */
-
- pgm_seg = _showcs() - 16;
- printf("Adjust Memory Disk v3.0 ");
- #if em_support
- printf("(with EM Support) ");
- #endif
- printf(" (c) Copyright 1986 by Gary Cramblitt\n");
- err_code = dose_noerr; /* set no error */
-
- /* ---- Make sure MS-DOS 2 or above ---- */
-
- _rax = dosf_getver << 8;
- _doint(dosi_dosf);
- if (_rax & 0x00ff < 2) {
- printf ("Error -- this program requires DOS version 2 or above.\n");
- exit(dose_invfunc);
- }
-
- /*
- ---- Release our own environment block. It doesn't hurt to do so.
- Done so we don't have to do it in the future when user requests
- memory disk shrinkage.
- */
-
- _res = peekw(environment_segment, pgm_seg);
- _rax = dosf_dealloc << 8;
- _doint(dosi_dosf);
- if (_carryf == 1) {
- printf("Error -- could not free environment block. Error code %d\n",
- _rax);
- exit(dose_arena);
- }
-
- /*
- ---- Parse the command line drive letter.
- If user makes an error, give him usage message and exit.
- */
-
- if (argc < 2 ||
- (drive_number = (toupper(*argv[1]) - 65)) < 0 || drive_number > 8) {
- dsp_usage();
- exit(dose_invfunc);
- }
-
- /*
- ---- Read the boot sector from the memory disk. Verify that we are
- dealing with the correct memory disk.
- */
-
- if ((result = readsec(drive_number, 0, &boot_sec)) != 0) {
- printf("Error -- could not read boot sector. Error code %1d\n", result);
- exit(dose_invdrv);
- }
- if (strcmp(boot_sec.ident,"AMDISK ") != 0) {
- printf("Error -- that drive is not the adjustable memory disk!\n");
- exit(dose_invdrv);
- }
-
- /* ---- Determine the drive's current size and free space. */
-
- mdisk_size = boot_sec.bpb_total/sec_per_K;
- _rax = dosf_drvfre << 8;
- _rdx = drive_number + 1;
- _doint(dosi_dosf);
- if (_rax == 0xffff) {
- printf("Error -- Invalid drive letter or memory disk is not loaded.\n");
- exit(dose_invdrv);
- }
- free_secs = _rbx * _rax; /* avail clusters * sectors per cluster */
- printf("Drive %c: Total Size: %dK Free Space: %dK\n",
- drive_number + 65, mdisk_size, free_secs/sec_per_K);
-
- /* ---- Obtain the default disk. ---- */
-
- _rax = dosf_getdisk << 8;
- _doint(dosi_dosf);
- default_drive = _rax & 0x00ff;
-
- /* ---- Get the memory disk's current directory. ---- */
-
- mdisk_pathname.drv = drive_number + 'A';
- mdisk_pathname.colon = ':';
- mdisk_pathname.slash = '\\';
- _rax = dosf_cwd << 8;
- _rdx = drive_number + 1;
- _rds = _showds();
- _rsi = mdisk_pathname.dir;
- _doint(dosi_dosf);
-
- /* ---- Allocate storage for the FAT and read it in. ---- */
-
- fat = calloc(boot_sec.bpb_fat_size, bytes_per_sec);
- first_fat_sector = boot_sec.bpb_reserved;
- last_fat_sector = first_fat_sector + boot_sec.bpb_fat_size - 1;
- k = 0;
- for (j = first_fat_sector; j <= last_fat_sector; j++) {
- readsec(drive_number, j, fat + k);
- k = k + bytes_per_sec;
- }
-
- /*
- ---- Determine what user wants to do -- expand or shrink the memory
- disk, and by how much.
- */
-
- if (argc >= 3) {
- if (toupper(*argv[2]) == 'F')
- mdisk_chg = atoi(argv[2]+1) - free_secs/sec_per_K;
- else if (toupper(*argv[2]) == 'M') {
- mdisk_chg = atoi(argv[2]+1) - free_secs/sec_per_K;
- if (mdisk_chg < 0) mdisk_chg = 0;
- } else {
- mdisk_chg = atoi(argv[2]);
- if (*argv[2] == '+' || *argv[2] == '-'); else
- mdisk_chg = mdisk_chg - (boot_sec.bpb_total/sec_per_K);
- }
- } else exit(dose_noerr);
- mdisk_size = mdisk_chg + (boot_sec.bpb_total/sec_per_K);
- mdisk_size = ((mdisk_size + (sec_per_blk/sec_per_K - 1))/
- (sec_per_blk/sec_per_K))*(sec_per_blk/sec_per_K); /* round to 32K */
- mdisk_secs = mdisk_size * sec_per_K;
- mdisk_chg = mdisk_secs - boot_sec.bpb_total;
- printf(" Desired Size: %dK Desired Change: %dK\n",
- mdisk_size, mdisk_chg/sec_per_K);
- if (mdisk_size < min_size || mdisk_size > max_size) {
- dsp_usage();
- exit(dose_invfunc);
- }
-
- /*
- ---- If expanding into Expanded Memory, check to make sure that
- EMM is available. Check is made by opening the EMM device.
- If open fails, EMM is not loaded. Get page frame segment from
- EMM. Raw DOS handle open is used here to avoid bringing in
- huge DeSmet IO routines.
- */
-
- em_requested = false;
- #if em_support
- if (argc == 4 && toupper(*(argv[3]+1)) == 'E') {
- _rax = (dosf_openh << 8) + 0; /* open a handle function */
- _rds = _showds();
- _rdx = &em_device_name; /* DS:DX => "EMMXXXX0" */
- _doint(dosi_dosf);
- j = _rax; /* j = returned handle */
- if (_carryf == 1) {
- printf("Error -- Expanded Memory Manager is not available.\n");
- printf(" Error code: %d\n",_rax);
- exit(dose_invfunc);
- } else {
- _rax = (dosf_ioctl << 8) + 7; /* Get output status */
- _rbx = j; /* BX = handle */
- _doint(dosi_dosf);
- _rbx = j; /* BX = handle */
- j = _rax & 0xff; /* j = returned device status */
- _rax = dosf_closeh << 8; /* close handle */
- _doint(dosi_dosf);
- if (j == 0xff) {
- em_requested = true; /* flag EM requested */
- _rax = emm_get_PFseg << 8; /* get EM page frame segment */
- _doint(usri_emm);
- _rax = _rax >> 8; /* status in AH */
- if (_rax == 0) em_PFseg = _rbx;
- else {
- printf("Error -- Expanded Memory Manager could not report page frame.\n");
- printf(" Error code: %2xH\n",_rax);
- exit(dose_noram);
- }
- } else {
- printf("Error -- Expanded Memory Manager is not available.\n");
- printf(" Error code: %2xH\n",j);
- exit(dose_invfunc);
- }
- }
- }
- #endif
-
- /*
- ---- Expand or shrink as indicated. If shrinking, first make
- sure there is sufficient room.
- */
-
- if (mdisk_chg < 0 ) {
- if (free_secs > -mdisk_chg) err_code = shrink();
- else {
- printf("Error -- NOT enough room to do the shrink.\n");
- printf(" You must first erase some files.\n");
- dsp_mem_blk_table();
- exit(dose_noerr);
- }
- } else if (mdisk_chg > 0) err_code = expand();
- else printf ("The disk is already that size! Nothing to do.\n");
-
- /* ---- Write the new FAT back to disk */
-
- if (err_code == dose_noerr)
- for (m = 0; m < boot_sec.bpb_fats; m++) {
- k = 0;
- for (j = first_fat_sector; j <= last_fat_sector; j++) {
- writesec(drive_number, j, fat + k);
- k = k + bytes_per_sec;
- }
- first_fat_sector = first_fat_sector + boot_sec.bpb_fat_size;
- last_fat_sector = last_fat_sector + boot_sec.bpb_fat_size;
- }
-
- /* ---- Write the updated boot sector back to memory disk ---- */
-
- if (err_code == dose_noerr)
- if ((result = writesec(drive_number, 0, &boot_sec)) != 0) {
- printf("Error -- could not write boot sector back. Code: %1d\n", result);
- printf("Reboot recommended.\n");
- err_code = dose_invdrv;
- }
-
- /*
- ---- Restore the memory disk's default directory, then reset default
- drive.
- */
-
- if (err_code == dose_noerr) {
- _rax = dosf_chdir << 8;
- _rds = _showds();
- _rdx = &mdisk_pathname;
- _doint(dosi_dosf);
-
- _rax = dosf_seldisk << 8;
- _rdx = default_drive;
- _doint(dosi_dosf);
- }
-
- /* ---- Free the C-allocated variables. ---- */
-
- free(fat);
-
- /* ---- Display Memory Block Table ----- */
-
- dsp_mem_blk_table();
-
- /*
- ---- If expanding and EM was not requested, terminate normally by
- using terminate and stay resident function.
- */
-
- if (err_code == dose_noerr && !em_requested && mdisk_chg > 0) {
- _rax = (dosf_keepprc << 8) + dose_noerr;
- _rdx = sec_per_blk * par_per_sec;
- _doint(dosi_dosf); /* PROGRAM TERMINATES HERE */
- }
-
- exit(err_code);
-
- } /* End of main routine */
-
- /* ==== EXPAND ROUTINE ==== */
- /* Expands the memory disk by allocating new memory blocks to it. */
-
- int expand()
- {
- int result, j;
- int mdisk_dif;
-
- /*
- ---- Size the already existing main memory block to 32K.
- We do this twice, once now, and once when we exit and
- stay resident. We do it now so as to detect any possible errors.
- The real allocation will be done at termination time.
- */
-
- mdisk_dif = mdisk_chg;
- if (!em_requested) {
- printf("Alocating new %dK memory block #%d\n",
- sec_per_blk/sec_per_K, boot_sec.bpb_media);
- _rax = dosf_setblk << 8;
- _res = pgm_seg;
- _rbx = sec_per_blk * par_per_sec;
- _doint(dosi_dosf);
- if (_carryf == 1) {
- printf("Error -- could not modify memory block size. Error code %1d\n",
- _rax);
- printf("Probably caused by not enough free memory.\n");
- return(dose_noram);
- }
- mdisk_dif = mdisk_dif - sec_per_blk;
-
- /*
- Increment the media byte to show an additional memory block has been
- allocated. Set the starting paragraph and size (in sectors) for the
- new block in the memory block table.
- */
-
- boot_sec.mem_blk_table[boot_sec.bpb_media].typ = nor_flg;
- boot_sec.mem_blk_table[boot_sec.bpb_media].par = pgm_seg;
- boot_sec.mem_blk_table[boot_sec.bpb_media].siz = sec_per_blk;
- boot_sec.mem_blk_table[boot_sec.bpb_media].hdl = 0;
-
- boot_sec.bpb_media = boot_sec.bpb_media + 1;
- fatput(boot_sec.bpb_media, 0, fat);
-
- /* Increase the total number of sectors. */
-
- boot_sec.bpb_total = boot_sec.bpb_total + sec_per_blk;
- }
-
- /* Now allocate new memory blocks for the remaining desired space. */
-
- for (;mdisk_dif > 0; mdisk_dif = mdisk_dif - sec_per_blk) {
- printf("Allocating new %dK memory block #%d\n",
- sec_per_blk/sec_per_K,boot_sec.bpb_media);
- #if em_support
- if (em_requested) {
- _rax = emm_get_handle << 8;
- _rbx = em_pag_per_blk;
- _doint(usri_emm);
- _rax = _rax >> 8;
- if (_rax == 0) {
- boot_sec.mem_blk_table[boot_sec.bpb_media].typ = em_flg;
- boot_sec.mem_blk_table[boot_sec.bpb_media].par = em_PFseg;
- boot_sec.mem_blk_table[boot_sec.bpb_media].siz = sec_per_blk;
- boot_sec.mem_blk_table[boot_sec.bpb_media].hdl = _rdx;
- boot_sec.bpb_total = boot_sec.bpb_total + sec_per_blk;
- boot_sec.bpb_media = boot_sec.bpb_media + 1;
- fatput(boot_sec.bpb_media, 0, fat);
- } else {
- printf("Error -- could not allocate new memory block from EMM.");
- printf(" Error code %2x\n",_rax);
- printf("Probably caused by not enough free memory.\n");
- break;
- }
- } else
- #endif
- {
- _rax = dosf_alloc << 8;
- _rbx = sec_per_blk * par_per_sec;
- _doint(dosi_dosf);
- if (_carryf == 1) {
- printf("Error -- could not allocate new memory block. Error code %1d\n",
- _rax);
- printf("Probably caused by not enough free memory.\n");
- break;
- } else {
- boot_sec.mem_blk_table[boot_sec.bpb_media].typ = nor_flg;
- boot_sec.mem_blk_table[boot_sec.bpb_media].par = _rax;
- boot_sec.mem_blk_table[boot_sec.bpb_media].siz = sec_per_blk;
- boot_sec.mem_blk_table[boot_sec.bpb_media].hdl = 0;
- boot_sec.bpb_total = boot_sec.bpb_total + sec_per_blk;
- boot_sec.bpb_media = boot_sec.bpb_media + 1;
- fatput(boot_sec.bpb_media, 0, fat);
- }
- }
- }
- return(dose_noerr);
-
- } /* end of expand routine */
-
- /*
- ==== SHRINK ROUTINE ====
- Shrinks the memory disk by moving all file sectors down
- to lowest possible locations, then deallocating memory
- blocks.
- */
-
- int shrink()
- {
-
- /* ==== Data Storage ==== */
-
- /* ---- Root Directory ---- */
-
- struct dir_entry root_dir[dir_per_sec];
-
- /* ---- Other locals ---- */
-
- int cur_dir; /* ptr to current directory */
- int dir_sector; /* current directory sector */
- int mdisk_dif; /* desired change in sectors */
- char tmpstr[20];
- int j, result;
-
- mdisk_dif = -mdisk_chg; /* make variable positive */
-
- result = dose_noerr;
-
- /* ---- Calculate the location of the directory sectors. */
-
- first_dir_sector = boot_sec.bpb_reserved +
- (boot_sec.bpb_fat_size * boot_sec.bpb_fats);
- last_dir_sector = (boot_sec.bpb_root * sizeof(struct dir_entry) /
- bytes_per_sec) + first_dir_sector - 1;
-
- /* ---- First data sector follows the last root directory sector. */
-
- first_data_sector = last_dir_sector + 1;
-
- /*
- ---- Locate the first available cluster in the FAT. First FAT entry
- is number 2, not 0, because the first two FAT entries are used
- for the media descriptor and filler.
- */
-
- for (free_cluster = 2; fatget(free_cluster, fat) != available;
- free_cluster++);
-
- /*
- ---- Loop through the root directory, packing the clusters of
- each file to the lowest possible locations.
- */
-
- for (dir_sector = first_dir_sector; dir_sector <= last_dir_sector;
- dir_sector++)
- {
- readsec(drive_number, dir_sector, &root_dir);
- for (cur_dir = 0; cur_dir < dir_per_sec; cur_dir++)
- if ((result = pack_file(&(root_dir[cur_dir]), 0, fat)) != dose_noerr)
- break;
- writesec(drive_number, dir_sector, &root_dir);
- if (result != dose_noerr) break;
- }
-
- /*
- ---- Free up memory. Loop backwards through the memory block table,
- freeing allocated memory blocks. As we do so, decrement the
- media byte (memory block counter) and total sectors.
- */
-
- j = boot_sec.bpb_media - 1;
- if (result == dose_noerr) while (mdisk_dif >= sec_per_blk) {
- if (mdisk_dif >= boot_sec.mem_blk_table[j].siz) {
- printf("Freeing memory block #%d\n",j);
- if (boot_sec.mem_blk_table[j].typ == nor_flg) {
- _res = boot_sec.mem_blk_table[j].par;
- _rax = dosf_dealloc << 8;
- _doint(dosi_dosf);
- if (_carryf == 1) {
- printf ("Error -- could not free allocated memory block #%d.",j);
- printf (" Error code %d\n",_rax);
- }
- }
- #if em_support
- else {
- _rax = emm_fre_handle << 8;
- _rdx = boot_sec.mem_blk_table[j].hdl;
- _doint(usri_emm);
- _rax = _rax >> 8;
- if (_rax != 0) {
- printf ("Error -- could not free EM pages for memory block #%d.",j);
- printf (" Error code %2x\n",_rax);
- }
- }
- #endif
- boot_sec.bpb_media = boot_sec.bpb_media - 1;
- fatput(boot_sec.bpb_media, 0, fat);
- boot_sec.bpb_total = boot_sec.bpb_total -
- boot_sec.mem_blk_table[j].siz;
- mdisk_dif = mdisk_dif - boot_sec.mem_blk_table[j].siz;
- }
- j = j - 1;
- }
-
- return(result);
-
- } /* end of shrink routine */
-
- /*
- ==== PACK_FILE ROUTINE ====
- Given the directory entry for a file, packs all the clusters
- for that file to the lowest possible locations. If the file
- is itself a subdirectory, then this routine will be called
- recursively via the "move_cluster" routine, i.e., "pack_file
- calls "move_cluster" who calls "pack_file" who calls
- "move_cluster" who calls "pack_file", etc.
-
- Clusters are packed down by moving any cluster above
- "free_cluster" down to "free_cluster". Then the next free
- cluster is located and the next cluster is examined.
- */
-
- int pack_file(dir, parent_cluster, fat)
- struct dir_entry *dir;
- int parent_cluster;
- unsigned char fat[];
- {
- int next_cluster;
- int cur_cluster;
- int new_cluster;
- int result;
-
- /* Is this directory entry erased or never used? If so, do nothing. */
-
- result = dose_noerr;
- if (dir->u_name.status != never_used &&
- dir->u_name.status != erased) {
-
- /*
- If file is not 0 length or it is a subdirectory file,
- we can pack it.
- */
-
- if (dir->size > 0 || isdir(dir)) {
-
- /*
- Handle the first cluster number, which is stored in the
- directory entry, not in the FAT.
- */
-
- next_cluster = dir->first_cluster;
- if (next_cluster > free_cluster) {
- new_cluster = free_cluster;
- fatput(fatget(next_cluster, fat), new_cluster, fat);
- dir->first_cluster = new_cluster;
- fatput(available, next_cluster, fat);
- for (; fatget(free_cluster, fat) != available; free_cluster++);
- result = move_cluster(dir, parent_cluster, fat,
- drive_number, next_cluster, new_cluster);
- }
-
- /* Handle rest of clusters stored in the FAT */
-
- if (result == dose_noerr) for (cur_cluster = dir->first_cluster;
- !islast(next_cluster = fatget(cur_cluster, fat));
- cur_cluster = fatget(cur_cluster, fat)) {
- if (next_cluster > free_cluster) {
- new_cluster = free_cluster;
- fatput(fatget(next_cluster, fat), new_cluster, fat);
- fatput(new_cluster, cur_cluster, fat);
- fatput(available, next_cluster, fat);
- for (; fatget(free_cluster, fat) != available; free_cluster++);
- result = move_cluster(dir, parent_cluster, fat,
- drive_number, next_cluster, new_cluster);
- if (result != dose_noerr) break;
- }
- }
- }
- }
- return(result);
- }
-
- /*
- ==== MOVE_CLUSTER ROUTINE ====
- Moves all sectors of secified cluster. If the file whose clusters
- are being moved is a subdirectory, then call "pack_file" routine
- recursively.
- */
-
- int move_cluster (dir, parent_cluster, fat, drive, from, to)
- struct dir_entry *dir;
- int parent_cluster;
- unsigned char fat[];
- int drive, from, to;
- {
- struct dir_entry a_sector[dir_per_sec];
- int cur_dir;
- int result;
- char *tryit;
- int j;
-
- result = dose_noerr;
- from = (from-2) * boot_sec.sec_per_cluster + first_data_sector;
- to = (to-2) * boot_sec.sec_per_cluster + first_data_sector;
- for (j = 0; j < boot_sec.sec_per_cluster; j++) {
- readsec(drive_number, from + j, &a_sector);
-
- /*
- If this sector belongs to a directory file, then we must
- recursively call the pack_file routine. The first two entries
- in any subdirectory, however, are special. They are named
- "." and ".." The first points to the disk location of the
- beginning of this subdirectory; the second to the disk location
- of the parent directory (0 if root directory)
- */
-
- if (isdir(dir))
- for (cur_dir = 0; cur_dir < dir_per_sec; cur_dir++) {
- if (a_sector[cur_dir].u_name.name[0] == '.') {
- if (a_sector[cur_dir].u_name.name[1] == '.')
- a_sector[cur_dir].first_cluster = parent_cluster;
- else a_sector[cur_dir].first_cluster = dir->first_cluster;
- }
- else {
- /* In DeSmet C, local variables are allocated on the stack. */
- /* Make sure there is sufficient stack space for the recursive */
- /* call. If not, display message, return error code, and */
- /* calling routines will attempt a graceful exit. Test if */
- /* stack has enough room by allocating space from it, then */
- /* freeing it. */
- if ((tryit = calloc(700, 1)) != 0) {
- free(tryit);
- pack_file(&(a_sector[cur_dir]), dir->first_cluster, fat);
- } else {
- printf("Error -- Insufficient stack space to pack ");
- printf("subdirectory %s\n", a_sector[cur_dir].u_name.name);
- printf("Too many subdirectories. Shrink abandoned. ");
- printf("Reboot recommended.\n");
- result = dose_noram;
- /* Note: Even though we can't handle the subdirectory, */
- /* keep going anyway so as to maintain integrity of disk. */
- }
- }
- }
-
- writesec(drive_number, to + j, &a_sector);
- }
- return(result);
- }
-
- /*
- ==== ISDIR ROUTINE ====
- Given a directory entry, returns true if the entry is for a
- subdirectory file.
- */
-
- int isdir(dir)
- struct dir_entry *dir;
- {
- if (dir->attr & dir_bit) return(true); else return(false);
- }
-
- /*
- ==== ISLAST ROUTINE ====
- Given a FAT entry, returns true if it is an EOF marker.
- */
-
- int islast(cluster)
- int cluster;
- {
- int j;
- int result;
-
- result = false;
- for (j = last_low; j <= last_high; j++)
- if (cluster == j) result = true;
- return(result);
- }
-
- /*
- ==== FATGET ROUTINE ====
- Given cluster number and FAT, returns the 12-bit FAT entry in
- and integer word, right-adjusted.
- */
-
- int fatget (cluster, fat)
- int cluster;
- unsigned char fat[];
- {
- int clloc, clword;
-
- clloc = 3*cluster/2;
- clword = fat[clloc] + (fat[clloc+1] << 8);
- if (cluster & 1) return (clword >> 4); else return (clword & 0x0fff);
- }
-
- /*
- ==== FATPUT ROUTINE ====
- Given a 12-bit FAT entry, cluster number, and the FAT, stores
- the entry into the FAT.
- */
-
- int fatput (wd12bits, cluster, fat)
- int cluster;
- int wd12bits;
- unsigned char fat[];
- {
- int clloc, clword;
-
- clloc = 3*cluster/2;
- clword = fat[clloc] + (fat[clloc+1] << 8);
- if (cluster & 1)
- clword = (clword & 0x000f) | (wd12bits << 4);
- else
- clword = (clword & 0xf000) | wd12bits;
- fat[clloc] = clword & 0x00ff;
- fat[clloc+1] = clword >> 8;
- }
-
- /*
- ==== DSP_MEM_BLK_TABLE ROUTINE ====
- Displays the Memory Block Table on the screen.
- */
-
- dsp_mem_blk_table()
- {
- int j;
-
- #if em_support
- printf("\n");
- printf(" Memory Block Table\n");
- printf("Block # Paragraph Size(sectors) EM Handle\n");
- printf("------- --------- ------------- ---------\n");
- for (j = 0; j < boot_sec.bpb_media; ++j) {
- printf(" %1d %4x %3d ",
- j,boot_sec.mem_blk_table[j].par,boot_sec.mem_blk_table[j].siz);
- if (boot_sec.mem_blk_table[j].typ == em_flg)
- printf(" %4x",boot_sec.mem_blk_table[j].hdl);
- else printf(" --");
- printf("\n");
- }
- #else
- printf("\n");
- printf(" Memory Block Table\n");
- printf("Block # Paragraph Size(sectors)\n");
- printf("------- --------- -------------\n");
- for (j = 0; j < boot_sec.bpb_media; ++j) {
- printf(" %1d %4x %3d\n",
- j,boot_sec.mem_blk_table[j].par,boot_sec.mem_blk_table[j].siz);
- }
- #endif
-
- }
-
- /*
- ==== PEEKW ROUTINE ====
- Given segment and offset, returns the word thereby addressed.
- Written because DeSmet C uses small memory model and there are
- no FAR data types.
- */
-
- int peekw(off, seg)
- unsigned char *off;
- int seg;
- {
- return((_peek(off+1, seg) << 8) + _peek(off, seg));
- }
-
- /*
- ==== READSEC ====
- Given drive number, desired logical sector number, and a sector
- buffer, this routine reads the sector into the buffer.
-
- NOTE: This routine uses DeSmet's "_doint" routine to perform absolute
- disk read interrupt number 25H. This interrupt, unlike most
- interrupts, leaves the flags register on the stack when it returns.
- In DeSmet this is OK, because the called routine restores the
- stack frame prior to RETurning. In some C compilers, this scheme
- won't work. For example, in AZTEC C, it is the CALLING routine's
- responsibility to restore the stack frame. In AZTEC, then, we
- would RETurn to the wrong address and die. So look out, if you are
- converting this program to some other version of C.
- */
-
- readsec (drive, sector, buffer)
- int drive;
- int sector;
- char *buffer;
- {
- _rax = drive;
- _rds = _showds(); /* ASSUMPTION: DS = SS in DeSmet C */
- _rbx = buffer;
- _rcx = 1;
- _rdx = sector;
- _doint(dosi_dsk_read);
- if (_carryf == 1) return (_rax); else return (0);
- }
-
- /*
- ==== WRITESEC ROUTINE ====
- Given drive number, logical sector number, and a buffer, this
- routine writes the sector to disk.
-
- See the note under routine READSEC.
- */
-
- writesec (drive, sector, buffer)
- int drive;
- int sector;
- char *buffer;
- {
- _rax = drive;
- _rds = _showds(); /* ASSUMPTION: DS = SS in DeSmet C */
- _rbx = buffer;
- _rcx = 1;
- _rdx = sector;
- _doint(dosi_dsk_write);
- if (_carryf == 1) return (_rax); else return (0);
- }
-
- /*
- ==== DSP_USAGE ROUTINE ====
- Displays message how to use program.
- */
-
- int dsp_usage()
-
- {
- #if em_support
- printf("Usage:\n ADJRAM drive size option\nWhere:\n");
- #else
- printf("Usage:\n ADJRAM drive size\nWhere:\n");
- #endif
- printf(" drive = memory disk drive letter, A to I\n");
- printf(" size = size of memory disk in K, %d to %d, in following format:\n",
- min_size,max_size);
- printf(" xxx = set memory disk size to xxx\n");
- printf(" +xxx = increase memory disk size by xxx\n");
- printf(" -xxx = decrease memory disk size by xxx\n");
- printf(" Fxxx = adjust size so there is xxx free space\n");
- printf(" Mxxx = ensure there is at least xxx of free space\n");
- printf(" Size will be rounded to the next highest %dK\n",
- sec_per_blk/sec_per_K);
- printf(" If size is omitted, current drive size is displayed.\n");
- #if em_support
- printf(" option= optional /E if INTEL/LOTUS/Microsoft Expanded Memory\n");
- printf(" is to be used for any expansion\n");
- #endif
- printf("Examples:\n");
- printf(" ADJRAM C: 250\n");
- printf(" will set memory disk C to 256K\n");
- #if em_support
- printf(" ADJRAM i: +60 /E\n");
- printf(" will increase memory disk I by 64K, using expanded memory\n");
- #else
- printf(" ADJRAM i: +60\n");
- printf(" will increase memory disk I by 64K\n");
- #endif
- printf(" ADJRAM C: m64\n");
- printf(" will ensure there is at least 64K free space on drive C\n");
- }
-