function [ piStarControl, error, piStarControlFields ] = ...
    parseIniFile( startPiHandle,  newPiStarControl, piStarControlFields, ...
                  parseDatabase, loadDatabase, databaseFileType, ...
                  databaseBlockCount )
% $Id: parseIniFile.m,v 1.1 2003/09/30 16:41:15 stuart Exp $
%
% Parse the PiStar.ini file.
%
% Passed:
% starPiHandle: handle for PiLab startup figure.
% newPiStarControl: [optional] new structure used to update .ini file.
%   If this is not empty, then the .ini file is updated unless the
%   parseDatabase or loadDatabase flag is set.
% piStarControlFields: cell array of strings: names of piStarControl
%   structure fields that have been updated by the GUI. Used to update
%   .ini file.  
% parseDatabase: flag, set: parse the piStarDatabase.ini file and
%   obtained specific fields for the UI.
% loadDatabase: flag, set: similar to parseDatabase, but loads a
%   specific block (see below) into piStarControl having first
%   initialized piStarControl with newPiStarControl
% databaseFileType: type of database file (baseline archive file,
%   simulation scenario file...). Used when loadDatabase is set. Also
%   define the delimiter (block type) searched for loading.
% databaseBlockCount: the block number loaded when the flag loadDatabase
%   is set. A value of zero = load all blocks. This is used for
%   simulation scenario files which load all segments (blocks).
%
% Returned:
% piStarControl: updated structure of controls.
% Error status: 0 = no errors, 1 = errors (for example, file opening).
% piStarControlFields: updated structure fields, used when loading from
%     the database.


%%%%%%%%%% Definitions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
TRUE = 1 ;
FALSE = 0 ;
iniFileNameStr  = 'piStar.ini' ;
iniShortNameStr = 'piStar.ini' ;  % Never includes the full path.
newIniFileNameStr  = 'NEWpiStar.ini' ;
tabChar = sprintf( '\t' ) ;
spaceChar = ' ' ;
d_PILINE = 1 ; % Corresponds with utilityNameCellStr.
d_PISTAR = 2 ;
d_RKWIN  = 3 ;
d_PIPRO  = 4 ;
d_DATABASE = 5 ;
d_SIMULATION = 6 ;  % General simulation parameters (all segments).
d_SIMSEGMENT = 7 ;  % Parameters for single segment of the simulation.
utilityNameCellStr = { 'PiLine' 'PiStar' 'RKWin' 'PiPro' 'Database' ...
                       'Simulation' 'Simuation' } ;
d_BASELINE_FILE   = 1 ; % Corresponds with databaseDelimiterCellStr.
d_SIMULATION_FILE = 2 ;
databaseDelimiterCellStr = { 'BASELINE' 'SEGMENT' } ;  % To be extended.
% Header prior to new additions to the .ini file (from the display).
% Header prior to new additions to the .ini file (from the display).
% Format inlcudes %s = utility name from utilityNameCellStr,
%                 %s = Date
%                 %d %d = Time, hours minutes
headerFormatStr = [ '\n// %s parameters first added on' ...
                    ' Date: %s  Time: %02d:%02d\n\n' ] ;
d_MAX_DATABASES = 10 ;  % Number of data base list files and names.
% Dimension of this array must equal d_MAX_DATABASES.
databaseDefaultNameCellStr = { 'Database 1' 'Database 2' 'Database 3' ...
                               'Database 4' 'Database 5' 'Database 6' ...
                               'Database 7' 'Database 8' 'Database 9' ...
                               'Database 10' } ;
d_HTTP_TMP_FILE_STR = 'httpDatabaseList.txt' ;

% The structure piStarControl if loaded from the .ini file. The fields
% are given below:
% structure piStarControl
% {
%   PiLine parameters                                      .ini value name
%   -----------------                                      ---------------
%   baseFileNameStr    1xn array char, used as string      baseFileName
%   roverFileNameStr   1xn array char, used as string      roverFileName
%   basePositionX      1x1 array numeric, used as double   basePositionX
%   basePositionY      1x1 array numeric, used as double   basePositionY
%   basePositionZ      1x1 array numeric, used as double   basePositionZ
%   basePositionLat    1x1 array numeric, used as double   basePositionLat
%   basePositionLon    1x1 array numeric, used as double   basePositionLon
%   basePositionHgt    1x1 array numeric, used as double   basePositionHgt
%   baseLatComponenetsVec  1x3 array numeric, used as double, degs, mins, secs
%   baseLonComponenetsVec  1x3 array numeric, used as double, degs, mins, secs
%   baseXComputed    1x1 array numeric, used as double
%   baseYComputed    1x1 array numeric, used as double
%   baseZComputed    1x1 array numeric, used as double
%   roverPositionX     1x1 array numeric, used as double   roverPositionX
%   roverPositionY     1x1 array numeric, used as double   roverPositionY
%   roverPositionZ     1x1 array numeric, used as double   roverPositionZ
%   roverPositionLat   1x1 array numeric, used as double   roverPositionLat
%   roverPositionLon   1x1 array numeric, used as double   roverPositionLon
%   roverPositionHgt   1x1 array numeric, used as double   roverPositionHgt
%   roverLatComponenetsVec  1x3 array numeric, used as double, degs, mins, secs
%   roverLonComponenetsVec  1x3 array numeric, used as double, degs, mins, secs
%   roverXComputed   1x1 array numeric, used as double
%   roverYComputed   1x1 array numeric, used as double
%   roverZComputed   1x1 array numeric, used as double
%   baselineVectorX    1x1 array numeric, used as double   baselineVectorX
%   baselineVectorY    1x1 array numeric, used as double   baselineVectorY
%   baselineVectorZ    1x1 array numberic, used as double  baselineVectorZ
%   baselineLength     1x1 array numberic, used as double  baselineLength
%   baseAntennaType    1x1 array numeric, used as double   baseAntennaType
%   roverAntennaType   1x1 array numeric, used as double   roverAntennaType
%   localTimeOffset    1x1 array numeric, used as double   localTimeOffset
%   loadStartTime      1x1 array numeric, used as double   startTime
%   loadStopTime       1x1 array numeric, used as double   stopTime
%
%   Note: 'baselineLength' can be provided in a special piStar.ini file
%   generated by the regression system (to support BID diagnostics).
%
%   PiStar parameters
%   -----------------
%   multipliersLoaded  1x1 array numeric, used as flag
%   multipliersValid   1x1 array numeric, used as flag
%   phaseMultiplierL1  1x1 array numeric, used as double   phaseMultiplierL1
%   phaseMultiplierL2  1x1 array numeric, used as double   phaseMultiplierL2
%   rangeMultiplierL1  1x1 array numeric, used as double   rangeMultiplierL1
%   rangeMultiplierL2  1x1 array numeric, used as double   rangeMultiplierL2
%
%   RKWin parameters
%   ----------------
%   rtkElevation       1x1 array numeric, used as double   rtkElevation
%   rtkVRSBaseline     1x1 array numeric, used as double   rtkVRSBaseline
%   rtkBackTrack       1x1 array numeric, used as double   rtkBackTrack
%   rtkHorizTolerance  1x1 array numeric, used as double   rtkHorizTolerance
%   rtkVertTolerance   1x1 array numeric, used as double   rtkVertTolerance
%   rtkAdapativeTolerance 1x1 array numeric, used as flag  rtkAdapativeTolerance
%   rtkHorizOffset     1x1 array numeric, used as double   rtkHorizOffset
%   rtkVertOffset      1x1 array numeric, used as double   rtkVertOffset
%   rtkHorizPPM        1x1 array numeric, used as double   rtkHorizPPM
%   rtkVertPPM         1x1 array numeric, used as double   rtkVertPPM
%   rtkToleranceMult   1x1 array numeric, used as double   rtkToleranceMult
%   rtkTestMode        1x1 array numeric, used as double   rtkTestMode
%   rtkBIDTimeOut      1x1 array numeric, used as double   rtkBIDTimeOut
%   rtkWeighting       1x1 array numeric, used as double   rtkWeighting
%   rtkSVRejection     1x1 array numeric, used as double   rtkSVRejection
%   rtkFloatAveraging  1x1 array numeric, used as double   rtkFloatAveraging
%   rtkSearchProbThreshold  1x1 array numeric, double    rtkSearchProbThreshold
%   rtkIonoModel       1x1 array numeric, used as double   rtkIonoModel
%   rtkIonoPPM         1x1 array numeric, used as double   rtkIonoPPM
%   rtkIonoScaleFactor 1x1 array numeric, used as double   rtkIonoScaleFactor
%   rtkDisableTropo    1x1 array numeric, used as flag     rtkDisableTropo
%   rtkDisableIono     1x1 array numeric, used as flag     rtkDisableIono
%   rtkRKwinFileName   1xn array char, used as string      rtkRKwinFileName
%   rtkPlotNameSuffix  1xn array char, used as string      rtkPlotNameSuffix
%   rtkEastOffset      1x1 array numeric, used as double   rtkEastOffset
%   rtkNorthOffset     1x1 array numeric, used as double   rtkNorthOffset
%   rtkUpOffset        1x1 array numeric, used as double   rtkUpOffset
%
%   PiPro parameters
%   ----------------
%   piProCodeAxis       1x1 array numeric, used as double  piProCodeAxis
%   piProPhaseAxis      1x1 array numeric, used as double  piProPhaseAxis
%   piProSavePlots      1x1 array numeric, used as flag    piProSavePlots 
%   piProFileName       1xn array char, used as string     piProFileName
%   piProEnableFFT      1x1 array numeric, used as flag    piProEnableFFT 
%   piProEnableACF      1x1 array numeric, used as flag    piProEnableACF 
%   piProQuickMode      1x1 array numeric, used as double  piProQuickMode 
%   piProCNRElevMask    1x1 array numeric, used as double  piProCNRElevMask 
%   piProSigmaMask      1x1 array numeric, used as double  piProSigmaMask
%   piProSkipCNRTests   1x1 array numeric, used as flag    piProSkipCNRTests 
%   piProOmitLegend     1x1 array numeric, used as flag    piProOmitLegend   
%
%   Database parameters (used in piStar.ini, where specified)
%   -------------------
%   databaseListCell     1xn cell array of strings         databaseListFile
%   databaseNameCell     1xn cell array of strings         databaseName
%   selectedDatabase     1x1 array numeric, used as double selectedDatabase
%   databasePathPrefixCell 1xn cell array of strings       databasePathPrefix
%   cacheDirectory      1xn array char, used as string     cacheDirectoryStr

%   Database parameters (used in piStarDatabase.ini)
%   -------------------
%   baselineName        1xn array char, used as string     baselineNameStr
%   description         1xn array char, used as string     descriptionStr
%
%   General purpose (for example, supporting processed data from the
%   regression system which may generate a special piStar.ini file)
% }


