Operating-System-Simulator / Sim02 / configops.c
configops.c
Raw
// header file
#include "configops.h"

/*
 * Function Name: clearConfigData
 * Algorithm: frees allocated memory for config data
 * Precondition: configData holds allocated data set
 * Postcondition: memory is freed, pointer is set to null
 * Exceptions: None
 * Notes: None
 */
ConfigDataType *clearConfigData( ConfigDataType *configData )
   {
    // check that config data pointer is not null
    if( configData != NULL )
       {
        // free data structure memory
            // function: free
        free( configData );

        // set config data to null
        configData = NULL;
       }  
    // set config data pointer to null (returned as parameter)
    return NULL; 
   }

/*
 * Function Name: displayConfigData
 * Algorithm: diagnostic function to show config data output
 * Precondition: configData holds allocated data set
 * Postcondition: data is printed to screen
 * Exceptions: None
 * Notes: None
 */
void displayConfigData( ConfigDataType *configData )
   {
    // initialize function/variables
    char displayString[ STD_STR_LEN ];

    // print lines of display
        // function: printf, configCodeToString (translates coded items)
    printf( "Config File Display\n" );
    printf( "-------------------\n" );
    printf( "Version                : %3.2f\n", configData->version );
    printf( "Program file name      : %s\n",(char *)configData->metaDataFileName );
    configCodeToString( configData->cpuSchedCode, displayString );
    printf( "CPU schedule selection : %s\n", displayString );
    printf( "Quantum time           : %d\n", configData->quantumCycles );
    printf( "Memory Available       : %d\n", configData->memAvailable );
    printf( "Process cycle rate     : %d\n", configData->procCycleRate );
    printf( "I/O cycle rate         : %d\n", configData->ioCycleRate );
    configCodeToString( configData->logToCode, displayString );
    printf( "Log to selection       : %s\n", displayString );
    printf( "Log file name          : %s\n\n",(char *)configData->logToFileName );
   }

/*
 * Function Name: getConfigData
 * Algorithm: opens file, acquires configuration data,
 *            returns pointer to data structure
 * Precondition: for correct operation, file is available, is formatted 
 *               correctly, and has all configuration lines and data although 
 *               the configuration lines are not required to be 
 *               in a specific order
 * Postcondition: in correct operation,
 *                returns pointer to correct configuration data structure
 * Exceptions: correctly and appropriately (without program failure) responds to 
 *             and reports file access failure, incorrectly formatted lead or end 
 *             descriptors, incorrectly formatted prompt, data out of range, and 
 *             incomplete file conditions
 * Notes: None
 */
