home *** CD-ROM | disk | FTP | other *** search
- /* Adjustable Ram Disk
-
- (c) Copyright 1986,1987 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.
- v3.1 2 Oct 86 Fix shrink bug. Not packing subdirectories properly
- v3.2 18 Oct 86 Allow SIZE= clause for AMDISK. Also allow drive letters
- A through L.
- v4.0 3 Jan 87 Add reserved conventional memory support as
- R:xxxx:nn option.
- Full support for expanded memory mixed with conventional
- memory.
- Max size of memory disk based upon available memory and
- cluster size.
- User requested expansion or shrinkage automatically
- adjusted to within limits and rounded to nearest
- memory block boundary.
- In expanded memory, use larger block size (64K) to avoid
- excessive usage of EMM handles.
- Display Memory Block Table only if /t option specified.
- Bug. Stop processing directory when first "never_used"
- flag is encountered.
- Bug in DeSmet free() routine. Causes memory overflo.
- Calculate stack space manually instead.
- Restrict program size to under 32K.
- Clean up error reporting. Tell user if error has
- corrupted the memory disk.
- v4.1 15 May 88 Restrict reserved memory to above segment a000.
- Initialize reserved memory when block is allocated.
-
- For program usage, see the last routine.
-
- A few definitions:
- 1. CONVENTIONAL MEMORY is that memory directly addressable
- by the 8088 or 8086 CPU and controlled by DOS. On the
- IBM PC, it falls below 640K.
- 2. RESERVED MEMORY is also directly addressable by the
- 8088 or 8086, but it is not controlled by DOS. On
- the IBM PC, it falls above 640K and below 1MB. It
- is usually reserved for use by the PC's BIOS. If your
- machine has memory mapped to addresses between 640K and
- 1MB and that memory is not needed for any other purpose,
- and it is directly addressable by the CPU (no special
- "paging" or "mapping" required to access it), then
- ADJRAM can use it via the R option. See .DOC
- 3. EXTENDED MEMORY is addressed above 1MB. It is only
- available on AT type machines (80286 or 80386 CPUs).
- It is not currently supported by ADJRAM.
- 4. EXPANDED MEMORY is memory conforming to the Lotus/
- Intel/Microsoft Expanded Memory Specification. It
- is supported by ADJRAM if you have the EMM loaded.
-
- 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).
-
- _showsp()
- Synopsis: char *_showsp()
-
- Returns the current value of SP.
-
- _setsp()
- Synopsis: void _setsp(newStackValue);
- unsigned newStackValue;
-
- Sets the SP register to the specified value.
-
- _memory()
- Synopsis: char *_memory()
-
- Returns a pointer to the first byte of free memory past
- the end of initialized memory (global data).
-
- _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.
-
- */
-
- /* ==== Definitions ==== */
-
- /* ---- Overall Definitions ---- */
-
- #define true 1
- #define false 0
-
- /*
- ---- To compile without LOTUS/INTEL/Microsoft Expanded Memory
- support, change the "1" to "0" in the next statement. Will
- save about 1500 bytes in EXE file.
- */
-
- #define em_support 1 /* compile for EM support */
-
- /* ---- To compile without reserved memory support, change
- the "1" to "0" in the next statement.
- */
-
- #define rm_support 1 /* compile for reserved memory */
-
- #define debug 0 /* compile with debug stmts */
-
- /* ---- Other customizable symbols */
-
- #define start_rm_addr 0xa000 /* start of reserved memory */
-
- /*
- 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 def_size_K 64 /* default to 64K RAM disk */
- #define min_size_K (boot_sec.mem_blk_table[0].siz/sec_per_K)
- #define min_size_sec boot_sec.mem_blk_table[0].siz
- #define em_sec_per_blk 512 /* increment in 256K Expanded */
- /* Memory blocks */
- #define cnv_sec_per_blk 64 /* increment in 32K conventional*/
- /* memory 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,
- it 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 K_per_blk (sec_per_blk/sec_per_K)
- /* K per memory block */
- #define em_pag_per_blk (K_per_blk/16)
- /* 16K EM pages per mem block */
- #define max_clusters 4086 /* max clusters per disk
- (12-bit FAT entries) */
- #define max_mem_blks (max_clusters/cnv_sec_per_blk)
- /* Maximum number of memory blocks */
- /* assuming cluster size of 1 */
- #define bytes_per_fat (max_clusters*3/2)
- #define sec_per_fat ((bytes_per_fat+bytes_per_sec-1)/bytes_per_sec)
- #define fat_size (sec_per_fat*bytes_per_sec)
-
- /* ---- 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 expanded memory */
- #define rm_flg 2 /* memory block is in reserved 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_too_many_dir 4 /* too many directories */
- #define dose_arena 7 /* arena trashed */
- #define dose_noram 8 /* not enough memory */
- #define dose_inv_env 10 /* invalid environment */
- #define dose_invdrv 15 /* invalid drive */
-
- /* ---- Directory definitions ---- */
-
- #define never_used 0 /* directory entry never used */
- #define erased 0xe5 /* file has been erased */
-
- /* ---- Directory Attribute Byte ---- */
-
- #define RO_bit 0x01 /* this bit indicates read-only */
- #define hidn_bit 0x02 /* this bit indicates hidden file */
- #define sys_bit 0x04 /* this bit indicates system file */
- #define vol_bit 0x08 /* this bit indicates volume label */
- #define dir_bit 0x10 /* this bit indicates subdirectory */
- #define arc_bit 0x20 /* this bit indicates modified file */
-
- /* ---- 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_K; /* memory disk size in K */
- int user_chg; /* user's desired change in sectors */
- int mdisk_chg; /* the difference between disk's current size
- and the final 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 */
- int avail_mem_blks; /* max expansion size in memory blocks */
- int sec_per_blk; /* sectors per memory block */
- int gbl_argc; /* command line argument count */
- char *gbl_argv; /* command line argument vector table */
- unsigned char expansion_type; /* 0 = expand using conventional memory */
- /* 1 = expand using expanded memory */
- /* 2 = expand using reserved memory */
- unsigned int user_rm_addr; /* user-specified reserved memory */
- /* starting paragraph address */
-
- /* ---- 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_mem_blks];
- 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 */
- char em_device_name[] = "EMMXXXX0"; /* EMM device name */
-
- /* ---- Declare types of library functions which return non-integer values */
-
- char *strncmp(); /* compares 2 strings of specified length */
- unsigned _showcs(); /* returns current CS register */
- unsigned _showds(); /* returns current DS = SS register */
- char *_showsp(); /* returns current SP register */
- void _setsp(); /* sets SP to specified value */
- char *_memory(); /* returns pointer to end of initialized memory */
- char _peek(); /* returns a byte given segment and offset */
-
- /* ==== MAIN ROUTINE ==== */
-
- main(argc, argv)
- int argc;
- char *argv[];
- {
- /*
- ---- 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;
-
- gbl_argc = argc;
- gbl_argv = argv;
-
- /* ---- Now move the stack down below 32K, so that we don't clobber
- DOS memory arena blocks we will be creating if expanding.
- New stack pointer is computed so that sum of code, global
- variables, and stack is less than 32K. DeSmet run-time memory
- looks like this:
-
- pgm_seg --> program segment prefix (256 bytes)
- CS --> code
- DS,SS --> initialized data
- uninitialized data
- _memory() --> (high water)
- stack
- SP -->
- */
-
- if(_showsp() <
- (((pgm_seg + (cnv_sec_per_blk*par_per_sec) - _showds()) * 16) - 0x80)) {
- printf("Error -- ADJRAM requires 32K of free memory to run\n");
- adjram_exit(dose_noram);
- } else
- _setsp(((pgm_seg + (cnv_sec_per_blk*par_per_sec) - _showds()) * 16) - 0x80);
-
- #if debug
- printf("CS = %4x next block = %4x\n",pgm_seg,
- pgm_seg + (cnv_sec_per_blk*par_per_sec));
- printf("DS = %4x end of dat = %4x\n",_showds(),
- _showds() + ((_memory()+15)/16));
- printf("mem= %4x\n",_memory());
- printf("SP = %4x top of stk = %4x\n",_showsp(),
- _showds() + (_showsp()/16)) + 0x8;
- #endif
-
- /* ---- Now call the real main routine. Never comes back from call. */
-
- actual_main(gbl_argc, gbl_argv);
- }
-
- /* ==== ACTUAL_MAIN ROUTINE ==== */
-
- int actual_main(argc, argv)
- int argc;
- char *argv[];
-
- {
- int err_code; /* exit error code ( 0 if no error ) */
- int non_fatal_err; /* user errors not requiring reboot */
- int j;
- int k;
- int m;
-
- /* ---- File Allocation Table ----*/
-
- unsigned char fat[fat_size];
-
- printf("Adjustable RAM Disk v4.1 ");
- printf(" (c) Copyright 1986, 1987, 1988 by Gary Cramblitt\n");
- #if em_support
- printf("(-- Expanded Memory Version)\n");
- #endif
-
- printf("\n");
- err_code = dose_noerr; /* set no error */
- non_fatal_err = dose_noerr;
-
- /* ---- 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");
- adjram_exit(dose_invfunc);
- }
-
- /* ---- If user wants to expand into LIM Expanded Memory or reserved
- memory, set the memory block size appropriately. If user is
- expanding into reserved memory, get the paragraph addresses
- and verify.
- */
-
- expansion_type = nor_flg;
- sec_per_blk = cnv_sec_per_blk;
- #if em_support
- for (j = 1; j < argc; j++) if (toupper(*(argv[j]+1)) == 'E')
- expansion_type = em_flg;
- if (expansion_type == em_flg) sec_per_blk = em_sec_per_blk;
- #endif
- #if rm_support
- for (j = 1; j < argc; j++) if (toupper(*argv[j]) == 'R') {
- expansion_type = rm_flg;
- user_rm_addr = htoi(argv[j]+2);
- j = atoi(argv[j]+7);
- if (j > 64 || j < 1 || user_rm_addr < start_rm_addr) {
- printf("Error -- Bad reserved memory parameter.\n");
- printf(" Must be in form R:hhhh:dd. Check documentation.\n");
- adjram_exit(dose_invfunc);
- }
- sec_per_blk = j * sec_per_K;
-
- /* --- Check that specified reserved memory is really there. --- */
-
- _poke(0xed, 0, user_rm_addr);
- _poke(0xed, (sec_per_blk*bytes_per_sec)-1, user_rm_addr);
- if ( (_peek(0, user_rm_addr) != 0xed)
- || (_peek((sec_per_blk*bytes_per_sec) - 1, user_rm_addr) != 0xed)) {
- printf("Error -- could not locate reserved memory block ");
- printf("from %4x:0000 to %4x:%4x\n",
- user_rm_addr, user_rm_addr, (sec_per_blk*bytes_per_sec)-1);
- printf(" Probably caused by no such memory.\n");
- adjram_exit(dose_arena);
- }
- }
- #endif
-
- /*
- ---- If using 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.
- */
-
- #if em_support
- if (expansion_type == em_flg) {
- _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);
- adjram_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) {
- _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);
- adjram_exit(dose_noram);
- }
- } else {
- printf("Error -- Expanded Memory Manager is not available.\n");
- printf(" Error code: %2xH\n",j);
- adjram_exit(dose_invfunc);
- }
- }
- }
- #endif
-
- /*
- ---- 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);
- adjram_exit(dose_inv_env);
- }
-
- /*
- ---- Set default minimum size of RAM disk. Will be overwritten as
- soon as boot sector is read in. Set here so that help message
- will have something to display.
- */
-
- min_size_sec = def_size_K*sec_per_K;
-
- /*
- ---- 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 > 11) {
- dsp_usage();
- exit(dose_invfunc);
- }
-
- /*
- ---- Read the boot sector from the memory disk. Verify that we are
- dealing with the correct memory disk.
- */
-
- if ((err_code = readsec(drive_number, 0, &boot_sec)) != dose_noerr) {
- printf("Error -- could not read boot sector. Error code %1d\n", err_code);
- adjram_exit(dose_invdrv);
- }
- if (strcmp(boot_sec.ident,"AMDISK4 ") != 0) {
- printf("Error -- that drive is not the adjustable RAM disk or invalid\n");
- printf(" version of AMDISK for this version of ADJRAM!\n");
- adjram_exit(dose_invdrv);
- }
-
- #if debug
- if (fat_size != boot_sec.bpb_fat_size*bytes_per_sec)
- printf("Coding Error -- FAT_SIZE does not match BPB_FAT_SIZE\n");
- #endif
-
- /* ---- Determine the drive's current size and free space. */
-
- mdisk_size_K = 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 RAM disk is not loaded.\n");
- adjram_exit(dose_invdrv);
- }
- free_secs = _rbx * _rax; /* avail clusters * sectors per cluster */
- printf("Drive %c: Starting Size: %dK Free Space: %dK\n",
- drive_number + 65, mdisk_size_K, 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);
-
- /*
- ---- Read in the FAT.
- */
-
- 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.
- */
-
- user_chg = 0;
- if (argc >= 3) {
- if (expansion_type == rm_flg) user_chg = sec_per_blk/sec_per_K;
- else if (toupper(*argv[2]) == 'F')
- user_chg = atoi(argv[2]+1) - free_secs/sec_per_K;
- else if (toupper(*argv[2]) == 'M') {
- user_chg = atoi(argv[2]+1) - free_secs/sec_per_K;
- if (user_chg < 0) user_chg = 0;
- } else if (*argv[2] != '/') {
- user_chg = atoi(argv[2]);
- if (*argv[2] == '+' || *argv[2] == '-'); else
- user_chg = user_chg - (boot_sec.bpb_total/sec_per_K);
- }
- }
- user_chg = user_chg * sec_per_K;
-
- /*
- ---- Display minimum shrinkage size (if shrink is possible at all.
- */
-
- if (user_chg <= 0) {
- if (boot_sec.bpb_media > 1)
- printf(" Next Smaller Size: %dK Min Shrinkage: %dK\n",
- (boot_sec.bpb_total -
- boot_sec.mem_blk_table[boot_sec.bpb_media-1].siz)/sec_per_K,
- boot_sec.mem_blk_table[boot_sec.bpb_media-1].siz/sec_per_K);
- else
- printf("RAM disk is as small as is possible.\n");
- }
-
- /*
- ---- Size our program to 32K if user is expanding the memory
- disk. This 32K program segment will become the first new
- memory block added to the memory disk's Memory Block Table.
- */
-
- if (user_chg >=0) {
- if (expansion_type == nor_flg) {
- _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");
- adjram_exit(dose_noram);
- }
- }
- }
-
- /*
- ---- Determine maximum expansion in terms of memory blocks.
- For expanded memory, ask EMM how many pages are available.
- Size available conventional memory in units of 32K memory
- blocks. Always leave at least 32K of memory so that ADJRAM
- has room to be run again.
- For reserved memory, user specifies exactly one block and he
- tells how big that block is.
- In any case, maximum expansion is limited to available
- clusters.
- */
-
- if (user_chg >= 0) {
- #if em_support
- if (expansion_type == em_flg) {
- _rax = emm_get_pages << 8; /* get number of EM pages */
- _doint(usri_emm);
- avail_mem_blks = _rbx/em_pag_per_blk;
- }
- #endif
- if (expansion_type == nor_flg) {
- _carryf == 0;
- for (avail_mem_blks = 0; _carryf == 0; avail_mem_blks++) {
- _rax = dosf_alloc << 8;
- _rbx = sec_per_blk * par_per_sec;
- _doint(dosi_dosf);
- boot_sec.mem_blk_table[boot_sec.bpb_media + avail_mem_blks].par = _rax;
- }
- avail_mem_blks = avail_mem_blks - 1;
- for (j = avail_mem_blks; j > 0; j--) {
- _rax = dosf_dealloc << 8;
- _res = boot_sec.mem_blk_table[boot_sec.bpb_media + j - 1].par;
- _doint(dosi_dosf);
- }
- }
- #if rm_support
- if (expansion_type == rm_flg) avail_mem_blks = 1;
- #endif
- j = ((max_clusters * boot_sec.sec_per_cluster) -
- boot_sec.bpb_total)/ sec_per_blk;
- if (j < avail_mem_blks) avail_mem_blks = j;
- printf(" Max Possible Size: %dK Max Expansion: %dK\n",
- (avail_mem_blks*K_per_blk) + (boot_sec.bpb_total/sec_per_K),
- avail_mem_blks*K_per_blk);
- }
-
- /*
- ---- Round user's request to the nearest memory block boundary.
- If expanding, round up, but do not exceed available memory.
- If shrinking, round up (less negative), and do not exceed
- free sectors.
- */
-
- mdisk_chg = user_chg;
- if (mdisk_chg > 0) {
- mdisk_chg = ((mdisk_chg + sec_per_blk - 1)/sec_per_blk) * sec_per_blk;
- if (mdisk_chg/sec_per_blk > avail_mem_blks) {
- mdisk_chg = avail_mem_blks * sec_per_blk;
- non_fatal_err = dose_noram;
- }
- } else if (mdisk_chg < 0) {
- if (-mdisk_chg > free_secs) {
- printf("Warning -- Insufficient free space in disk to shrink that much.\n");
- printf(" You must erase some files.\n");
- mdisk_chg = -free_secs;
- non_fatal_err = dose_noram;
- }
- for (j = boot_sec.bpb_media-1;
- -mdisk_chg >= boot_sec.mem_blk_table[j].siz && j > 0; j--) {
- mdisk_chg = mdisk_chg + boot_sec.mem_blk_table[j].siz;
- }
- mdisk_chg = 0;
- for (j++; j < boot_sec.bpb_media; j++)
- mdisk_chg = mdisk_chg - boot_sec.mem_blk_table[j].siz;
- }
- if (user_chg != mdisk_chg)
- printf("Warning -- Rounding your requested change of %dK to %dK.\n",
- user_chg/sec_per_K,mdisk_chg/sec_per_K);
-
- mdisk_size_K = (mdisk_chg + boot_sec.bpb_total)/sec_per_K;
- printf(" Final Size: %dK Amount Change: %dK\n",
- mdisk_size_K, mdisk_chg/sec_per_K);
-
- /*
- ---- From here on, any error that occurs would probably require the
- user to reboot.
- */
-
- /*
- ---- Expand or shrink as indicated.
- */
-
- if (mdisk_chg < 0 ) err_code = shrink(fat);
- else if (mdisk_chg > 0) err_code = expand();
-
- /* ---- Write the new FAT back to disk */
-
- 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 = writesec(drive_number, 0, &boot_sec)) != 0) {
- printf("Error -- could not write boot sector back. Code: %1d\n", err_code);
- err_code = dose_invdrv;
- }
-
- /*
- ---- Restore the memory disk's default directory, then reset default
- drive.
- */
-
- _rax = dosf_chdir << 8;
- _rds = _showds();
- _rdx = &mdisk_pathname;
- _doint(dosi_dosf);
-
- _rax = dosf_seldisk << 8;
- _rdx = default_drive;
- _doint(dosi_dosf);
-
- /* ---- Display Memory Block Table if user requested it. ----- */
-
- for (j = 1; j < argc; j++) if (toupper(*(argv[j]+1)) == 'T')
- dsp_mem_blk_table();
-
- /*
- ---- Tell user results.
- */
-
- if (err_code != dose_noerr) {
- printf("*** Sorry, RAM disk left corrupted. Recommend you check\n");
- printf(" your files, save them if possible, and reboot.\n");
- } else err_code = non_fatal_err;
-
- /*
- ---- If expanding using conventional memory, terminate normally by
- using terminate and stay resident function.
- */
-
- if (expansion_type == nor_flg && mdisk_chg > 0) {
- printf("ADJRAM exiting (code %d)\n",err_code);
- _rax = (dosf_keepprc << 8) + dose_noerr;
- _rdx = sec_per_blk * par_per_sec;
- _doint(dosi_dosf); /* PROGRAM TERMINATES HERE */
- }
-
- adjram_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;
-
- /*
-
- */
-
- mdisk_dif = mdisk_chg;
- result = dose_noerr;
-
- /*
- The first new memory block is ADJRAM's own program segment, which
- has already been resized to 32K.
- 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.
- */
-
- if (expansion_type == nor_flg) {
- mdisk_dif = mdisk_dif - sec_per_blk;
- 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;
-
- /* 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) {
- #if em_support
- if (expansion_type == em_flg) {
- _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;
- } 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");
- result = dose_arena;
- break;
- }
- }
- #endif
- if (expansion_type == nor_flg) {
- _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");
- result = dose_arena;
- 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;
- }
- }
- #if rm_support
- /* --- Reserved memory must be initialized by zeroing it. --- */
- if (expansion_type == rm_flg) {
- for (j=0; j < sec_per_blk*bytes_per_sec; j++)
- _poke(0x00, j, user_rm_addr);
- boot_sec.mem_blk_table[boot_sec.bpb_media].typ = rm_flg;
- boot_sec.mem_blk_table[boot_sec.bpb_media].par = user_rm_addr;
- 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;
- }
- #endif
- }
- return(result);
-
- } /* 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(fat)
- unsigned char fat[];
- {
-
- /* ==== 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 */
- int done_dir; /* true when root directory completed */
- 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 FAT ID 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.
- */
-
- done_dir = false;
- for (dir_sector = first_dir_sector;
- !done_dir && 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 (root_dir[cur_dir].u_name.status == never_used) {
- done_dir = true;
- break;
- } else
- 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 >= boot_sec.mem_blk_table[j].siz) {
- if (boot_sec.mem_blk_table[j].typ == em_flg) {
- _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);
- result = dose_arena;
- }
- } else 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);
- result = dose_arena;
- }
- }
- boot_sec.bpb_media = boot_sec.bpb_media - 1;
- 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 from itself.
-
- 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[];
- {
- struct dir_entry a_sector[dir_per_sec];
- int next_cluster;
- int cur_cluster;
- int new_cluster;
- int result;
- int cur_dir;
- int result;
- int cluster_start;
- int done_dir;
- int j;
-
- /* Is this directory entry erased or never used? If so, do nothing. */
-
- result = dose_noerr;
-
- #if debug
- printf("Considering file %s for packing.\n",dir->u_name.name);
- #endif
-
- 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)) {
-
- #if debug
- printf(" Packing file %s\n",dir->u_name.name);
- #endif
-
- /*
- 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(drive_number, next_cluster, new_cluster,
- &a_sector);
- }
-
- /* 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(drive_number, next_cluster, new_cluster,
- &a_sector);
- if (result != dose_noerr) break;
- }
- }
- }
-
- /*
- If the directory entry is for a subdirectory, then process
- it, packing each of its files. Process a cluster at a time...
- */
-
- done_dir = false;
- if (isdir(dir)) for (cur_cluster = dir->first_cluster;
- !done_dir && !islast(cur_cluster);
- cur_cluster = fatget(cur_cluster, fat)) {
- if (result != dose_noerr) break;
- cluster_start = (cur_cluster-2) * boot_sec.sec_per_cluster +
- first_data_sector;
-
- /* For each sector in the cluster... */
-
- for (j = 0; !done_dir && j < boot_sec.sec_per_cluster; j++) {
- result = readsec(drive_number, cluster_start + j, &a_sector);
- if (result != dose_noerr) break;
-
- /*
- For each directory entry in the sector, pack it. The first
- two entries are special files ".." and "."
- */
-
- 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 if (a_sector[cur_dir].u_name.status == never_used) {
- done_dir = true;
- break;
- } 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 */
- if ((_showsp() - _memory()) > 700)
- result = 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_too_many_dir;
- /* Note: Even though we can't handle the subdirectory, */
- /* keep going anyway so as to maintain integrity of disk. */
- }
- }
- }
- if (result != dose_noerr) break;
- writesec(drive_number, cluster_start + j, &a_sector);
- }
- }
- }
- if (result != dose_noerr)
- printf("Error -- Error while packing file %s\n",
- dir->u_name.name);
-
- #if debug
- printf("Done packing file %s\n",dir->u_name.name);
- #endif
-
- return(result);
- }
-
- /*
- ==== MOVE_CLUSTER ROUTINE ====
- Moves all sectors of specified cluster.
- */
-
- int move_cluster (drive, from, to, buffer)
- int drive, from, to;
- unsigned char *buffer;
- {
- int result;
- int tmp_result;
- int j;
-
- 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++) {
- tmp_result = readsec(drive, from + j, buffer);
- result = writesec(drive, to + j, buffer);
- }
- return(result + tmp_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;
-
- printf("\n");
- #if em_support
- printf(" Memory Block Table\n");
- printf("Block # Paragraph Size(K) 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/sec_per_K);
- 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(" Memory Block Table\n");
- printf("Block # Paragraph Size(K)\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/sec_per_K);
- }
- #endif
- printf("\n");
-
- }
-
- #if rm_support
- /*
- ==== HTOI ROUTINE ====
- Convert hexadecimal string to integer.
- */
-
- int htoi(str)
- char str[];
- {
- int temp;
- int j;
- int nibble;
-
- temp = 0;
- for (j=0; ishex(str[j]); j++) {
- nibble = toupper(str[j]) - '0';
- if (nibble > 9) nibble = nibble - ('A'-'9'-1);
- if (nibble < 0 || nibble > 15) break;
- temp = (temp << 4) + nibble;
- }
- return(temp);
- }
-
- /*
- ==== ISHEX ROUTINE ====
- Returns true if character is hexadecimal (upper or lower case).
- */
-
- int ishex(ch)
- char ch;
- {
- if (isdigit(ch) || (toupper(ch) >='A' && toupper(ch) <= 'F'))
- return(true);
- else return(false);
- }
- #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.
- */
-
- int 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 (dose_noerr);
- }
-
- /*
- ==== WRITESEC ROUTINE ====
- Given drive number, logical sector number, and a buffer, this
- routine writes the sector to disk.
-
- See the note under routine READSEC.
- */
-
- int 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 (dose_noerr);
- }
- /*
- ==== ADJRAM_EXIT ROUTINE ====
- Displays exit code and exits with that code to DOS.
- */
- int adjram_exit(err_code)
- int err_code;
- {
- printf("ADJRAM exiting (code %d)\n",err_code);
- exit(err_code);
- }
-
- /*
- ==== DSP_USAGE ROUTINE ====
- Displays message how to use program.
- */
-
- int dsp_usage()
-
- {
- printf("WARNING: This program is distributed with documentation and ");
- printf("source code.\n");
- printf(" Using it without first reading the documentation ");
- printf("is hazardous.\n");
- printf("Usage: ADJRAM drive size option\nWhere:\n");
- printf(" drive = RAM disk drive letter, A to L\n");
- printf(" size = size of RAM disk in K (minimum %d) in following format:\n",
- min_size_K);
- printf(" xxx = set RAM disk size to xxx\n");
- printf(" +xxx = increase RAM disk size by xxx\n");
- printf(" -xxx = decrease RAM 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",
- K_per_blk);
- printf(" If size is omitted, current drive size is displayed.\n");
- printf(" option= optional /T to display Memory Block Table\n");
- #if em_support
- printf(" optional /E to expand using LIM Expanded Memory\n");
- #endif
- printf("Examples:\n");
- printf(" ADJRAM C: 250\n");
- printf(" will set RAM disk C to 256K\n");
- #if em_support
- printf(" ADJRAM i: +250 /e /t\n");
- printf(" will increase RAM disk I by 256K using Expanded Memory\n");
- #else
- printf(" ADJRAM i: +60 /t\n");
- printf(" will increase RAM disk I by 64K\n");
- #endif
- printf(" and will display the Memory Block Table\n");
- printf(" ADJRAM C: m64\n");
- printf(" will ensure there is at least 64K free space on drive C\n");
- }
-