%%%%%%%%%% Initialization %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Load cell array used to parse and update the .ini file. Enables the
% name of the piStarControl structure field name to be otained from the
% corresponding name of the control parameter in the .ini file, and visa
% versa.  (Most of these match the structure field names, but not all).
% The columns are:
% { name of field in piStarControl Structure }
%       { name of control parameter in the .ini file }
%             { type of value, 0 = string,
%                              1 = number,
%                              2 = 'yes' or 'no'
%                              3 = geodetic position latitude
%                              4 = geodetic position longitude }
%                              5 = string, (filename in database)
%                              6 = cell array of strings
% Type 5 is used to indentify filenames from the database that may
% require the  path prefix from databasePathPrefixCell.
% Type 6 uses the same 'name of control parameter' multiples times in
% the .ini file.
%
% Technical note:
% This cell array could also be loaded row by row using:
% controlCellArray = {} ;  To define as cell array.
% controlCellArray(  1, : ) = [ { 'string1' } { 'string2' } { number } ] ;
% controlCellArray(  2, : ) = [ { 'string1' } { 'string2' } { number } ] ; etc

%   PiLine parameters
controlCellArray = { 'baseFileNameStr'   'baseFileName'     5  d_PILINE ; ...
                     'roverFileNameStr'  'roverFileName'    5  d_PILINE ; ...
                     'basePositionX'     'basePositionX'    1  d_PILINE ; ...
                     'basePositionY'     'basePositionY'    1  d_PILINE ; ...
                     'basePositionZ'     'basePositionZ'    1  d_PILINE ; ...
                     'basePositionLat'   'basePositionLat'  3  d_PILINE ; ...
                     'basePositionLon'   'basePositionLon'  4  d_PILINE ; ...
                     'basePositionHgt'   'basePositionHgt'  1  d_PILINE ; ...
                     'roverPositionX '   'roverPositionX'   1  d_PILINE ; ...
                     'roverPositionY'    'roverPositionY'   1  d_PILINE ; ...
                     'roverPositionZ'    'roverPositionZ'   1  d_PILINE ; ...
                     'roverPositionLat'  'roverPositionLat' 3  d_PILINE ; ...
                     'roverPositionLon'  'roverPositionLon' 4  d_PILINE ; ...
                     'roverPositionHgt'  'roverPositionHgt' 1  d_PILINE ; ...
                     'baselineVectorX'   'baselineVectorX'  1  d_PILINE ; ...
                     'baselineVectorY'   'baselineVectorY'  1  d_PILINE ; ...
                     'baselineVectorZ'   'baselineVectorZ'  1  d_PILINE ; ...
                     'baselineLength'    'baselineLength'   1  d_PILINE ; ...
                     'baseAntennaType'   'baseAntennaType'  1  d_PILINE ; ...
                     'roverAntennaType'  'roverAntennaType' 1  d_PILINE ; ...
                     'localTimeOffset'   'localTimeOffset'  1  d_PILINE ; ...
                     'loadStartTime'     'startTime'        1  d_PILINE ; ...
                     'loadStopTime'      'stopTime'         1  d_PILINE ; ...
%   PiStar parameters
                     'phaseMultiplierL1' 'phaseMultiplierL1' 1 d_PISTAR; ...
                     'phaseMultiplierL2' 'phaseMultiplierL2' 1 d_PISTAR; ...
                     'rangeMultiplierL1' 'rangeMultiplierL1' 1 d_PISTAR; ...
                     'rangeMultiplierL2' 'rangeMultiplierL2' 1 d_PISTAR; ...
%   RKWin parameters
                     'rtkElevation'      'rtkElevation'      1 d_RKWIN ; ...
                     'rtkVRSBaseline'    'rtkVRSBaseline'    1 d_RKWIN ; ...
                     'rtkBackTrack'      'rtkBackTrack'      1 d_RKWIN ; ...
                     'rtkHorizTolerance' 'rtkHorizTolerance' 1 d_RKWIN ; ...
                     'rtkVertTolerance'  'rtkVertTolerance'  1 d_RKWIN ; ...
             'rtkAdaptiveTolerance'  'rtkAdaptiveTolerance'  2 d_RKWIN ; ...
                     'rtkHorizOffset'    'rtkHorizOffset'    1 d_RKWIN ; ...
                     'rtkVertOffset'     'rtkVertOffset'     1 d_RKWIN ; ...
                     'rtkHorizPPM'       'rtkHorizPPM'       1 d_RKWIN ; ...
                     'rtkVertPPM'        'rtkVertPPM'        1 d_RKWIN ; ...
                     'rtkToleranceMult'  'rtkToleranceMult'  1 d_RKWIN ; ...
                     'rtkTestMode'       'rtkTestMode'       1 d_RKWIN ; ...
                     'rtkBIDTimeOut'     'rtkBIDTimeOut'     1 d_RKWIN ; ...
                     'rtkWeighting'      'rtkWeighting'      1 d_RKWIN ; ...
                     'rtkSVRejection'    'rtkSVRejection'    1 d_RKWIN ; ...
                  'rtkFloatAveraging'    'rtkFloatAveraging' 1 d_RKWIN ; ...
           'rtkSearchProbThreshold' 'rtkSearchProbThreshold' 1 d_RKWIN ; ...
                     'rtkIonoModel'      'rtkIonoModel'      1 d_RKWIN ; ...
                     'rtkIonoPPM'        'rtkIonoPPM'        1 d_RKWIN ; ...
                   'rtkIonoScaleFactor' 'rtkIonoScaleFactor' 1 d_RKWIN ; ...
                     'rtkDisableTropo'   'rtkDisableTropo'   2 d_RKWIN ; ...
                     'rtkDisableIono'    'rtkDisableIono'    2 d_RKWIN ; ...
                     'rtkRKwinFileName'  'rtkRKwinFileName'  0 d_RKWIN ; ...
                     'rtkPlotNameSuffix' 'rtkPlotNameSuffix' 0 d_RKWIN ; ...
                     'rtkEastOffset'     'rtkEastOffset'     1 d_RKWIN ; ...
                     'rtkNorthOffset'    'rtkNorthOffset'    1 d_RKWIN ; ...
                     'rtkUpOffset'       'rtkUpOffset'       1 d_RKWIN ; ...
                     'rtkPositionType'   'rtkPositionType'   1 d_RKWIN ; ...
                     'rtkDualFreqOnly'   'rtkDualFreqOnly'   2 d_RKWIN ; ...
                     'rtkCustomFlagsStr' 'rtkCustomFlags'    0 d_RKWIN ; ...
%   PiPro parameters
                     'piProCodeAxis'     'piProCodeAxis'     1 d_PIPRO ; ...
                     'piProPhaseAxis'    'piProPhaseAxis'    1 d_PIPRO ; ...
                     'piProSavePlots'    'piProSavePlots'    2 d_PIPRO ; ...
                     'piProFileName'     'piProFileName'     0 d_PIPRO ; ...
                     'piProEnableFFT'    'piProEnableFFT'    2 d_PIPRO ; ...
                     'piProEnableACF'    'piProEnableACF'    2 d_PIPRO ; ...
                     'piProQuickMode'    'piProQuickMode'    1 d_PIPRO ; ...
                     'piProCNRElevMask'  'piProCNRElevMask'  1 d_PIPRO ; ...
                     'piProSigmaMask'    'piProSigmaMask'    1 d_PIPRO ; ...
                     'piProSkipCNRTests' 'piProSkipCNRTests' 2 d_PIPRO ; ...
                     'piProOmitLegend'   'piProOmitLegend'   2 d_PIPRO ; ...
%   Database parameters
                     'baselineNameStr'   'baselineName'      0 d_DATABASE ; ...
                     'descriptionStr'    'description'       0 d_DATABASE ; ...
                     'databaseListCell'  'databaseListFile'  6 d_DATABASE ; ...
                     'databaseNameCell'  'databaseName'      6 d_DATABASE ; ...
                     'selectedDatabase'  'selectedDatabase'  1 d_DATABASE ; ...
                     'cacheDirectoryStr' 'cacheDirectory'    0 d_DATABASE ; ...
               'databasePathPrefixCell' 'databasePathPrefix' 6 d_DATABASE ; ...
%   Simulation parameters (all segments) in PiStar.ini file
                    'simScenarioFileStr' 'simScenarioFile'   0 d_SIMULATION ;...
           'simPositionFileEnabled' 'simPositionFileEnabled' 2 d_SIMULATION ;...
%   Simulation parameters (all segments) in simulation .ini file
                    'simPositionFileStr' 'simPositionFile'   0 d_SIMULATION ;...
                     'simNameStr'        'simName'           0 d_SIMULATION ;...
                     'simDescriptionStr' 'simDescription'    0 d_SIMULATION ;...
                     'simPlotNameSuffix' 'simPlotNameSuffix' 0 d_SIMULATION ;...
                     'simStartTime'      'simStartTime'      1 d_SIMULATION ;...
                     'simEpochRate'      'simEpochRate'      1 d_SIMULATION ;...
                     'simSnapToEpoch'    'simSnapToEpoch'    2 d_SIMULATION ;...
                     'simStartSpeed'     'simStartSpeed'     1 d_SIMULATION ;...
                 'simBasePositionLat' 'simBasePositionLat'  3 d_SIMULATION ;...
                 'simBasePositionLon' 'simBasePositionLon'  4 d_SIMULATION ;...
                 'simBasePositionHgt' 'simBasePositionHgt'  1 d_SIMULATION ;...
                 'simRoverPositionLat' 'simRoverPositionLat' 3 d_SIMULATION ;...
                 'simRoverPositionLon' 'simRoverPositionLon' 4 d_SIMULATION ;...
                 'simRoverPositionHgt' 'simRoverPositionHgt' 1 d_SIMULATION ;...
%   Simulation parameters used by PiLine observation generation.
                 'simBaseAntennaType'  'simBaseAntennaType'  1 d_SIMULATION ;...
                 'simRoverAntennaType' 'simRoverAntennaType' 1 d_SIMULATION ;...
                 'simBaseClockOffset'  'simBaseClockOffset'  1 d_SIMULATION ;...
                 'simBaseClockRate'    'simBaseClockRate'    1 d_SIMULATION ;...
                 'simRoverClockOffset' 'simRoverClockOffset' 1 d_SIMULATION ;...
                 'simRoverClockRate'   'simRoverClockRate'   1 d_SIMULATION ;...
                 'simElevationMask'    'simElevationMask'    1 d_SIMULATION ;...
                 'simEphemerisFileStr' 'simEphemerisFile'    0 d_SIMULATION ;...
                 'simBaseFileStr'      'simBaseFile'         0 d_SIMULATION ;...
                 'simRoverFileStr'     'simRoverFile'        0 d_SIMULATION ;...
%   Simulation parameters (noise) used by PiLine observation generation.
                       'simNoiseSeed'  'simNoiseSeed'        1 d_SIMULATION ;...
                 'simCodeNoiseBaseL1'  'simCodeNoiseBaseL1'  1 d_SIMULATION ;...
                 'simCodeNoiseBaseL2'  'simCodeNoiseBaseL2'  1 d_SIMULATION ;...
                 'simCodeNoiseBaseL5'  'simCodeNoiseBaseL5'  1 d_SIMULATION ;...
                 'simCodeNoiseRoverL1' 'simCodeNoiseRoverL1' 1 d_SIMULATION ;...
                 'simCodeNoiseRoverL2' 'simCodeNoiseRoverL2' 1 d_SIMULATION ;...
                 'simCodeNoiseRoverL5' 'simCodeNoiseRoverL5' 1 d_SIMULATION ;...
                 'simPhaseNoiseBaseL1' 'simPhaseNoiseBaseL1' 1 d_SIMULATION ;...
                 'simPhaseNoiseBaseL2' 'simPhaseNoiseBaseL2' 1 d_SIMULATION ;...
                 'simPhaseNoiseBaseL5' 'simPhaseNoiseBaseL5' 1 d_SIMULATION ;...
               'simPhaseNoiseRoverL1' 'simPhaseNoiseRoverL1' 1 d_SIMULATION ;...
               'simPhaseNoiseRoverL2' 'simPhaseNoiseRoverL2' 1 d_SIMULATION ;...
               'simPhaseNoiseRoverL5' 'simPhaseNoiseRoverL5' 1 d_SIMULATION ;...
           'simCodeMultipathBaseL1' 'simCodeMultipathBaseL1' 1 d_SIMULATION ;...
           'simCodeMultipathBaseL2' 'simCodeMultipathBaseL2' 1 d_SIMULATION ;...
           'simCodeMultipathBaseL5' 'simCodeMultipathBaseL5' 1 d_SIMULATION ;...
         'simCodeMultipathRoverL1' 'simCodeMultipathRoverL1' 1 d_SIMULATION ;...
         'simCodeMultipathRoverL2' 'simCodeMultipathRoverL2' 1 d_SIMULATION ;...
         'simCodeMultipathRoverL5' 'simCodeMultipathRoverL5' 1 d_SIMULATION ;...
         'simPhaseMultipathBaseL1' 'simPhaseMultipathBaseL1' 1 d_SIMULATION ;...
         'simPhaseMultipathBaseL2' 'simPhaseMultipathBaseL2' 1 d_SIMULATION ;...
         'simPhaseMultipathBaseL5' 'simPhaseMultipathBaseL5' 1 d_SIMULATION ;...
       'simPhaseMultipathRoverL1' 'simPhaseMultipathRoverL1' 1 d_SIMULATION ;...
       'simPhaseMultipathRoverL2' 'simPhaseMultipathRoverL2' 1 d_SIMULATION ;...
       'simPhaseMultipathRoverL5' 'simPhaseMultipathRoverL5' 1 d_SIMULATION ;...
   'simCodeMultipathCorrBaseL1' 'simCodeMultipathCorrBaseL1' 1 d_SIMULATION ;...
   'simCodeMultipathCorrBaseL2' 'simCodeMultipathCorrBaseL2' 1 d_SIMULATION ;...
   'simCodeMultipathCorrBaseL5' 'simCodeMultipathCorrBaseL5' 1 d_SIMULATION ;...
 'simCodeMultipathCorrRoverL1' 'simCodeMultipathCorrRoverL1' 1 d_SIMULATION ;...
 'simCodeMultipathCorrRoverL2' 'simCodeMultipathCorrRoverL2' 1 d_SIMULATION ;...
 'simCodeMultipathCorrRoverL5' 'simCodeMultipathCorrRoverL5' 1 d_SIMULATION ;...
 'simPhaseMultipathCorrBaseL1' 'simPhaseMultipathCorrBaseL1' 1 d_SIMULATION ;...
 'simPhaseMultipathCorrBaseL2' 'simPhaseMultipathCorrBaseL2' 1 d_SIMULATION ;...
 'simPhaseMultipathCorrBaseL5' 'simPhaseMultipathCorrBaseL5' 1 d_SIMULATION ;...
 'simPhaseMultipathCorrRoverL1' ...
                              'simPhaseMultipathCorrRoverL1' 1 d_SIMULATION ;...
 'simPhaseMultipathCorrRoverL2' ...
                              'simPhaseMultipathCorrRoverL2' 1 d_SIMULATION ;...
 'simPhaseMultipathCorrRoverL5' ...
                              'simPhaseMultipathCorrRoverL5' 1 d_SIMULATION ;...

%   Simulation parameters (single segments)
%   NOTE! These parameters are stored in an array of structures,
%   piStarControl.segStruct(n ).fieldName, for n segments, in which
%   the field name is defined in this cell array.
%   n = piStartControl.simSegmentCount
%   This compares with the usual piStartControl.fieldName for other
%   parameters.
%   Note! When adding new parameters, update the structure initialization
%   further below.
                     'simSegNameStr'     'simSegName'        0 d_SIMSEGMENT; ...
                  'simSegDescriptionStr' 'simSegDescription' 0 d_SIMSEGMENT; ...
                     'simHeading'        'simHeading'        1 d_SIMSEGMENT ;...
                     'simAcceleration'   'simAcceleration'   1 d_SIMSEGMENT ;...
                     'simFinalSpeed'     'simFinalSpeed'     1 d_SIMSEGMENT ;...
                     'simHoldTime'       'simHoldTime'       1 d_SIMSEGMENT ;...
                  'simHgtDynamicTypeStr' 'simHgtDynamicType' 0 d_SIMSEGMENT ;...
                     'simHgtDynamicMag'  'simHgtDynamicMag'  1 d_SIMSEGMENT ;...
                     'simHgtDynamicFreq' 'simHgtDynamicFreq' 1 d_SIMSEGMENT ;...
                     'simHgtDynamicEnd'  'simHgtDynamicEnd'  2 d_SIMSEGMENT } ;