bool getConfigData( char *fileName,
                       ConfigDataType **configData, char *endStateMsg ) 
   {
    // initialize function/variables

        // set constant number of data lines
        const int NUM_DATA_LINES = 9;

        // set read only constant
        const char READ_ONLY_FLAG[] = "r";

        // create pointer for data input
        ConfigDataType *tempData;
        
        // declare other variables
        FILE *fileAccessPtr;
        char dataBuffer[ MAX_STR_LEN ];
        int intData, dataLineCode, lineCtr = 0;
        double doubleData;
        //bool dontStopAtNonPrintable = false;
        
    // set endStateMsg to success
        // function: copyString
    copyString( endStateMsg, "Configuration file upload successful" );

    // initialize config data pointer in case of return error
    *configData = NULL;

    // open file
        // function: fopen
    fileAccessPtr = fopen( fileName, READ_ONLY_FLAG );

    // check for file open failure
    if( fileAccessPtr == NULL )
       {
        // set end state message to config file access error
            // function: copyString
        copyString( endStateMsg, "Configuration file access error" );

        // return file access error
        return false;
       }

    // get first line, check for failure
        // function: getStringToDelimiter
    if( ! getStringToDelimiter ( fileAccessPtr, COLON, dataBuffer )
             || compareString( dataBuffer, "Start Simulator Configuration File" ) != STR_EQ )
       {
        // close file access
            // function: fclose
        fclose( fileAccessPtr );

        // set end state message to corrupt Leader Line error
            // function: copyString
        copyString( endStateMsg, "Corrupt configuration leader line error" );

        // return corrupt file data
        return false;
       }

    // create temporary pointer to configuration data structure
    tempData = (ConfigDataType *) malloc( sizeof( ConfigDataType ) );

    // loop to end of config data items
    while( lineCtr < NUM_DATA_LINES )
       {

        // get Line Leader, check for failure
            // function: getStringToDelimiter
        if( ! getStringToDelimiter ( fileAccessPtr, COLON, dataBuffer ) )
           {
            // free temp struct memory
                // function: free
            free( tempData );

            // close file access
                // function: fclose
            fclose( fileAccessPtr );

            // set end state message to line capture failure
                // function: copyString
            copyString( endStateMsg, "Configuration start line capture error" );

            // return incomplete file error
            return false;
           }
        
        // find correct data Line by number
            // function: getDataLineCode
        dataLineCode = getDataLineCode( dataBuffer );

        // check for data line found
        if( dataLineCode != CFG_CORRUPT_PROMPT_ERR )
           {
            // get data value

                // check for version number (double value)
                if( dataLineCode == CFG_VERSION_CODE )
                   {
                    // get version number
                        // function: fscanf
                    fscanf( fileAccessPtr, "%lf", &doubleData );
                   }
                // otherwise, check for metaData or LogTo file names
                //    or CPU Scheduling names (strings)
                else if( dataLineCode == CFG_MD_FILE_NAME_CODE
                           || dataLineCode == CFG_LOG_FILE_NAME_CODE 
                             || dataLineCode == CFG_CPU_SCHED_CODE
                               || dataLineCode == CFG_LOG_TO_CODE )
                   {
                    // get string input
                        // function: fscanf
                    fscanf( fileAccessPtr, "%s", dataBuffer );
                   }

                // otherwise, assume integer data
                else
                   {
                    // get integer input
                        // function: fscanf
                    fscanf( fileAccessPtr, "%d", &intData );
                   }

        // check for data value in range
            // function: valueInRange
        if( valueInRange( dataLineCode, intData, doubleData, dataBuffer ) )
           {
            // assign to data pointer depending on config item
                // function: getCpuSchedCode, getLogToCode
            switch( dataLineCode )
               {
                case CFG_VERSION_CODE:
                      
                   tempData->version = doubleData;
                   break;

                case CFG_MD_FILE_NAME_CODE:

                   copyString( (char *) tempData->metaDataFileName, dataBuffer );
                   break;
                
                case CFG_CPU_SCHED_CODE:

                   tempData->cpuSchedCode = getCpuSchedCode( dataBuffer );     
                   break;

                case CFG_QUANT_CYCLES_CODE:

                   tempData->quantumCycles = intData;
                   break;

                case CFG_MEM_AVAILABLE_CODE:

                   tempData->memAvailable = intData;
                   break;

                case CFG_PROC_CYCLES_CODE:

                   tempData->procCycleRate = intData;
                   break;

                case CFG_IO_CYCLES_CODE:

                   tempData->ioCycleRate = intData;
                   break;

                case CFG_LOG_TO_CODE:

                   tempData->logToCode = getLogToCode( dataBuffer );
                   break;

                case CFG_LOG_FILE_NAME_CODE:

                   copyString( (char *) tempData->logToFileName, dataBuffer );
                   break;
               }
           }

        // otherwise, assume data value not in range
        else
           {
            // free temp struct memory
                // function: free
            free( tempData );

            // close file access
                // function: fclose
            fclose( fileAccessPtr );

            // set end state message to configuration data out of range
                // function: copyString
            copyString( endStateMsg, "Configuration item out of range" );

            // return data out of range
            return false;
           }
           }

        // otherwise, assume data line not found
        else
           {
            // free temp struct memory
                // function: free
            free( tempData );

            // close file access
                // function: fclose
            fclose( fileAccessPtr );
                
            // set end state message to configuration corrupt prompt error
                // function: copyString
            copyString( endStateMsg, "Corrupted configuration prompt" );

            // return corrupt config file code
            return false;
           }

        // increment line counter
        lineCtr++;
       }

    // end master loop

    // acquire end of sim config string
        // function: getStringToDelimiter
    if( ! getStringToDelimiter ( fileAccessPtr, PERIOD, dataBuffer ) 
                    || compareString( dataBuffer, "End Simulator Configuration File" ) != STR_EQ )
       {
        // free temp struct memory
            // function: free
        free( tempData );

        // close file access
            // function: fclose
        fclose( fileAccessPtr );

        // set end state message to corrupt configuration end line
            // function: copyString
        copyString( endStateMsg, "Configuration end line capture error" );

        // return corrupt file data
        return false;
       }

    // assign temporary pointer to parameter return pointer
    *configData = tempData;

    // close file access
        // function: fclose
    fclose( fileAccessPtr );

    // return no error code
    return true; 
   }

