#!/usr/bin/env python3
# ========================================================================
# SPDX-FileCopyrightText: 2021-2022 Harald Pretl
# Johannes Kepler University, Institute for Integrated Circuits
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# SPDX-License-Identifier: Apache-2.0
#
# This script traverses SPICE model files (e.g. from SKY130) and
# extracts only the wanted model section, removes all comments and
# empty lines, and resolves all includes so that a flat model file
# results. This should speed up ngspice starts.
# ========================================================================

import sys,re,os

def process_file(file_in_name, top_file):
    global is_warning
    try:
        f_in = open(file_in_name, 'r')
    except FileNotFoundError:
        print('Warning! File ' + file_in_name + ' not found.')
        is_warning = True
        return;

    # process_file can be called recursively, so that nested include
    # files can be traversed

    # write_active indicates whether we are in the right model section; in
    # include files, it is always true

    if top_file == True:
        write_active = False
    else:
        write_active = True
    
    for line in f_in:
        line_trim = (line.lower()).strip()

        if top_file == True:
            # we assume that .lib statements are only used in the main file
            if '.lib' in line_trim:
                if model_section in line_trim: 
                    write_active = True
                else:
                    write_active = False
        
            if '.endl' == line_trim:
                write_active = False
                f_out.write(line)

        if len(line_trim) > 0: # write no empty lines
            if (line_trim[0] != '*'): # write no comments
                if (write_active == True):
                    if '.include' in line_trim:
                        # need to save and restore working dir so that nested 
                        # includes work
                        current_wd = os.getcwd()
                        newfile = re.findall(r'"(.*?)(?<!\\)"', line_trim)
                        print('Reading ',newfile[0])

                        # enter new working dir
                        new_wd = os.path.dirname(newfile[0]) 
                        if len(new_wd) > 0:
                            try:
                                os.chdir(new_wd)
                            except OSError:
                                print('Warning: Could not enter directory ' + new_wd)
                                is_warning = True

                        # traverse into new include file
                        new_file_name = os.path.basename(newfile[0]) 
                        process_file(new_file_name, False) 
                        
                        # restore old working dir after return
                        os.chdir(current_wd)
                    else:
                        f_out.write(line)

    f_in.close()
    return;

# main routine

if len(sys.argv) == 3:
    model_section = sys.argv[2]
else:
    model_section = 'tt'

if (len(sys.argv) == 2) or (len(sys.argv) == 3):
    infile_name = sys.argv[1]
    outfile_name = infile_name + '.' + model_section + '.red'

    try:
        f_out = open(outfile_name, 'w')
    except OSError:
        print('Error: Cannot write file ' + outfile_name + '.')
        sys.exit(1)
    
    is_warning = False
    process_file(infile_name, True)
    f_out.close()
    
    print()
    print('Model file ' + outfile_name + ' written.')
    if is_warning == True:
        print('There have been warnings! Please check output log.')
        sys.exit(0)
    else:
        sys.exit(0) 
else:
    print()
    print('iic-spice-model-red.py    SPICE model file reducer')
    print('                          (c) 2021 Harald Pretl, JKU')
    print()
    print('Usage: iic-spice-model-red <inputfile> [corner] (default corner = tt)')
    print()
    print('Return codes for script automation:')
    print('  0 = all OK or warnings')
    print('  1 = errors')
    print('  2 = call of script w/o parameters (= showing this message)')
    print()
    sys.exit(2)