multipliersLoadedFlags      = 0 ;
ecefPositionLoadedFlags     = 0 ;
geodeticPositionLoadedFlags = 0 ;
baselineVectorLoadedFlags   = 0 ;


%%%%%%%%%% Check input arguments %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if nargin >= 1 & ~isempty( startPiHandle )
  % Uing a GUI, startPiHandle is available.
    guiEnabled = 1 ;
else
  guiEnabled = 0 ;
end

% Checked next as values used when checking the second argument.
if nargin < 4 | isempty( parseDatabase )
  parseDatabase = FALSE ;
end
if nargin < 5 | isempty( loadDatabase )
  loadDatabase = FALSE ;
end

if nargin >= 2 & ~isempty( newPiStarControl )
  piStarControl = newPiStarControl ;  % Instead of default values.

  if parseDatabase | loadDatabase
  % If parsing or loading from the data base, then newPiStarControl is
  % not empty, but the .ini is not being read or updated.
    updateIniFile = 0 ;
  else
    updateIniFile = 1 ;
  end

  if loadDatabase
    if databaseFileType == d_BASELINE_FILE
    % Default certain values that should not retain previous values.
      piStarControl.baselineLength   = [] ;
      piStarControl.localTimeOffset  = [] ;
      piStarControl.baseFileNameStr  = [] ;  % May be loaded via the GUI.
      piStarControl.roverFileNameStr = [] ;
      piStarControl.ecefPositionValid = 0 ;
      % When set, computed x,y,z also valid.
      piStarControl.geodeticPositionValid = 0 ;
      piStarControl.baselineVectorValid   = 0 ;
      piStarControl.dataFileNamesValid    = 0 ;
      piStarControl.piLineValid           = 0 ;
      piStarControl.baselineNameStr = [] ;
      piStarControl.descriptionStr = [] ;
      piStarControl.loadStartTime = [] ;
      piStarControl.loadStopTime = [] ;

    elseif databaseFileType == d_SIMULATION_FILE
    % Simulation scenario file.
    
      % Init system parameters (not selected by the user).
      % It would be possible to use,
      % piStarControl.segStruct = struct( [] ) ;
      % and the loading would work correctly (empty values added for
      % segments that did not contain them). However, if a parameter is
      % not available for *all* segments, then the field would not be
      % created. This would require repeated use of isfield() in the
      % scenario interpreter. Also, definiting the structure makes for
      % more efficient loading (when a new parameter appears in later
      % segments) as the entire structure does not need to be
      % redimensioned.
      piStarControl.segStruct = struct( ...
        'simSegNameStr', [],        'simSegDescriptionStr', [], ...
        'simHeading', [],           'simAcceleration', [], ...
        'simFinalSpeed', [],        'simHoldTime', [], ...
        'simHgtDynamicTypeStr', [], 'simHgtDynamicMag', [], ...
        'simHgtDynamicFreq', [],    'simHgtDynamicEnd', [] ) ;

      piStarControl.simSegmentCount = 0 ;  % # of segments.
      piStarControl.simSelectedSegment = [] ; % Selected seg from the GUI.

      % General simulation parameters (selected by the user).
      % Default values are set prior to running the scenario.
      piStarControl.simPositionFileStr = [] ;
      piStarControl.simEphemerisFileStr = [] ;
      piStarControl.simBaseFileStr = [] ;
      piStarControl.simRoverFileStr = [] ;
      piStarControl.simNameStr = [] ;
      piStarControl.simDescriptionStr = [] ;
      piStarControl.simStartTime = [] ;
      piStarControl.simEpochRate = [] ;
      piStarControl.simSnapToEpoch = [] ;
      piStarControl.simStartSpeed = [] ;
      piStarControl.simBasePositionLat = [] ;
      piStarControl.simBasePositionLon = [] ;
      piStarControl.simBasePositionHgt = [] ;
      piStarControl.simRoverPositionLat = [] ;
      piStarControl.simRoverPositionLon = [] ;
      piStarControl.simRoverPositionHgt = [] ;
      piStarControl.simBaseAntennaType = [] ;
      piStarControl.simRoverAntennaType = [] ;
      piStarControl.simBaseClockOffset = [] ;
      piStarControl.simBaseClockRate = [] ;
      piStarControl.simRoverClockOffset = [] ;
      piStarControl.simRoverClockRate = [] ;
      piStarControl.simElevationMask = [] ;
      piStarControl.simNoiseSeed       = 0.0 ;
      piStarControl.simCodeNoiseBaseL1 = 0.0 ;
      piStarControl.simCodeNoiseBaseL2 = 0.0 ;
      piStarControl.simCodeNoiseBaseL5 = 0.0 ;
      piStarControl.simCodeNoiseRoverL1 = 0.0 ;
      piStarControl.simCodeNoiseRoverL2 = 0.0 ;
      piStarControl.simCodeNoiseRoverL5 = 0.0 ;
      piStarControl.simPhaseNoiseBaseL1 = 0.0 ;
      piStarControl.simPhaseNoiseBaseL2 = 0.0 ;
      piStarControl.simPhaseNoiseBaseL5 = 0.0 ;
      piStarControl.simPhaseNoiseRoverL1 = 0.0 ;
      piStarControl.simPhaseNoiseRoverL2 = 0.0 ;
      piStarControl.simPhaseNoiseRoverL5 = 0.0 ;
      piStarControl.simCodeMultipathBaseL1 = 0.0 ;
      piStarControl.simCodeMultipathBaseL2 = 0.0 ;
      piStarControl.simCodeMultipathBaseL5 = 0.0 ;
      piStarControl.simCodeMultipathRoverL1 = 0.0 ;
      piStarControl.simCodeMultipathRoverL2 = 0.0 ;
      piStarControl.simCodeMultipathRoverL5 = 0.0 ;
      piStarControl.simPhaseMultipathBaseL1 = 0.0 ;
      piStarControl.simPhaseMultipathBaseL2 = 0.0 ;
      piStarControl.simPhaseMultipathBaseL5 = 0.0 ;
      piStarControl.simPhaseMultipathRoverL1 = 0.0 ;
      piStarControl.simPhaseMultipathRoverL2 = 0.0 ;
      piStarControl.simPhaseMultipathRoverL5 = 0.0 ;
      piStarControl.simCodeMultipathCorrBaseL1 = 0.0 ;
      piStarControl.simCodeMultipathCorrBaseL2 = 0.0 ;
      piStarControl.simCodeMultipathCorrBaseL5 = 0.0 ;
      piStarControl.simCodeMultipathCorrRoverL1 = 0.0 ;
      piStarControl.simCodeMultipathCorrRoverL2 = 0.0 ;
      piStarControl.simCodeMultipathCorrRoverL5 = 0.0 ;
      piStarControl.simPhaseMultipathCorrBaseL1 = 0.0 ;
      piStarControl.simPhaseMultipathCorrBaseL2 = 0.0 ;
      piStarControl.simPhaseMultipathCorrBaseL5 = 0.0 ;
      piStarControl.simPhaseMultipathCorrRoverL1 = 0.0 ;
      piStarControl.simPhaseMultipathCorrRoverL2 = 0.0 ;
      piStarControl.simPhaseMultipathCorrRoverL5 = 0.0 ;
    end
  end