/*
 * Function Name: configCodeToString
 * Algorithm: utility function to support display of cpu scheduling or 
 *            Log To code strings
 * Precondition: code variable holds constant value from ConfigDataCodes 
 *               for item (e.g., CPU_SCHED_SRTF_P, LOGTO_FILE_CODE, etc.)
 * Postcondition: string parameter holds correct string associated 
 *                with the given constant
 * Exceptions: None
 * Notes: None
 */
void configCodeToString( int code, char *outString )
   {
    // Define array with eight items, and short (10) lengths
    char displayStrings[ 8 ][ 10 ] = { "SJF-N", "SRTF-P", "FCFS-P",
                                       "RR-P", "FCFS-N", "Monitor",
                                       "File", "Both" };
    // copy string to return parameter
        // function: copyString
    copyString( outString, displayStrings[ code ] );
   }

/*
 * Function Name: getCpuSchedCode
 * Algorithm: converts string data (e.g., "SJF-N", "SRTF-P")
 *            to constant code number to be stored as integer
 * Precondition: codeStr is a c-style string with one of the specified 
 *               cpu scheduling operations 
 * Postcondition: returns code representing scheduling actions
 * Exceptions: defaults to fcfs code
 * Notes: None
 */
ConfigDataCodes getCpuSchedCode( char *codeStr )
   {
    // initialize function/variables 

        // set up temporary string for testing
            // function: getStringLength, malloc
        int strLen = getStringLength( codeStr );
        char *tempStr = (char *)malloc( strLen + 1 );

        // set default return to FCFS-N
        int returnVal = CPU_SCHED_FCFS_N_CODE;

    // set string to lower case for testing
        // function: setStrToLowerCase
    setStrToLowerCase( tempStr, codeStr );

    // check for SJF-N
        // function: compareString
    if( compareString( tempStr, "sjf-n" ) == STR_EQ )
       {
        // set return code to sjf
        returnVal = CPU_SCHED_SJF_N_CODE;
       }
        
    // check for SRTF-P
        // function: compareString
    if( compareString( tempStr, "srtf-p" ) == STR_EQ )
       {
        // set return code to srtf
        returnVal = CPU_SCHED_SRTF_P_CODE;
       }

    // check for FCFS-P
        // function: compareString
    if( compareString( tempStr, "fcfs-p" ) == STR_EQ )
       {
        // set return code to fcfs
        returnVal = CPU_SCHED_FCFS_P_CODE;
       }

    // check for RR-P
        // function: compareString
    if( compareString( tempStr, "rr-p" ) == STR_EQ )
       {
        // set return code to rr
        returnVal = CPU_SCHED_RR_P_CODE;
       }

    // free temp string memory
        // function: free
    free( tempStr );

    // return found value
    return returnVal;
   }

