$include (..\lib\compStch.ext) /* *============================================================================ * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE * * Permission to use for any purpose, modify, copy, and make enhancements * and derivative works of the software is granted if attribution is given to * R.M. Gillmore, dba the ACME Software Deli, as the author * * While the ACME Software Deli does not work for money, there is nonetheless * a significant amount of work involved. The ACME Software Deli maintains the * rights to all code written, though it may be used and distributed as long as * the following conditions are maintained. * * 1. The copyright statement at the top of each code block is maintained in * your distribution. * 2. You do not identify yourself as the ACME Software Deli * 3. Any changes made to the software are sent to the ACME Software Deli *============================================================================ */ menuCommands: do; $include (..\lib\comnDefs.ext) $if not noID declare IDString (*) byte data ( '@(#)menuCmds.p86 $Author: rmgillmore $ $Date:: 2025-05-04 19:35:39#$:', 0 ); $endif $set (menuCommandsSource) $include (..\lib\menuCmds.ext) $include (..\lib\fileIO.ext) $include (..\lib\changExt.ext) $include (..\lib\iniMgr.ext) $include (..\lib\string.ext) $include (..\lib\errCode.ext) $include (..\lib\loadExec.ext) $include (..\lib\dirFunct.ext) $include (..\lib\exit.ext) $include (..\lib\mem.ext) $include (..\lib\videoIO.ext) $include (..\lib\shrt2lng.ext) $include (..\lib\debugHlp.ext) $if LOGGING $include (..\lib\logger.ext) $endif declare menuSelectionObjectType literally 'structure ( selectionName ( SELECTION_NAME_LENGTH ) char )'; declare selectionType literally 'structure ( nameString ( SELECTION_NAME_LENGTH ) char )'; declare menuSelectionType literally 'structure ( selection ( NUMBER_MENU_SELECTIONS ) selectionType )'; declare pageArray ( NUMBER_PAGES ) menuSelectionType; declare iniHandle iniHandle_t, iniFileName (MAX_PATH) char, menuDataName (MAX_PATH) char, menuHelpFileName (MAX_PATH) char, scriptDirectoryName (MAX_PATH) char; /* derived using the path to the executable, * the 'scripts' string, and a trailing * path delimiter character */ declare baseScriptName (*) char data ( '00acmenu.bat', 0 ); /* * --------------------------------------------------- * Helper Functions * --------------------------------------------------- */ deriveScriptName: procedure ( pageNumber, selectionLetter, scriptNamePtr ) reentrant; declare pageNumber integer, selectionLetter byte, scriptNamePtr pointer, scriptName based scriptNamePtr (*) char; /* * using the page number and the selection letter, create the name of the * script on which an action is to be performed */ call strcpy( scriptNamePtr, @baseScriptName ); scriptName( 0 ) = byte( pageNumber - 1 ) + '1'; scriptName( 1 ) = selectionLetter; end deriveScriptName; /* * --------------------------------------------------- * Constructors * --------------------------------------------------- */ initializeMenuData: procedure ( fullProgramName ) reentrant public; declare fullProgramName pointer, fileExtensionPtr pointer, fileHandle word, numberRead word, lastSlashIndex word; /* * open the initialization file. that will allow us to get what we need * as the user has specified */ call strcpy( @iniFileName, fullProgramName ); call changeExtension( @iniFileName, @( 'ini', 0 ) ); iniHandle = openIni( @iniFileName ); /* * derive the name of the help file (the base name MUST be * the same as the executable) */ call strcpy( @menuHelpFileName, fullProgramName ); fileExtensionPtr = getFromIniData( iniHandle, @( 'Data', 0 ), @( 'helpExtension', 0 ) ); if ( NULL = fileExtensionPtr ) then do; /* * the key did not exist, so save the default */ fileExtensionPtr = @( 'hlp', 0 ); call storeInIniData( iniHandle, @( 'Data', 0 ), @( 'helpExtension', 0 ), fileExtensionPtr ); end; call changeExtension( @menuHelpFileName, fileExtensionPtr ); /* * derive the name of the data file */ call strcpy( @menuDataName, fullProgramName ); call changeExtension( @menuDataName, @( 'dat', 0 ) ); /* * open the data file, and read the data into the pageArray */ fileHandle = fopen( @menuDataName, @( 'rb', 0 ) ); if ( errno = 0 ) then do; /* * the file is open, read it and close it */ call memset( @pageArray, 0, size( pageArray ) ); numberRead = fread( fileHandle, @pageArray, size( pageArray ) ); if ( numberRead <> size( pageArray ) ) then do; call printStringAsciiZ( @( 'Unable to create acmeMenu selections', 0 ) ); call exit( UNABLE_TO_OPEN_INPUT ); end; call fclose( fileHandle ); end; /* * derive the name for the scripts */ call strcpy( @scriptDirectoryName, fullProgramName ); lastSlashIndex = findrb( @scriptDirectoryName, PATH_DELIM, strlen( @scriptDirectoryName ) ); scriptDirectoryName( lastSlashIndex + 1 ) = NUL; fileExtensionPtr = getFromIniData( iniHandle, @( 'Data', 0 ), @( 'scriptsDirectory', 0 ) ); if ( NULL = fileExtensionPtr ) then do; /* * the key did not exist, so save the default */ fileExtensionPtr = @( 'scripts', 0 ); call storeInIniData( iniHandle, @( 'Data', 0 ), @( 'scriptsDirectory', 0 ), fileExtensionPtr ); end; call strcat( @scriptDirectoryName, fileExtensionPtr ); menuDataScripts: do; declare attribReturned word, fileAttributes byte, fileHandle word, fileLength dword, scriptName ( MAX_PATH ) char, shortName ( MAX_PATH ) char, pageNumberIndex byte, pageNumber integer, stringLength word, selectionName byte, selectionIndex integer, numberWritten word; /* * ensure there is a directory to hold the scripts associated with each * selection */ attribReturned = attrib( @scriptDirectoryName, @( '-a', 0 ), @fileAttributes ); if ( attribReturned = 0 ) and ( ( fileAttributes and SUBDIR_MASK ) = 0 ) then do; /* * there is a problem because there is an existing file with the name * as we expected for the scripts directory */ call printStringAsciiZ( @( 'Unable to create acmeMenu scripts directory, name conflict', 0 ) ); call exit( INVALID_ENVIRONMENT ); end; else if ( attribReturned = 0 ) and ( ( fileAttributes and SUBDIR_MASK ) <> 0 ) then do; /* * the directory already exists, so we have no problems */ end; else do; declare returnCode word; /* * no file or directory, so create it and we are done */ returnCode = mkdir( @scriptDirectoryName ); end; /* * ensure that the scripts exist (regardless of contents). If not, * create it */ call strcat( @scriptDirectoryName, PATH_DELIM_STR ); do pageNumber = 1 to NUMBER_PAGES; do selectionName = 'A' to 'Z'; call strcpy( @scriptName, @scriptDirectoryName ); call deriveScriptName( pageNumber, selectionName, @shortName ); call strcat( @scriptName, @shortName ); /* * by opening the file for both read and write, no contents * are lost AND the file is created if it does not exist */ fileHandle = fopen( @scriptName, @( 'rw', 0 ) ); /* * if the file is empty (ftell at the end of the file returns 0), * create the "header" in the file */ call fseek( fileHandle, FROM_END_OF_FILE, 0 ); fileLength = ftell( fileHandle ); if ( 0 = fileLength ) then do; /* * the file is brand new, so provide the header information */ call fprintf( fileHandle, @( '@Echo Off', CR, LF, 0 ) ); call fprintf( fileHandle, @( '::\t%s', CR, LF, 0 ), @scriptName ); end; call fclose( fileHandle ); end; end; /* for each page number */ end menuDataScripts; end initializeMenuData; storeMenuData: procedure reentrant public; declare fileHandle word, numberWritten word, iniCloseReturned integer; fileHandle = fopen( @menuDataName, @( 'wb', 0 ) ); numberWritten = fwrite( fileHandle, @pageArray, size( pageArray ) ); call fclose( fileHandle ); iniCloseReturned = closeIni( iniHandle ); end storeMenuData; /* * --------------------------------------------------- * Accessors * --------------------------------------------------- */ showHelp: procedure ( firstArgumentString ) reentrant public; declare firstArgumentString pointer; declare listCommandNamePtr pointer, commandNameString pointer, viewReturned word, freeReturned integer, numberRows word, numberColumns word, colorAttribute byte; listCommandNamePtr = getFromIniData( iniHandle, @( 'Tools', 0 ), @( 'fileViewer', 0 ) ); if ( NULL = listCommandNamePtr ) then do; /* * the key/value did not exist in the configuration file, so * create the default and use it */ listCommandNamePtr = @( 'view', 0 ); call storeInIniData( iniHandle, @( 'Tools', 0 ), @( 'fileViewer', 0 ), listCommandNamePtr ); end; call screenSize( @numberColumns, @numberRows ); colorAttribute = getAttributeAtLocation( 0, 0 ); commandNameString = malloc( strlen( listCommandNamePtr ) + strlen( @menuHelpFileName ) + 2 ); if ( NULL <> commandNameString ) then do; call strcpy( commandNameString, listCommandNamePtr ); call strcat( commandNameString, @( ' ', 0 ) ); call strcat( commandNameString, @menuHelpFileName ); viewReturned = loadExec( commandNameString ); call clrWindow( 0, 0, numberColumns - 1, numberRows - 1, colorAttribute ); freeReturned = free( commandNameString ); end; else do; call fprintf( stderr, @( 'Insufficient memory to show help', CR, LF, 0 ) ); call pause; end; end showHelp; getSelectionName: procedure ( pageNumber, selectionLetter ) selectionNameType reentrant public; declare pageNumber word, selectionLetter char; return( @pageArray( pageNumber-1 ).selection( selectionLetter-'A' ).nameString( 0 ) ); end getSelectionName; executeScript: procedure ( pageNumber, selectionLetter ) integer reentrant public; declare pageNumber integer, selectionLetter byte; declare localScriptName ( MAX_PATH ) char, shortScriptName ( MAX_PATH ) char, scriptReturned word; call strcpy( @localScriptName, @scriptDirectoryName ); call deriveScriptName( pageNumber, selectionLetter, @localScriptName( strlen( @localScriptName ) ) ); $if LOGGING call addToLog( DEBUG, __FILE__, __LINE__, @( 'will execute %s', 0 ), @localScriptName ); $endif /* * we need to be sure that we are using the short name */ call convertToShortName( @localScriptName, @shortScriptName ); scriptReturned = loadExec( @shortScriptName ); return ( signed( scriptReturned ) ); end executeScript; /* * --------------------------------------------------- * Manipulators * --------------------------------------------------- */ setSelectionName: procedure ( pageNumber, selectionLetter, newNameString ) reentrant public; declare pageNumber word, selectionLetter char, newNameString pointer, selectionText based newNameString (*) char; /* * we must ensure that the selection text is not longer than allowed */ selectionText( SELECTION_NAME_LENGTH-1 ) = NUL; call strcpy( @pageArray( pageNumber-1 ).selection( selectionLetter-'A' ).nameString, newNameString ); end setSelectionName; editScript: procedure ( pageNumber, selectionLetter ) reentrant public; declare pageNumber integer, selectionLetter byte, selectionIndex integer, commandName ( MAX_PATH ) char, editorNamePtr pointer, exitCode word, localScriptName ( MAX_PATH ) char; /* * using the page number and the selection letter, create the name of the * script on which an action is to be performed */ call strcpy( @localScriptName, @scriptDirectoryName ); call deriveScriptName( pageNumber, selectionLetter, @localScriptName( strlen( @localScriptName ) ) ); /* * now, get the name of the editor */ editorNamePtr = getFromIniData( iniHandle, @( 'Tools', 0 ), @( 'scriptEditor', 0 ) ); if ( NULL = editorNamePtr ) then do; editorNamePtr = @( 'notepad.exe', 0 ); call storeInIniData( iniHandle, @( 'Tools', 0 ), @( 'scriptEditor', 0 ), editorNamePtr ); end; $if LOGGING call addToLog( DEBUG, __FILE__, __LINE__, @( '%s %s', 0 ), editorNamePtr, @localScriptName ); $endif call sprintf( @commandName, @( '%s %s', 0 ), editorNamePtr, @localScriptName ); call strcat( @commandName, @( CR, 0 ) ); exitCode = loadExec( @commandName ); end editScript; end menuCommands;