else
  updateIniFile = 0 ;

  % Initial piStarControl structure to defaults.

  % No longer clear entire structure as simulation parameters are not
  % default in this section.
  %piStarControl = [] ;  % Clear structure for control parameters.
  piStarControl.multipliersValid      = 0 ;  % Defaults to invalid.
  piStarControl.ecefPositionValid     = 0 ;
  % When set, computed x,y,z also valid.
  piStarControl.geodeticPositionValid = 0 ;
  piStarControl.baselineVectorValid   = 0 ;
  piStarControl.dataFileNamesValid    = 0 ;
  piStarControl.piLineValid           = 0 ;

  piStarControl.baseAntennaType  = [] ;  % PiLine processing values.
  piStarControl.roverAntennaType = [] ;
  piStarControl.baseFileNameStr  = [] ;  % May be loaded via the GUI.
  piStarControl.roverFileNameStr = [] ;
  piStarControl.localTimeOffset  = [] ;
  piStarControl.loadStartTime = [] ;
  piStarControl.loadStopTime = [] ;

  % Set default values for rkwin
  %   piStarControl.rtkBackTrack        = []
  %   piStarControl.rtkHorizTolerance   = 0.12
  %   piStarControl.rtkVertTolerance    = 0.22
  %   piStarControl.rtkAdaptiveTolerance = FALSE
  %   piStarControl.rtkHorizOffset      = 0.01
  %   piStarControl.rtkVertOffset       = 0.02
  %   piStarControl.rtkHorizPPM         = 0.5 
  %   piStarControl.rtkVertPPM          = 1.2
  %   piStarControl.rtkToleranceMult    = 4.5
  %   piStarControl.rtkElevation        = 13
  %   piStarControl.rtkVRSBaseline      = []
  %   piStarControl.rtkTestMode         = 1
  %   piStarControl.rtkBIDTimeOut       = 3600
  %   piStarControl.rtkWeighting        = 4
  %   piStarControl.rtkSVRejection      = []
  %   piStarControl.rtkFloatAveraging   = []
  %   piStarControl.rtkSearchProbThreshold = []
  %   piStarControl.rtkIonoModel        = []
  %   piStarControl.rtkIonoPPM          = []
  %   piStarControl.rtkIonoScaleFactor  = []
  %   piStarControl.rtkDisableTropo     = FALSE 
  %   piStarControl.rtkDisableIono      = FALSE 
  %   piStarControl.rtkBaseAntennaType  = 0
  %   piStarControl.rtkRoverAntennaType = 0
  %   piStarControl.rtkRKwinFileName    = 'rkwin.exe'
  %   piStarControl.rtkPlotNameSuffix   = []
  %   piStarControl.rtkPositionType = []
  %   piStarControl.rtkDualFreqOnly = TRUE
  %   piStarControl.rtkCustomFlagsStr []

  piStarControl.rtkBackTrack = [] ;
  piStarControl.rtkHorizTolerance = 0.12 ;
  piStarControl.rtkVertTolerance = 0.22 ;
  piStarControl.rtkAdaptiveTolerance = FALSE ;
  piStarControl.rtkHorizOffset = 0.01 ;
  piStarControl.rtkVertOffset = 0.02 ;
  piStarControl.rtkHorizPPM = 0.5 ;
  piStarControl.rtkVertPPM  = 1.2 ;
  piStarControl.rtkToleranceMult = 4.5 ;
  piStarControl.rtkElevation = 13 ;
  piStarControl.rtkVRSBaseline = [] ;
  piStarControl.rtkTestMode  = 1 ;
  piStarControl.rtkBIDTimeOut = 3600 ;
  piStarControl.rtkWeighting = 4 ;
  piStarControl.rtkSVRejection = [] ;
  piStarControl.rtkFloatAveraging  = [] ;
  piStarControl.rtkSearchProbThreshold = 99.9 ;
  piStarControl.rtkIonoModel = [] ;
  piStarControl.rtkIonoPPM   = [] ;
  piStarControl.rtkIonoScaleFactor = [] ;
  piStarControl.rtkDisableTropo = FALSE ;
  piStarControl.rtkDisableIono  = FALSE ;
  piStarControl.rtkBaseAntennaType  = 0 ;  % Usually the same as PiLine.
  piStarControl.rtkRoverAntennaType = 0 ;
  piStarControl.rtkRKwinFileName    = [] ;
  piStarControl.rtkPlotNameSuffix   = [] ;
  piStarControl.rtkEastOffset = [] ;
  piStarControl.rtkNorthOffset = [] ;
  piStarControl.rtkUpOffset = [] ;
  piStarControl.rtkPositionType = [] ;
  piStarControl.rtkDualFreqOnly = TRUE ;
  piStarControl.rtkCustomFlagsStr = [] ;

  % Set default values for PiPro. Now set by PiPro.
  %
  % piStarControl.piProCodeAxis  = 5
  % piStarControl.piProPhaseAxis = 1000
  % piStarControl.piProSavePlots = TRUE
  % piStarControl.piProFileName  = 'load_pi.exe'
  % piStarControl.piProEnableFFT = FALSE
  % piStarControl.piProEnableACF = FALSE
  % piStarControl.piProQuickMode = 0
  % piStarControl.piProCNRElevMask = []
  % piStarControl.piProSigmaMask = []

  piStarControl.piProCodeAxis  = [] ;
  piStarControl.piProPhaseAxis = [] ;
  piStarControl.piProSavePlots = TRUE ;
  piStarControl.piProFileName  = 'load_pi.exe' ;
  piStarControl.piProEnableFFT = FALSE ;
  piStarControl.piProEnableACF = FALSE ;
  piStarControl.piProQuickMode = [] ;
  piStarControl.piProCNRElevMask = [] ;
  piStarControl.piProSigmaMask   = [] ;
  piStarControl.piProSkipCNRTests = FALSE ;
  piStarControl.piProOmitLegend = FALSE ;

  % Set defaults for database management.
  % Strings below used to set databaseFileNameCell after loading.
  piStarControl.databaseListCell = {} ;
  piStarControl.databaseNameCell = {} ;
  piStarControl.selectedDatabase = [] ;
  piStarControl.databasePathPrefixCell = {} ;
  piStarControl.cacheDirectoryStr = [] ;
  piStarControl.baselineNameStr = [] ;
  piStarControl.descriptionStr = [] ;

  % Simulation parameters.
  piStarControl.simScenarioFileStr = [] ;
  piStarControl.simPositionFileEnabled = 0 ;  % Simulated positions output.

  % Note: 'baselineLength' can be provided in a special piStar.ini file
  % generated by the regression system (to support BID diagnostics).
  % Otherwise (usual case), it is computed.
  piStarControl.baselineLength   = [] ;
end

if nargin < 3
  piStarControlFields = [] ;
end

if nargin >= 6 & ~isempty( databaseFileType )
  databaseDelimiterStr = databaseDelimiterCellStr{ databaseFileType } ;
end


if updateIniFile
% When updating the ini file, it is possible for a swap from geodetic to
% xyz coordinates (or visa versa) to occur. It is illegal for both to be
% present, so the old type must be deleted.  This is achieved by setting
% the values to NaN, which is a special (and only) case which deletes
% lines from the ini file.
 if any( strcmp( piStarControlFields, 'basePositionX' ) )
   piStarControl.basePositionLat = NaN ;
   piStarControl.basePositionLon = NaN ;
   piStarControl.basePositionHgt = NaN ;
   piStarControl.roverPositionLat = NaN ;
   piStarControl.roverPositionLon = NaN ;
   piStarControl.roverPositionHgt = NaN ;
   piStarControl.baselineVectorX = NaN ;
   piStarControl.baselineVectorY = NaN ;
   piStarControl.baselineVectorZ = NaN ;
 elseif any( strcmp( piStarControlFields, 'basePositionLat' ) )
   piStarControl.basePositionX = NaN ;
   piStarControl.basePositionY = NaN ;
   piStarControl.basePositionZ = NaN ;
   piStarControl.roverPositionX = NaN ;
   piStarControl.roverPositionY = NaN ;
   piStarControl.roverPositionZ = NaN ;
   piStarControl.baselineVectorX = NaN ;
   piStarControl.baselineVectorY = NaN ;
   piStarControl.baselineVectorZ = NaN ;
 end

 % Clear previous values. For example, database load may have set ecef
 % flag, while current ini file still contains geodetic (will now be
 % removed, but first sets geodetic flag). Prevents both flags set which
 % triggers a warning message. Note, these flags are not useful when
 % updating the ini flag (set based on the original ini file, not the
 % updated one).
 piStarControl.ecefPositionValid = 0 ;
 piStarControl.geodeticPositionValid = 0 ;
end


% Prepare to write message to the Status Box.
% First set up handles to the Status Text Box in the Startup GUI.
% Search down from the passed figure handle.
if guiEnabled
  statusBoxHandle  = findobj( startPiHandle, 'Tag', 'statusBox' ) ;
  % Note: the font style is not set here using
  %   set( statusBoxHandle, 'FontName', 'courier' ) ;
  % because this would change the current text in the status box which
  % would be visible while the .ini file is being parsed (if no other
  % message is posted). It is set when needed.