/*
 * Function Name: getLogToCode
 * Algorithm: converts string data (e.g., "File", "Monitor")
 *            to constant code number to be stored as integer
 * Precondition: codeStr is a c-style string with one of the specified
 *               log to operations 
 * Postcondition: returns code representing log to actions 
 * Exceptions: defaults to monitor code 
 * Notes: None
 */
ConfigDataCodes getLogToCode( char *logToStr )
   {
    // initialize function/variables
    
        // create temporary string
            // function: getStringLength, malloc
        int strLen = getStringLength( logToStr );
        char *tempStr = (char *)malloc( strLen + 1 );

        // set default to log to monitor
        int returnVal = LOGTO_MONITOR_CODE;

    // set temp string to lower case
        // function: setStrToLowerCase
    setStrToLowerCase( tempStr, logToStr );

    // check for BOTH
        // function: compareString
    if( compareString( tempStr, "both" ) == STR_EQ )
       {
        // set return value to both code
        returnVal = LOGTO_BOTH_CODE;
       }

    // check for FILE
        // function: compareString
    if( compareString( tempStr, "file" ) == STR_EQ )
       {
        // set return value to file code
        returnVal = LOGTO_FILE_CODE;
       }

    // free temp string memory
        // function: free
    free( tempStr );

    // return found value
    return returnVal;
   }

/*
 * Function Name: getDataLineCode
 * Algorithm: tests string for one of known leader strings, returns line number
 *            if string is correct, returns CFG_CORRUPT_DATA_ERR if string is 
 *            not found
 * Precondition: dataBuffer is valid c-style string
 * Postcondition: returns line number of data item in terms of a constant
 *                (e.g., CFG_VERSION_CODE, CFG_CPU_SCHED_CODE, etc.)
 * Exceptions: returns CFG_CORRUPT_FILE_ERR if string is not identified
 * Notes: None
 */
int getDataLineCode( char *dataBuffer )
   {
    // return appropriate code depending on prompt string provided
        // function: compareString
    if( compareString( dataBuffer, "Version/Phase" ) == STR_EQ )
       {
        return CFG_VERSION_CODE;
       }

    if( compareString( dataBuffer, "File Path" ) == STR_EQ )
       {
        return CFG_MD_FILE_NAME_CODE;
       }
    
    if( compareString( dataBuffer, "CPU Scheduling Code" ) == STR_EQ )
       {
        return CFG_CPU_SCHED_CODE;
       }

    if( compareString( dataBuffer, "Quantum Time (cycles)" ) == STR_EQ )
       {
        return CFG_QUANT_CYCLES_CODE;
       }

    if( compareString( dataBuffer, "Memory Available (KB)" ) == STR_EQ )
       {
        return CFG_MEM_AVAILABLE_CODE;
       }

    if( compareString( dataBuffer, "Processor Cycle Time (msec)" ) == STR_EQ )
       {
        return CFG_PROC_CYCLES_CODE;
       }

    if( compareString( dataBuffer, "I/O Cycle Time (msec)" ) == STR_EQ )
       {
        return CFG_IO_CYCLES_CODE;
       }

    if( compareString( dataBuffer, "Log To" ) == STR_EQ )
       {
        return CFG_LOG_TO_CODE;
       }

    if( compareString( dataBuffer, "Log File Path" ) == STR_EQ )
       {
        return CFG_LOG_FILE_NAME_CODE;
       }

    return CFG_CORRUPT_PROMPT_ERR;
   }

/*
 * Function Name: valueInRange
 * Algorithm: tests one of three values (int, double, string) for being in 
 *            a specified range, depending on data code
 *            (i.e., specified config value)
 * Precondition: one of the three data values is valid
 * Postcondition: returns true if data is within specified parameters,
 *                false otherwise
 * Exceptions: metadata or logfile names are ignored and return true
 * Notes: None
 */