end


% Open piStar.ini file and parse processing parameters.

error = 1 ;  % Default to error set.
httpFile = logical( 0 ) ;

if loadDatabase & ( databaseFileType == d_SIMULATION_FILE )
% Reading simulation scenario file.
  if isempty( piStarControl.simScenarioFileStr )
    set( statusBoxHandle, 'FontName', 'courier', 'String', ...
         sprintf( [ 'WARNING!\nsimScenarioFile not specified\n' ...
                    'in file ' iniFileNameStr ] ) ) ;
    return ;
  end
  fid = fopen( piStarControl.simScenarioFileStr, 'r' ) ;

  if fid == -1  % Could not open file to read.
    set( statusBoxHandle, 'FontName', 'courier', 'String', ...
         [ '!! Cannot open file ' piStarControl.simScenarioFileStr ...
           ' to read !!' ] )
    return ;
  end

elseif parseDatabase | loadDatabase
  if isempty( piStarControl.databaseListCell )
    set( statusBoxHandle, 'FontName', 'courier', 'String', ...
         sprintf( [ 'WARNING!\ndatabaseListFile not specified\n' ...
                    'in file ' iniFileNameStr ] ) ) ;
    return ;
  end

  % Check if http file.
  databaseListStr = piStarControl.databaseListCell{ ...
                            piStarControl.selectedDatabase } ;
  if strcmp( databaseListStr( 1: 7 ), 'http:\\' )
  % Convert from DOS to UNIX slashes.

    [ path, name, ext ] = fileparts( databaseListStr ) ;
    set( statusBoxHandle, 'FontName', 'courier', 'String', ...
         sprintf( 'Tranferring http file: %s', [ name ext ] ) ) ;

    databaseListStr( findstr( '\', databaseListStr ) ) = '/' ;
    dos( [ 'wget -O ' d_HTTP_TMP_FILE_STR ' "' databaseListStr '"' ] ) ;

    % Check if the transfer was successful.
    % The temp file is always created, but may have zero size.
    dirStruct = dir( d_HTTP_TMP_FILE_STR ) ;
    if dirStruct.bytes == 0
      dos( [ 'del ' d_HTTP_TMP_FILE_STR ] ) ;  % Remove the empty file.
      fid = -1 ;  % Similar to 'cannot open to read local file' case below.
    else
      fid = fopen( d_HTTP_TMP_FILE_STR, 'r' ) ;  % Local file.
    end
    httpFile = logical( 1 ) ;
  else
    fid = fopen( databaseListStr, 'r' ) ;  % Local file.
  end

  if fid == -1  % Could not open file to read.
    set( statusBoxHandle, 'FontName', 'courier', 'String', ...
         sprintf( '!! Cannot open file %s \nto read !!', databaseListStr ) ) ;
    return ;
  end

else
  %MTA
  %if exist( iniFileNameStr, 'file' ) == 2
  if 1
  %MTA
    % iniFileNameStr = which( iniFileNameStr ) ;  % Add full path.
    fid = fopen( iniFileNameStr, 'r' ) ;
  else
    fid = -1 ;
  end

  if fid == -1  % Could not open file to read.
    set( statusBoxHandle, 'FontName', 'courier', 'String', ...
         [ '!! Cannot open file ' iniFileNameStr ' to read !!' ] )
    return ;
  end
end


if updateIniFile
% Open NEWpiStar.ini temporary file.
  newFid = fopen( newIniFileNameStr, 'w' ) ;

  if newFid == -1  % Could not open file to write.
    set( statusBoxHandle, 'FontName', 'courier', 'String', ...
         [ '!! Cannot open file ' newIniFileNameStr ' to write !!' ] )
    return ;
  end
else
  newFid = [] ;
end


%%%%%%%%%% Loop for all input lines until end of file %%%%%%%%%%%%%%%%%%%%%%%%%%
invalidControlStr = [] ;
delimiterStr = [] ;
newDelimiter = FALSE ;
parsingBlock = FALSE ;
loadBlock = FALSE ;
blockCountBaseline   = 0 ;  % Block count for a specific block type.
piStarControl.database.baselineNameCellArray = {} ;  % Clear last load.
blockCount = 0 ;
piStarControl.database.maxBaselineNameLength = 0 ;  % Used for GUI formatting.

while 1 
  lineStr = fgetl( fid ) ;
  if ~ischar( lineStr )  % End of file.
    break ;
  end

  % Comments lines starting with the following strings are ignored:
  % ';'  '#'  '%'  '//'
  % '[' indicates a special limiter (saved).
  if ( length( lineStr) == 0 ) | ( lineStr( 1 ) == ';' ) | ...
     ( lineStr( 1 ) == '#' ) | ( lineStr( 1 ) == '%' ) | ...
     ( lineStr( 1 ) == '[' ) | ...
     ( ( length( lineStr ) >= 2 & ...
       ( lineStr( 1 ) == '/' ) & lineStr( 2 ) == '/' ) )

    if updateIniFile
      fprintf( newFid, '%s\n', lineStr ) ;
    end

    if ( length( lineStr ) > 0 ) & ( lineStr( 1 ) == '[' )
    % Special delimiter. Remove '[' and chars after and include a ']'
      delimiterStr = sscanf( lineStr( 2 : end ), '%c' ) ;
      bracketIndexVec = findstr( delimiterStr, ']' ) ;
      delimiterStr( bracketIndexVec( 1 ):end ) = [] ;
      newDelimiter = TRUE ;
    end
    continue ;
  end

  % Check if line comprises only spaces and tabs. Ignore these lines.
  testStr = lineStr ;
  testStr( findstr( spaceChar, testStr ) ) = [] ;  % Remove spaces.
  testStr( findstr( tabChar, testStr ) ) = [] ;    % Remove tabs.
  if isempty( testStr )
    if updateIniFile  % Replace with just a blank line.
      fprintf( newFid, '\n' ) ;
    end
    continue ;
  end

  % Obtain position of = char, and check for illegal line formats.
  equalCharIndexVec = findstr( '=', lineStr ) ;
  if isempty( equalCharIndexVec )
    set( statusBoxHandle, 'FontName', 'courier', 'String', ...
         sprintf( [ 'WARNING!\nFile ' iniShortNameStr ...
                    ' contains line without = char\n' lineStr ] ) ) ;
    return ;
  elseif length( equalCharIndexVec ) > 1
    set( statusBoxHandle, 'FontName', 'courier', 'String', ...
         sprintf( [ 'WARNING!\nFile ' iniShortNameStr ...
                    ' contains line with multiple = chars\n' lineStr ]));
    return ;
  end
  if equalCharIndexVec == 1   % Line cannot start with the '=' char.
    set( statusBoxHandle, 'FontName', 'courier', 'String', ...
         sprintf( [ 'WARNING!\nFile ' iniShortNameStr ...
                    ' contains line starting with = char\n' lineStr ]));
    return ;
  end
  
  % Value occurs after the '=' char and must exist.

  % Leading spaces are ignored by the sscanf. Additional strings
  % (comments) are ignored.
  valueStr = sscanf( lineStr( equalCharIndexVec + 1 : end ), '%s', 1 ) ;

  if valueStr( 1 ) == '"'
  % Started with double-quote. Assume a file name that may contain
  % spaces. The scan above terminates at the first space, so a character
  % scan is required. Then remove chars up to and including the first "
  % and all chars after and including the second ".
    valueStr = sscanf( lineStr( equalCharIndexVec + 1 : end ), '%c' ) ;
    doubleQuoteIndexVec = findstr( valueStr, '"' ) ;
    valueStr( [ 1:doubleQuoteIndexVec( 1 ) doubleQuoteIndexVec( 2 ):end ] ) =[];
  end
 

  if isempty( valueStr )
    set( statusBoxHandle, 'FontName', 'courier', 'String', ...
         sprintf( [ 'WARNING!\nFile ' iniShortNameStr ...
                    ' contains empty value after = char\n' lineStr ]));
    return ;
  end


  % Obtain the control string, the first parameter on the line.
  controlStr = lineStr( 1 : equalCharIndexVec - 1 ) ;
  % Remove any leading spaces of trailing spaces (before the '=' char).
  controlStr = controlStr( controlStr ~= ' ' ) ;


  %%%%%%%%%% Database file processing %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  if loadDatabase
  % Parsing and loading database or simulation file.
  % When loading a simulation file: All general paramters and segments
  % (blocks) are loaded and processing always drops through to allow
  % loading into the piStartControl structure.
  % When loading a database: Must find the specific delimiter
  % (block type) and block number. Once found, processing drops through
  % to allow loading into the piStarControl structure. Otherwise a
  % 'continue' for the for loop for the next line of the .ini file.
    if newDelimiter
      loadBlock = FALSE ;  % Initialize sync to required block.

      if strcmp( delimiterStr, databaseDelimiterStr )
        blockCount = blockCount + 1 ;

        if blockCount == databaseBlockCount
          loadBlock = TRUE ;
        end
      end
      newDelimiter = FALSE ;  % Won't trigger until next delimiter.
    end

    if ~loadBlock & databaseBlockCount ~= 0
    % Continue for loops, to next line of .ini file. To load all
    % simulation parameters (including blocks), databaseBlockCount = 0.
      continue ;
    end
    % Else: fall through to decode parameter and load piStarControl.

  elseif parseDatabase
  % Just parsing data base for the UI. Specific parameters are loaded
  % into the structure piStarControl.Database, but no parameters are
  % loaded directly into piStarControl. Note the 'continue' statement
  % for the main for loop (per line of .ini file).

    if newDelimiter
    % Parsed a new [delimiter] given in brackets.
      if parsingBlock == FALSE
      % Not currently parsing a block from a previous delimiter.
        parsingBlock = TRUE ;
      else
      % Got another delimiter before decoding the previous block has
      % finished, i.e. some required parameters were missing.
        set( statusBoxHandle, 'FontName', 'courier', 'String', ...
             sprintf( [ 'WARNING!\nDelimiter [' delimiterStr ...
                        '] occurred after incomplete block' ] ) ) ;
        return ;
      end
    end

    if ~isempty( delimiterStr )

      switch delimiterStr
        case databaseDelimiterCellStr{ 1 }  % Baseline information.
          if newDelimiter  % Increment counter for specific block type.
            blockCountBaseline = blockCountBaseline + 1 ;
            newDelimiter = FALSE ;
          end

          switch controlStr
            case 'baselineName'
              piStarControl.database.baselineNameCellArray( ...
                      blockCountBaseline ) = { valueStr } ;
              % Used for GUI formatting.
              piStarControl.database.maxBaselineNameLength = ...
                      max( [ piStarControl.database.maxBaselineNameLength ...
                             length( valueStr ) ] ) ;

              % Got all mandatory parameters. OK to receiver another
              % delimiter. However, other redundant parameters may occur
              % first.
              parsingBlock = FALSE ;

            case 'description'
              piStarControl.database.descriptionNameCellArray( ...
                      blockCountBaseline ) = { valueStr } ;
          end  % of switch controlStr

        case 'End'
        % Usually redundant as one block follows another. However, can
        % be used to prevent further parsing of a block, and leaving
        % parameters in a miscellaneous block.
          % No parmeters are needed, so OK to receive another delimiter.
          parsingBlock = FALSE ;

        otherwise
          set( statusBoxHandle, 'FontName', 'courier', 'String', ...
               sprintf( [ 'WARNING!\nUnknown Delimiter [' delimiterStr ']']));
          return ;

      end  % of switch delimiterStr

      continue ;  % For loop for each line of .ini file.

    end  % end of if for delimiterStr not empty.
  end
  %%%%%%%%%% End of database file processing %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


  % Get the name of the field in the piStarControl structure, fieldStr,
  % which corresponds to the name of the control parameter in the .ini
  % file, controlStr. First, match the controlStr in the 2nd column
  % using the strcmp(), which returns a logical vector (with just a
  % single unity value). Use this to select the corrresponding fieldStr
  % from the 1st column on the same row, and the valueType from the 3rd
  % column.
  cellRowIndex = find( strcmp( controlStr, controlCellArray( :, 2 ) ) ) ;

  if ~isempty( cellRowIndex )

    fieldStr      = controlCellArray{ cellRowIndex, 1 } ;
    valueType     = controlCellArray{ cellRowIndex, 3 } ;
    valueCatagory = controlCellArray{ cellRowIndex, 4 } ;

    % Convert control string from .ini file to control value dependent
    % on value type. Or, if updating the .ini file, append to a
    % temporary new .ini file (control value unchanged).
    if ~updateIniFile
      controlValue = loadValue( [], valueStr, valueType ) ;

      % Load piStarControl structure.
      if valueCatagory == d_SIMSEGMENT  % Simulation file segment.
      % Parameters are loaded into a sub-structure array with array
      % index = blockCount.
        if blockCount ~= 0  % Must have sync'ed to first segment (block).
          piStarControl.segStruct = ...
              setfield( piStarControl.segStruct, { blockCount }, ...
                        fieldStr, controlValue ) ;
          piStarControl.simSegmentCount = blockCount ;  % # of segments.
        end
      elseif valueType == 6  % Cell array of strings.
        piStarControl = ...
          setfield( piStarControl, fieldStr, ...
                    [ getfield( piStarControl, fieldStr ) { controlValue } ] ) ;
      else
        piStarControl = setfield( piStarControl, fieldStr, controlValue ) ;
      end

    elseif valueType == 6  % Update .ini file. Cell array of strings.
    % Cell arrays result in multiple lines being written to the .ini
    % file (the entire cell array contents). Further instances of the
    % same field string must then be ignored, so the cell array in
    % piStarControl is cleared. This mechanism is possible because
    % piStarControl is not returned when updating the .ini file.

      cellStr = getfield( piStarControl, fieldStr ) ;
      if ~isempty( cellStr )
      % Typically the number of values in the array will match the
      % number of parameters in the .ini file. However, the .ini has
      % been manually appended, we may 'run out' of array values.
      % Thus, must check for empty. (Note: extra parameters appended
      % to the .ini file after its read by the UI will be deleted).
        loadValue( controlStr, [], valueType, cellStr{ 1 }, newFid ) ;
        % Effectively 'left shift' the cell array, and save.
        cellStr( 1 ) = [] ;
        piStarControl = setfield( piStarControl, fieldStr, cellStr ) ;
      end
    else  % Update .ini file. Regular parameter.
      loadValue( controlStr, [], valueType, ...
                 getfield( piStarControl, fieldStr ), newFid ) ;
    end

    % Delete names of fields in the cell array of fields updated via the
    % GUI. As they are already in the .ini file, they do not need to be
    % written separately (below, after .ini parsing complete).
    % (If loading from the data base, then this clears out any entry
    % added via the GUI, and a new entry is appended below).
    piStarControlFields( strcmp( piStarControlFields, fieldStr ) ) = [] ;

    if loadDatabase
    % !!!TA we don't want to this when loading a simulator file!!!
    %
    % Similar to when controls are updated via the GUI, add an entry to
    % the cell array of control fields that is later used when the .ini
    % file is updated (if 'apply' is clicked). For this case, the cell
    % array is returned by this function.
      piStarControlFields =  [ piStarControlFields { fieldStr } ] ;

      if valueType == 5 & ...
         ~isempty( piStarControl.databasePathPrefixCell{ ...
                     piStarControl.selectedDatabase } )
      % File name string that may require a path prefix. Update initial
      % value loaded above into piStarControl structure.
        piStarControl = ...
          setfield( piStarControl, fieldStr, ...
                    [ piStarControl.databasePathPrefixCell{ ...
                          piStarControl.selectedDatabase } controlValue ] ) ;
      end
    end

  else
    invalidControlStr = controlStr ;
  end

  switch controlStr
  % Set flags for parameters that have to be loaded as a set, to check
  % that the set is complete. Also, some parameters require special
  % handling.
    % PiLine parameters
    case 'basePositionX'
      ecefPositionLoadedFlags = bitset( ecefPositionLoadedFlags, 1 ) ;

    case 'basePositionY'
      ecefPositionLoadedFlags = bitset( ecefPositionLoadedFlags, 2 ) ;

    case 'basePositionZ'
      ecefPositionLoadedFlags = bitset( ecefPositionLoadedFlags, 3 ) ;

    case 'roverPositionX'
      ecefPositionLoadedFlags = bitset( ecefPositionLoadedFlags, 4 ) ;

    case 'roverPositionY'
      ecefPositionLoadedFlags = bitset( ecefPositionLoadedFlags, 5 ) ;

    case 'roverPositionZ'
      ecefPositionLoadedFlags = bitset( ecefPositionLoadedFlags, 6 ) ;

    case 'basePositionLat'
      geodeticPositionLoadedFlags = bitset( geodeticPositionLoadedFlags, 1 ) ;

    case 'basePositionLon'
      geodeticPositionLoadedFlags = bitset( geodeticPositionLoadedFlags, 2 ) ;

    case 'basePositionHgt'
      geodeticPositionLoadedFlags = bitset( geodeticPositionLoadedFlags, 3 ) ;

    case 'roverPositionLat'
      geodeticPositionLoadedFlags = bitset( geodeticPositionLoadedFlags, 4 ) ;

    case 'roverPositionLon'
      geodeticPositionLoadedFlags = bitset( geodeticPositionLoadedFlags, 5 ) ;

    case 'roverPositionHgt'
      geodeticPositionLoadedFlags = bitset( geodeticPositionLoadedFlags, 6 ) ;

    case 'baselineVectorX'
      baselineVectorLoadedFlags = bitset( baselineVectorLoadedFlags, 1 ) ;

    case 'baselineVectorY'
      baselineVectorLoadedFlags = bitset( baselineVectorLoadedFlags, 2 ) ;

    case 'baselineVectorZ'
      baselineVectorLoadedFlags = bitset( baselineVectorLoadedFlags, 3 ) ;

    case 'baseAntennaType'
      % Set rkwin value to the PiLine value.
      piStarControl.rtkBaseAntennaType = piStarControl.baseAntennaType ;

    case 'roverAntennaType'
      % Set rkwin value to the PiLine value.
      piStarControl.rtkRoverAntennaType = piStarControl.roverAntennaType ;

    % PiStar parameters
    case 'phaseMultiplierL1'
      multipliersLoadedFlags = bitset( multipliersLoadedFlags, 1 ) ;

    case 'phaseMultiplierL2'
      multipliersLoadedFlags = bitset( multipliersLoadedFlags, 2 ) ;

    case 'rangeMultiplierL1'
      multipliersLoadedFlags = bitset( multipliersLoadedFlags, 3 ) ;

    case 'rangeMultiplierL2'
      multipliersLoadedFlags = bitset( multipliersLoadedFlags, 4 ) ;

    case 'rtkPlotNameSuffix'
      % Remove illegal characters.
      piStarControl.rtkPlotNameSuffix( ...
        findstr( '\', piStarControl.rtkPlotNameSuffix ) ) = [] ;
      piStarControl.rtkPlotNameSuffix( ...
        findstr( '*', piStarControl.rtkPlotNameSuffix ) ) = [] ;
      
  end  % Of switch.

end  % Of while loop for all input lines in the .ini file.

fclose( fid ) ;  % Close .ini file.
if httpFile
% Can remove the temp database list file here. However, it may be
% useful, and there is no other method to transfer this.
  %dos( [ 'del ' d_HTTP_TMP_FILE_STR ] ) ;
end


% Set any defaults when loading from a database. Typically, parameters
% not specified in the database are not updated. However, there are
% exceptions:
% The rtkIonoScaleFactor is used with special value 255 for SAPOS, which
% also sets absolute antenna model. It must be default to empty
% (non-SAPOS; relative model).
if loadDatabase
  if ~strcmp( piStarControlFields, 'rtkIonoScaleFactor' )
  % Not specified in the database.
    piStarControl.rtkIonoScaleFactor = [] ;
  end
end

if updateIniFile & ~isempty( piStarControlFields )
% Updating the .ini file (clicked on "Apply"), and names of updated
% fields in the piStarControl structure are available in the cell array
% of strings, piStarControlFields (loaded by the GUI callback). These
% fields did not have corresponding control values in the .ini file when
% parsed above (which would delete any entry in the list
% piStarControlFields), i.e. default values were first used. Therefore,
% the .ini file must be appended with the new values from the GUI.

  writeHeader = 1 ;
  for index = 1:length( piStarControlFields )
    % Loop for the names of the field in the piStarControl structure
    % which were updated by the GUI. This is likely to be a short list.
    fieldStr = piStarControlFields{ index } ;

    % Get the name of the control parameter, iniControlStr, used in
    % the .ini file from the cell array. First, find the fieldStr in the
    % 1st column using the strcmp(), which returns a logical vector
    % (with just a single unity value). Use this to select the
    % corrresponding iniControlStr from the 2nd column on the same row,
    % and the valueType from the 3rd column.
    cellRowIndex = find( strcmp( fieldStr, controlCellArray( :, 1 ) ) ) ;
    iniControlStr = controlCellArray{ cellRowIndex, 2 } ;
    valueType     = controlCellArray{ cellRowIndex, 3 } ;

    if writeHeader  % Format defined at head of this file.
      utilityType = controlCellArray{ cellRowIndex, 4 } ;
      timeVec = clock ;  % Current time [year month day hour min sec ].
      fprintf( newFid, headerFormatStr, utilityNameCellStr{ utilityType }, ...
                       date, timeVec(4), timeVec( 5 ) ) ;
      writeHeader = 0 ;  % Write just the once.
    end

    % Write new line to the .ini file.
    loadValue( iniControlStr, [], valueType, ...
               getfield( piStarControl,  fieldStr ),  newFid ) ;
  end
end

if updateIniFile
  fclose( newFid) ;

  % Update the ini file from the new version.
  dos( [ 'del ' iniFileNameStr ] ) ;
  dos( [ 'move ' newIniFileNameStr ' ' iniFileNameStr ] ) ;
end


% Set 'pointer' to the selected database.
if isempty( piStarControl.selectedDatabase ) | ...
   piStarControl.selectedDatabase > length( piStarControl.databaseListCell )|...
   piStarControl.selectedDatabase < 1
% Invalid entry found. Set to first specified database (if available).
  if isempty( piStarControl.databaseListCell )
    piStarControl.selectedDatabase = [] ;
  else
    piStarControl.selectedDatabase = 1 ;
  end
end
% If no database list file was given, piStarControl.selectedDatabase = [] and
% piStarControl.databaseListCell = [].

% Set default database names if not provided. Fill with max allowable,
% as they all appear the the pull-down menu (values without a
% corresponding databaseFillCell entry are grayed out).
for index = 1:d_MAX_DATABASES
  % Must check for length first to prevent prevent checking an index
  % outside the current dimension of databaseNameCell.
  if index > length( piStarControl.databaseNameCell ) | ...
     isempty( piStarControl.databaseNameCell{ index } )
    piStarControl.databaseNameCell( index ) = databaseDefaultNameCellStr(index);
  end
end
% Set an 'empty' path prefix if not specified (if more databases than
% give path prefixes). If, for example, a path prefix is only required
% for the second database, it must be set to [] in the .ini file for the
% first database.
for index = ( length( piStarControl.databasePathPrefixCell ) + 1 ) : ...
              length( piStarControl.databaseListCell )
  piStarControl.databasePathPrefixCell{ index } = [] ;
end


% Check parameter groups for validity.

% Check data file names.
if ~isempty( piStarControl.baseFileNameStr )  & ...
   ~isempty( piStarControl.roverFileNameStr )
  piStarControl.dataFileNamesValid = 1 ;
end

% Check piStar phase/range multipliers.
if ( multipliersLoadedFlags == 1 + 2 + 4 + 8 ) & ...  % set all bit flags.
   ~isempty( piStarControl.phaseMultiplierL1 ) & ...
   ~isempty( piStarControl.phaseMultiplierL2 ) & ...
   ~isempty( piStarControl.rangeMultiplierL1 ) & ...
   ~isempty( piStarControl.rangeMultiplierL2 )
  piStarControl.multipliersValid = 1 ;
end

% Check for full valid positions.
if ( ecefPositionLoadedFlags == 1 + 2 + 4 + 8 + 16 + 32 ) & ...
   ~isempty( piStarControl.basePositionX )  & ...
   ~isempty( piStarControl.basePositionY )  & ...
   ~isempty( piStarControl.basePositionZ )  & ...
   ~isempty( piStarControl.roverPositionX ) & ...
   ~isempty( piStarControl.roverPositionY ) & ...
   ~isempty( piStarControl.roverPositionZ )
  piStarControl.ecefPositionValid = 1 ;
end

if ( geodeticPositionLoadedFlags == 1 + 2 + 4 + 8 + 16 + 32 ) & ...
   ~isempty( piStarControl.basePositionLat )  & ...
   ~isempty( piStarControl.basePositionLon )  & ...
   ~isempty( piStarControl.basePositionHgt )  & ...
   ~isempty( piStarControl.roverPositionLat ) & ...
   ~isempty( piStarControl.roverPositionLon ) & ...
   ~isempty( piStarControl.roverPositionHgt )
  piStarControl.geodeticPositionValid = 1 ;

  % Convert to ecef.
  [ piStarControl.baseXComputed, ...
    piStarControl.baseYComputed, ...
    piStarControl.baseZComputed ] = ...,
    translateToECEF( piStarControl.basePositionLat, ...
                     piStarControl.basePositionLon, ...
                     piStarControl.basePositionHgt ) ;
  [ piStarControl.roverXComputed, ...
    piStarControl.roverYComputed, ...
    piStarControl.roverZComputed ] = ...,
    translateToECEF( piStarControl.roverPositionLat, ...
                     piStarControl.roverPositionLon, ...
                     piStarControl.roverPositionHgt ) ;
end

if ( baselineVectorLoadedFlags == 1 + 2 + 4 ) & ...
   ~isempty( piStarControl.baselineVectorX ) & ...
   ~isempty( piStarControl.baselineVectorY ) & ...
   ~isempty( piStarControl.baselineVectorZ )
  piStarControl.baselineVectorValid = 1 ;
end


% Compute baseline length for display purposes.
if isempty( piStarControl.baselineLength )
% Not provided in the piStar.ini file (the usual case). Can
% alternatively be provided via the regression system (special
% piStar.ini file), or from the database.
  if piStarControl.ecefPositionValid
   piStarControl.baselineLength = sqrt( ...
     ( piStarControl.basePositionX - piStarControl.roverPositionX ) * ...
       ( piStarControl.basePositionX - piStarControl.roverPositionX ) + ...
     ( piStarControl.basePositionY - piStarControl.roverPositionY ) * ...
       ( piStarControl.basePositionY - piStarControl.roverPositionY ) + ...
     ( piStarControl.basePositionZ - piStarControl.roverPositionZ ) * ...
       ( piStarControl.basePositionZ - piStarControl.roverPositionZ ) ) ;
  elseif piStarControl.geodeticPositionValid
   piStarControl.baselineLength = sqrt( ...
     ( piStarControl.baseXComputed - piStarControl.roverXComputed ) * ...
       ( piStarControl.baseXComputed - piStarControl.roverXComputed ) + ...
     ( piStarControl.baseYComputed - piStarControl.roverYComputed ) * ...
       ( piStarControl.baseYComputed - piStarControl.roverYComputed ) + ...
     ( piStarControl.baseZComputed - piStarControl.roverZComputed ) * ...
       ( piStarControl.baseZComputed - piStarControl.roverZComputed ) ) ;

  % Test only!
  % Obtain approximate east/north/up vector for 4700 rkwin input file.
  % Actually a delta lat/long/up, hence only approx.
  % fprintf( 'Vector East = %d\n', ...
  %          ( piStarControl.roverPositionLon - piStarControl.basePositionLon )...
  %           * 2 * pi * 6378135 ...
  %           * cos( piStarControl.basePositionLat * pi / 180 ) / 360 ) ;
  % fprintf( 'Vector North = %d\n', ...
  %          ( piStarControl.roverPositionLat- piStarControl.basePositionLat )...
  %           * 2 * pi * 6378135 / 360 ) ;
  % fprintf( 'Vector Up = %d\n', ...
  %          piStarControl.roverPositionHgt - piStarControl.basePositionHgt ) ;
  % End of Test.

  elseif piStarControl.baselineVectorValid
   piStarControl.baselineLength = sqrt( ...
     piStarControl.baselineVectorX * piStarControl.baselineVectorX + ...
     piStarControl.baselineVectorY * piStarControl.baselineVectorY + ...
     piStarControl.baselineVectorZ * piStarControl.baselineVectorZ ) ;
  end
end


% Check if sufficient parameters to run PiLine.
% THIS WILL NEED TO BE REMOVED AND CHECKED IN RUNPILINE
if ( piStarControl.ecefPositionValid | piStarControl.geodeticPositionValid | ...
     piStarControl.baselineVectorValid ) & ...
   piStarControl.dataFileNamesValid
  piStarControl.piLineValid = 1 ;
end


% Check if 'Warning!' (serious) or 'Caution!' messages required.
if ~isempty( invalidControlStr )
  set( statusBoxHandle, 'FontName', 'courier', 'String', ...
       sprintf( [ 'WARNING!\n' ...
                  'piStar.ini contains invalid control parameter:\n' ...
                  invalidControlStr ] ) ) ;
elseif geodeticPositionLoadedFlags & ~piStarControl.geodeticPositionValid
  set( statusBoxHandle, 'FontName', 'courier', 'String', ...
       sprintf( [ 'WARNING!\n' ...
                  'piStar.ini contains invalid/missing geodetic position\n'...
                  'Use format 12d34m5.67sN (S,E,W) for degs,mins,secs, or\n'...
                  '           12°34''5.67"N, or\n'...
                  '           12.3456N' ] ) ) ;
elseif ecefPositionLoadedFlags & ~piStarControl.ecefPositionValid
  set( statusBoxHandle, 'FontName', 'courier', 'String', ...
       sprintf( [ 'WARNING!\n' ...
                  'piStar.ini contains invalid/missing x,y,z position' ] ) ) ;
elseif piStarControl.ecefPositionValid & piStarControl.geodeticPositionValid
  set( statusBoxHandle, 'FontName', 'courier', 'String', ...
       sprintf( [ 'CAUTION!\n' ...
                  'piStar.ini contains ECEF & geodetic positions' ] ) ) ;
elseif piStarControl.ecefPositionValid & piStarControl.baselineVectorValid
  set( statusBoxHandle, 'FontName', 'courier', 'String', ...
       sprintf( [ 'CAUTION!\n' ...
                  'piStar.ini contains ECEF position & baseline Vector' ] ) ) ;
elseif piStarControl.geodeticPositionValid & piStarControl.baselineVectorValid
  set( statusBoxHandle, 'FontName', 'courier', 'String', ...
       sprintf( [ 'CAUTION!\n' ...
                  'piStar.ini contains geodetic positon & baseline Vector' ] ));
elseif parseDatabase
  error = 0 ;  % All processing OK.
  [ path, name, ext ] = fileparts( piStarControl.databaseListCell{ ...
                                       piStarControl.selectedDatabase } ) ;
  set( statusBoxHandle, 'FontName', 'courier', 'String', ...
       sprintf( 'Successfully read file: %s', [ name ext ] ) ) ;
else
  error = 0 ;  % All processing OK.
  set( statusBoxHandle, 'FontName', 'courier', 'String', ...
       sprintf( 'Successfully read file: %s', iniFileNameStr ) ) ;
end


%%%%%%%%%% Sub Functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [ controlValue ] = ...
    loadValue( controlStr, valueStr, valueType, newControlValue, newFid )
% Decode the value from the .ini file when parsing the file for the
% first time (pass first 3 parameters), or update the .ini file when
% newFid loaded (pass all parameters). For the latter case, the .ini is
% also parsed (to determine the layout), but the control parameters are
% ignored as they have already been loaded (and possibly updated via the
% GUI).

% Not returned when only 4 parameters passed. Must default to prevent
% Matlab compiler run-time warning.
controlValue = [] ;

if nargin < 5
% Not updating the .ini file, but just parsing the file and loading.
  switch valueType
    case { 0 5 6 }
    % String; or string = filename in database; or single string
    % selected from a cell array of strings.
      controlValue = valueStr ;
      if strcmp( controlValue, '[]' )
        controlValue = [] ;
      end

    case 1  % Number
      controlValue = str2num( valueStr ) ;  % Return the value.

    case 2  % 'yes' or 'no'
      if valueStr( 1 ) == 'Y' | valueStr ( 1 ) == 'y'
        controlValue = 1 ;
      else
        controlValue = 0 ; 
      end

    case { 3 4 }  % Geodetic position
      controlValue = parseGeodeticPosition( valueStr ) ;

  end  % of switch

elseif isnan( newControlValue )
% Value is NaN: Updating the .ini file, but special case used to
% remove a line. For example, swapping from geodetic to x,y,z
% coordinate. Only one set is allowed.
% DO NOTHING.
% (Cannot use an "elseif ~isnan()" instead of the "else" below because
% this returns [] rather than 1 when the passed value is [] ).

else
% Updating the .ini file. valueStr is not used.
% Not special case used to remove a line (when value is NaN).
% Value to file always written as a string.
  switch valueType
    case { 0 5 6 }  % Already a string
      if isempty( newControlValue )
        controlValueStr = '[]' ;
      else
        % Check if any spaces (such as file names).
        % If so, surround with double-quotes.
        spaceIndexVec = findstr( newControlValue, ' ' ) ;
        if isempty( spaceIndexVec ) 
          controlValueStr = newControlValue ;
        else
          controlValueStr = [ '"' newControlValue '"' ] ;
        end
      end

    case 1  % Number
      if isempty( newControlValue )
      % Previous value has been removed (set to "not defined").
        controlValueStr = '[]' ;
      else
        controlValueStr = num2str( newControlValue ) ;
      end

    case 2  % 'yes' or 'no'
      if newControlValue
        controlValueStr = 'Yes' ;
      else
        controlValueStr = 'No' ; 
      end

    case 3  % Geodetic position latitude
      controlValueStr = formatGeodeticPosition( newControlValue, 0 ) ;

    case 4  % Geodetic position longitude
      controlValueStr = formatGeodeticPosition( newControlValue, 1 ) ;

  end  % of switch

  % Add line to new .ini file.
  fprintf( newFid, '%s = %s\n', controlStr, controlValueStr ) ;
end
% End of subfunction loadValue().


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [ position, positionComponentsVec ] = parseGeodeticPosition( inputStr )
% Default plotting controls for phase or range residual plots.
% Allowable formats are:
% 61d34m22.60114sN or S (longitude is E or W)
% 61°34'22.60114"N or S

TRUE = 1 ;
FALSE = 0 ;

signMultiplier = 1 ;

if length( inputStr ) < 7
% Must have minimum of: 1d1m1sN. Check required because use (end-1) below.
  position = [] ;
  positionComponentsVec = [] ;
  return ;
end

char_d_indexVec = findstr( inputStr, 'd' ) ;
if isempty( char_d_indexVec )
  char_d_indexVec = findstr( inputStr, '°' ) ;
end

char_m_indexVec = findstr( inputStr, 'm' ) ;
if isempty( char_m_indexVec )
  char_m_indexVec = findstr( inputStr, '''' ) ;  % Match for single quote.
end

secondChar = inputStr( end - 1 ) ;
if ~strcmp( secondChar, 's' ) & ~strcmp( secondChar, '"' ) & ...
   ( ~isempty( char_d_indexVec ) | ~isempty( char_m_indexVec ) )
% Must have a valid 'second' character, unless no degree of minute char
% found (i.e. entering value as decimal degrees, which has no delimiters).
  position = [] ;
  positionComponentsVec = [] ;
  return ;
end

directionChar = inputStr( end ) ;
if strcmp( directionChar, 'N' ) | strcmp( directionChar, 'E' )
  signMultiplier = 1 ;
elseif strcmp( directionChar, 'S' ) | strcmp( directionChar, 'W' )
  signMultiplier = -1 ;
else  % Incorrect format.
  position = [] ;
  positionComponentsVec = [] ;
  return ;
end

% Check if format is just decimal degrees.
if isempty( char_d_indexVec ) & isempty( char_m_indexVec )
  decimalDegrees = TRUE ;
else
  decimalDegrees = FALSE ;
 
  % Check for single occurance of chars d, m, and in correct order.
  if length( char_d_indexVec ) ~= 1 | ...
     length( char_m_indexVec ) ~= 1 | ...
     ...% Cannot start with 'd'. Must check because use (char_d_indexVec-1)
     ...% below.
     char_d_indexVec           == 1 | ...
     ( char_d_indexVec >  char_m_indexVec )
    position = [] ;
    positionComponentsVec = [] ;
    return ;
  end
end

if decimalDegrees
  degrees = str2num( inputStr( 1:(end-1) ) ) ;

  % Load returned values.
  position =  degrees * signMultiplier ;

  % The following is not used yet, but would need an update at such time.
  positionComponentsVec( 1 ) = position ;
  positionComponentsVec( 2 ) = 0 ;  % To be updated.
  positionComponentsVec( 3 ) = 0 ;
else
  degrees = str2num( inputStr( 1:(char_d_indexVec-1) ) ) ;
  minutes = str2num( inputStr( (char_d_indexVec+1):(char_m_indexVec-1) ) ) ;
  seconds = str2num( inputStr( (char_m_indexVec+1):(end-2) ) ) ;

  position = ( degrees + minutes / 60.0 + seconds / 3600.0 ) * signMultiplier ;

  positionComponentsVec( 1 ) = degrees * signMultiplier ;  % For displays.
  positionComponentsVec( 2 ) = minutes ;
  positionComponentsVec( 3 ) = seconds ;
end

% End of subfunction parseGeodeticPosition().


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [ positionStr ] = formatGeodeticPosition( position, type )
% Convert position to string:
% 61°34'22.60114"N or S  (longitude is E or W)
% type = 0: latitude  (choose N or S)
% type = 1: longitude (choose E or W)

if type == 0  % Latitude
  if position < 0
    typeChar = 'S' ;
  else
    typeChar = 'N' ;
  end
else
  if position < 0
    typeChar = 'W' ;
  else
    typeChar = 'E' ;
  end
end

pos = abs( position ) ;
degrees = fix( pos ) ;
pos = ( pos - degrees ) * 60 ;
minutes = fix( pos ) ;
seconds = ( pos - minutes ) * 60 ;

positionStr = [ num2str( degrees) '°' num2Str( minutes ) '''' ...
                num2str( seconds, 7 ) '"' typeChar ] ;

% End of subfunction formatGeodeticPosition().


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [ x, y, z ] = translateToECEF( lat, lon, hgt )
% Translate a geodetic latitude, longitude, height position (in WGS84) into
%  an ECEF x,y,z position.
%
% Passed:
%   lat, lon, hgt: geodetic_position, lat / long / height (in degrees, meters).
%
% Returned:
%   ecef_position: array of x,y,z absolute position coords. Returned.
%
% Globals: NONE.
%
% Technique:
% The standard formulae are used. This routine was copied from piLine,
% file baseline.c.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

E2WGS84 = 6.6943799901413E-3 ;  % =1-(1-F)**2 eccentricity squared
AWGS84  = 6378137.0          ;  % semi major axis of the WGS84 ellipsoid

latRad = lat * ( pi / 180.0 ) ;  % Convert to radians.
lonRad = lon * ( pi / 180.0 ) ;

sinLat = sin( latRad ) ;

% Calculate radius of curvature in the prime vertical.
radCurve = AWGS84 / sqrt( 1 - E2WGS84 * sinLat * sinLat ) ;

rhCosLat = ( radCurve + hgt ) * cos( latRad ) ;

% Calculate ecef x, y, z position.
x = rhCosLat * cos( lonRad ) ;
y = rhCosLat * sin( lonRad ) ;
z = ( radCurve * ( 1.0 - E2WGS84 ) + hgt ) * sinLat ;

% End of subfunction translateToECEF().


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% $Log: parseIniFile.m,v $
% Revision 1.1  2003/09/30 16:41:15  stuart
% o Required for PiStar.ini processing
%
% Revision 1.27  2003/09/30 15:20:06  timo
% Updates to support new PiPro parameters.
%
% Revision 1.26  2003/06/17 14:53:31  timo
% Upates for PiStar.
%
% Revision 1.25  2003/05/20 13:42:10  timo
% Updates for PiStar simulator.
%
% Revision 1.24  2003/05/13 09:13:57  timo
% Updates to support PiStar simulator.
%
% Revision 1.23  2003/01/03 11:27:58  timo
% Add start and stop times for PiLine. Fix updating the piStar.ini
% file with [] values.
%
% Revision 1.22  2002/10/02 07:51:57  timo
% Fix Matlab compiler warning.
%
% Revision 1.21  2002/09/26 13:07:52  timo
% Add test code for 4700 to obtain vector in east/north/up.
%
% Revision 1.20  2002/09/19 14:43:54  timo
% Set default value for iono scale factor after loading from a
% database.
%
% Revision 1.19  2002/09/17 08:48:15  timo
% Clear baselineNameCellArray. Must clear last load, or cell array will
% be appended and list box show more than one database.
%
% Revision 1.18  2002/09/12 10:12:40  timo
% Further updates to support databases.
%
% Revision 1.17  2002/08/22 14:01:38  timo
% Fix reads of datdabasePathPrefix from the piStar.ini file.
%
% Revision 1.16  2002/08/14 16:33:14  timo
% Further updates to support databases.
%
% Revision 1.15  2002/07/29 14:26:52  timo
% Further updates to support databases.
%
% Revision 1.14  2002/07/18 16:26:13  timo
% Update support for database.
%
% Revision 1.13  2002/07/16 13:31:02  timo
% Updates for database file parsing.
%
% Revision 1.12  2002/07/09 14:39:29  timo
% Updates for using a database .ini file to specify survey data files.
%
% Revision 1.11  2002/06/18 13:04:09  timo
% Updates to allow east,north,up offsets.
%
% Revision 1.10  2002/06/11 14:19:51  timo
% Add reading of baselineLengh from regression system.
%
% Revision 1.9  2002/05/01 09:32:18  timo
% Updates for Bad Init Detection.
%
% Revision 1.8  2002/02/14 10:36:37  timo
% Inlcude parsing new PiPro parameters.
%
% Revision 1.7  2002/01/17 16:05:09  timo
% Updates for piPro and rkwin parameters.
%
% Revision 1.6  2001/12/06 17:45:05  timo
% Include updates for rewriting the piLab.ini file.
%
% Revision 1.5  2001/11/20 12:00:31  timo
% Baseline vector for display purposes was not being computed
% when the baseline vector was specified in the piStar.ini file (as
% opposed to the base/rover geodetic or ecef positions).
%
% Revision 1.4  2001/11/08 09:37:21  timo
% Add computation of baseline length (appears in plots).
%
% Revision 1.3  2001/10/03 12:04:34  timo
% Updates for V1.32
%
% Revision 1.2  2001/10/02 09:11:53  timo
% Updates for V3.12. Read new rkwin.out file format. Load rkwin
% version number.
%
% Revision 1.1  2001/09/13 16:39:48  timo
% Parses PiStar.ini file, which contains parameters for PiLab, PiLine,
% and support of RKWin.
%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