bool valueInRange( int lineCode, int intVal, double doubleVal, char *stringVal )
   {
    // initialize function/variables
    bool result = true;
    char *tempStr;
    int strLen;

    // use line code to identify prompt line
    switch( lineCode )
       {
        // for version code
        case CFG_VERSION_CODE:

            // check if limits of version code are exceeded
            if( doubleVal < 0.00 || doubleVal > 10.00 )
               {
                // set bool result to false
                result = false;
               }
            break;

        // for cpu scheduling code
        case CFG_CPU_SCHED_CODE:

            // create temporary string and set to lower case
                // function: getStringLength, malloc, setStrToLowerCase
            strLen = getStringLength( stringVal );
            tempStr = (char *)malloc( strLen + 1);
            setStrToLowerCase( tempStr, stringVal );

            // check for not finding one of the scheduling strings
                // function: compareString
            if( compareString( tempStr, "fcfs-n" ) != STR_EQ 
                && compareString( tempStr, "sjf-n" ) != STR_EQ
                && compareString( tempStr, "srtf-p" ) != STR_EQ
                && compareString( tempStr, "fcfs-p" ) != STR_EQ
                && compareString( tempStr, "rr-p" ) != STR_EQ )
               {
                // set bool result to false
                result = false;
               }

            // free temp string memory
                // function: free
            free( tempStr );

            break;

        // for quantum cycles
        case CFG_QUANT_CYCLES_CODE:

            // check for quantum cycles limits exceeded
            if( intVal < 0 || intVal > 100 )
               {
                // set bool result to false
                result = false;
               }
            break;

        // for memory available
        case CFG_MEM_AVAILABLE_CODE:

            // check for available memory limits exceeded
            if( intVal < 1024 || intVal > 102400 )
               {
                // set bool result to false
                return false;
               }
            break;

        // check for process cycles
        case CFG_PROC_CYCLES_CODE:

            // check for process cycles limits exceeded
            if( intVal < 1 || intVal > 1000 )
               {
                // set bool result to false
                result = false;
               }
            break;

        // check for I/O cycles
        case CFG_IO_CYCLES_CODE:
            
            // check for I/O cycles limits exceeded 
            if( intVal < 1 || intVal > 10000 )
               {
                // set bool result to false
                result = false;
               }
            break;

        // check for log to operation
        case CFG_LOG_TO_CODE:

            // create temporary string and set to lower case
                // function: getStringLength, malloc, setStrToLowerCase
            strLen = getStringLength( stringVal );
            tempStr = (char *)malloc( strLen + 1 );
            setStrToLowerCase( tempStr, stringVal );

            // check for not finding one of the log to strings
                // function: compareString
            if( compareString( tempStr, "both" ) != STR_EQ
                && compareString( tempStr, "monitor" ) != STR_EQ
                && compareString( tempStr, "file" ) != STR_EQ )
               {
                // set bool result to false
                result = false;
               }

            // free temp string memory
                // function: free
            free( tempStr );
            
            break;

        // check if file name is legitimate
        case CFG_LOG_FILE_NAME_CODE:

            strLen = getStringLength( stringVal );
            // string must be at least length 4 - regardless must hold a string quantity
            if( strLen >= 4 )
               {
                // create temporary string and set to lower case
                tempStr = (char *)malloc( strLen + 1 );
                setStrToLowerCase( tempStr, stringVal );

                char * subStr = (char *)malloc( strLen + 1 );
                getSubString( subStr, tempStr, strLen - 4 , strLen - 1);
                
                // test if string fits specification
                if( compareString( tempStr, "none" ) != STR_EQ
                    && compareString( subStr, ".lgf" ) != STR_EQ )
                   {
                    result = false;
                   }

                // free temp and sub string memory
                free( tempStr );
                free( subStr );
               }
            else
               {
                result = false;
               }

            break;
       }

    // return results of limits analysis
    return result;
   }