Tool: Update some new features and refinements

 - Support name the output database file.
 - Support input specific name database file.
 - Fix the defect that delete all database file in the path.
 - UI option and terminal options are conflicting now.
 - Terminal messages are reversed, summary info shows at last.
 - Support sort messages in terminal mode.
 - Update help message and document.
 - Other code and structure refinements.

Signed-off-by: Jianliang Shen <jianliang.shen@arm.com>
Change-Id: I597f05bebc4f20d316f400ed3d099bd9dbbd972a
diff --git a/code-size-analyze-tool/README.rst b/code-size-analyze-tool/README.rst
index add23e2..e9abcf2 100644
--- a/code-size-analyze-tool/README.rst
+++ b/code-size-analyze-tool/README.rst
@@ -24,7 +24,7 @@
 
 .. code-block:: bash
 
-    sudo apt-get install python3-dev libmysqlclient-dev libncursesw6 libncurses6
+    sudo apt-get install python3-dev libmysqlclient-dev libncursesw6 libncurses6 libsqlite3-dev
     pip install mysqlclient XlsxWriter
 
 Windows
@@ -44,56 +44,72 @@
 
 .. code-block:: bash
 
-    python3 code_size_analyze.py [-h] [-i MAP_FILE_INPUT] [-u]
-                                 <--gnuarm|--armcc>
-                                 [-a] [-s] [-l] [-o] [-f] [-d]
-                                 [--dump_section SECTION_NAME]
-                                 [--dump_library LIBRARY_NAME]
-                                 [--dump_obj OBJ_NAME]
-                                 [--dump_function DUMP_FUNCTION_NAME]
-                                 [--dump_data DUMP_DATA_NAME]
-                                 [--search_func FUNCTION_NAME]
-                                 [--search_data DATA_NAME]
+    usage: code_size_analyze.py [-h] [--gnuarm | --armcc] [--db-name <data.db>]
+                                [-u | -S | -s | -l | -o | -f | -d |
+                                 --dump-sec <sec> | --dump-lib <lib> |
+                                 --dump-obj <obj> | --dump-func <func> |
+                                 --dump-data <data> | --search-func <func> |
+                                 --search-data <data>]
+                                [--sort-by-size | --sort-by-name |
+                                 --sort-by-obj | --sort-by-lib |
+                                 --sort-by-sec] [--desc | --asc]
+                                 file_input
 
-    options:
-        -h, --help                          show this help message and exit
-        -i MAP_FILE_INPUT                   map file path <path>/tfm_s.map
-        -u, --ui                            show UI
-        --gnuarm                            gnuarm map file input
-        --armcc                             armclang map file input
-        -a, --all                           show total
-        -s, --list_section                  list section
-        -l, --list_library                  list library
-        -o, --list_obj                      list object file
-        -f, --list_function                 list function
-        -d, --list_data                     list data
-        --dump_section SECTION_NAME         dump section
-        --dump_library LIBRARY_NAME         dump library
-        --dump_obj OBJ_NAME                 dump object file
-        --dump_function DUMP_FUNCTION_NAME  dump function
-        --dump_data DUMP_DATA_NAME          dump data
-        --search_func FUNCTION_NAME         search function
-        --search_data DATA_NAME             search data
+    positional arguments:
+        file_input            map or database file
+
+    optional arguments:
+        -h, --help            show this help message and exit
+        --gnuarm              GNUARM model
+        --armcc               ARMCLANG model
+        --db-name <data.db>   database name to save
+        -u, --ui              start UI to analyze
+        -S, --Summary         show summary message
+        -s, --list-section    list section
+        -l, --list-library    list library
+        -o, --list-obj        list object file
+        -f, --list-function   list function
+        -d, --list-data       list data
+        --dump-sec <sec>      dump section
+        --dump-lib <lib>      dump library
+        --dump-obj <obj>      dump object file
+        --dump-func <func>    dump function
+        --dump-data <data>    dump data
+        --search-func <func>  search function
+        --search-data <data>  search data
+        --sort-by-size        list by size order
+        --sort-by-name        list by name order
+        --sort-by-obj         list by object file name order
+        --sort-by-lib         list by library file name order
+        --sort-by-sec         list by section name order
+        --desc                sort with desc order
+        --asc                 sort with asc order
 
 Create database
 ===============
 
 It is required to input map file path for the script before show the UI. One of
-the options like ``--gnuarm`` or ``--armcc`` is required. Keep the compiler
-option same from the beginning to the end.
+the options like ``--gnuarm`` or ``--armcc`` is required.
+
+The default database name created is ``data.db``. Use ``--db-name`` to name the
+output file if necessary. For example, saving two different databases to compare
+later.
 
 .. code-block:: bash
 
-    python3 code_size_analyze.py -i MAP_FILE_INPUT <--gnuarm|--armcc>
+    $: python code_size_analyze.py tfm_s.map <--gnuarm|--armcc> --db-name tfm_s.db
 
-Show the UI
-===========
+UI mode
+=======
 
 The script ui.py supplies a menu to choose what developers may be interested.
+You can enter UI mode by analyzing map file directly or by importing database
+file path. The latter way is suggested as it runs more quickly.
 
 .. code-block:: bash
 
-    python3 code_size_analyze.py -u <--gnuarm|--armcc>
+    $: python code_size_analyze.py tfm_s.map <--gnuarm|--armcc> -u
+    $: python code_size_analyze.py tfm_s.db -u
 
 There are several keys to use UI.
 
@@ -106,56 +122,111 @@
 * ``s`` or ``S``: Enter output file name to save the content of current page.
 * ``:`` : Start search and enter the function or data name.
 
+Terminal mode
+=============
+
+In terminal mode, it is better to analyze database file rather than map file.
+
 Dump detail information
-=======================
+-----------------------
 
 You can get the list of all sections, libraries, object files, functions or
 data. You can also dump the specific symbol with the name.
 
 .. code-block:: bash
 
-    python3 code_size_analyze.py <--gnuarm|--armcc> -s
-    python3 code_size_analyze.py <--gnuarm|--armcc> --dump_section SECTION_NAME
+    $: python code_size_analyze.py tfm_s.map --armcc --db-name test.db -S
+    ───────────────────────────────────────────────
+    Code size       : 56676         55.35   KB
+    -----------------------------------------------
+    RO data         : 3732          3.64    KB
+    RW data         : 204           0.20    KB
+    ZI data         : 24588         24.01   KB
+    Flash size      : 60612         59.19   KB = Code + RO + RW
+    RAM size        : 24792         24.21   KB = RW + ZI
+    ───────────────────────────────────────────────
 
+    $: python code_size_analyze.py tfm_s.db -s
+    $: python code_size_analyze.py tfm_s.db --dump-sec <sec>
 
 Search specific function or data
-================================
+--------------------------------
 
 You can search the target with keyword in command line. For example:
 
 .. code-block:: bash
 
-    python3 code_size_analyze.py <--gnuarm|--armcc> --search_func FUNCTION_NAME
-    python3 code_size_analyze.py <--gnuarm|--armcc> --search_data DATA_NAME
+    $: python code_size_analyze.py tfm_s.db --search-func <func>
+    $: python code_size_analyze.py tfm_s.db --search-data <data>
+
+Sort Table
+----------
+
+You can sort the messages in terminal mode. The script supplies five options and
+two orders. For example:
+
+.. code-block:: bash
+
+    $: python code_size_analyze.py tfm_s.db -l --sort-by-size --asc
+    ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
+    Name                                              Flash size  RAM size    Code        RO data     RW data     ZI data     Inc. data   Debug
+    --------------------------------------------------------------------------------------------------------------------------------------------------
+    libtfm_qcbor_s.a                                  758         0           758         0           0           0           4           17046
+    libtfm_sprt.a                                     1016        0           1016        0           0           0           0           41004
+    c_w.l                                             1248        96          1248        0           0           96          86          1892
+    libtfm_psa_rot_partition_attestation.a            2497        557         2492        5           0           557         68          51865
+    libtfm_spm.a                                      4112        657         3932        136         44          613         168         52958
+    libtfm_psa_rot_partition_its.a                    5090        116         5030        32          28          88          28          49804
+    libtfm_psa_rot_partition_crypto.a                 6062        3232        6062        0           0           3232        36          92472
+    libplatform_s.a                                   6486        316         5582        780         124         192         404         94887
+    libmbedcrypto.a                                   28408       2292        26138       2262        8           2284        1066        226489
+    ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
+
+Not all symbols support to be sorted by the whole five options, refer to the
+table to get more information.
+
++----------------+---------+---------+--------------+----------+------+
+| Options        | Section | Library | Object files | Function | Data |
++================+=========+=========+==============+==========+======+
+| --sort-by-size |    √    |    √    |       √      |    √     |   √  |
++----------------+---------+---------+--------------+----------+------+
+| --sort-by-name |    √    |    √    |       √      |    √     |   √  |
++----------------+---------+---------+--------------+----------+------+
+| --sort-by-sec  |    √    |         |              |    √     |   √  |
++----------------+---------+---------+--------------+----------+------+
+| --sort-by-lib  |         |    √    |       √      |    √     |   √  |
++----------------+---------+---------+--------------+----------+------+
+| --sort-by-obj  |         |         |       √      |    √     |   √  |
++----------------+---------+---------+--------------+----------+------+
 
 *******************
 Code size diff tool
 *******************
 
 Use ``code_size_diff.py`` to diff two diffrent build results with same compiler.
-Firstly, use ``code_size_analyze.py`` to prepare two different databases. For
-example:
 
 .. code-block:: bash
 
-    usage: code_size_diff.py [-h] -i [input_dbs [input_dbs ...]]
-                             [-a] [-f] [-d] [-o] [-l]
+    usage: code_size_diff.py [-h] (-S | -f | -d | -o | -l) based_db compared_db
+
+    positional arguments:
+        based_db             based databse
+        compared_db          compared databse
 
     optional arguments:
-    -h, --help            show this help message and exit
-    -i [input_dbs [input_dbs ...]], --input [input_dbs [input_dbs ...]]
-                          Input two different data base files
-    -a, --diff_all        diff summary
-    -f, --diff_function   diff function
-    -d, --diff_data       diff data
-    -o, --diff_obj        diff object file
-    -l, --diff_lib        diff library
+        -h, --help            show this help message and exit
+        -S, --diff-Summary    diff summary
+        -f, --diff-function   diff function
+        -d, --diff-data       diff data
+        -o, --diff-obj        diff object file
+        -l, --diff-lib        diff library
 
-Then compare two database with the diff tool, the branch1 is base.
+Firstly, use ``code_size_analyze.py`` to prepare two different databases. Then
+compare two database with the diff tool, the branch1 is base.
 
 .. code-block:: bash
 
-    python3 code_size_diff.py -i output/branch1.db output/branch2.db -a
+    $: python code_size_diff.py output/branch1.db output/branch2.db -S
     Code size:  +++         48928   B               47.78   KB
     RO data:    +++         29440   B               28.75   KB
     RW data:    ---         64      B               0.06    KB
@@ -163,9 +234,6 @@
     Flash size: +++         78304   B               76.47   KB
     RAM size:   ---         564     B               0.55    KB
 
-The summary information change will be printed. Enter ``-h`` to get more usages
-of diff tool.
-
 --------------
 
 *Copyright (c) 2021-2022, Arm Limited. All rights reserved.*
diff --git a/code-size-analyze-tool/code_size_analyze.py b/code-size-analyze-tool/code_size_analyze.py
index 4aa6763..ef914f2 100644
--- a/code-size-analyze-tool/code_size_analyze.py
+++ b/code-size-analyze-tool/code_size_analyze.py
@@ -8,94 +8,168 @@
 import argparse
 import os
 import sys
+import glob
 sys.path.append("src")
 from ui import UI
 from sq import SQ
 
-none_databse = "Cannot find database file! Please use this command to create \
-databse:\n\n\tpython3 code_size_analyze.py -i <map file path> --gnuarm/--armcc\n"
+none_databse = "Cannot find database {}! Please use this command to create \
+databse:\n\n\tpython3 code_size_analyze.py --map <map file path> \
+--gnuarm/--armcc --db {}\n"
+
+def reverse_terminal_text(items):
+    line1 = "─" * 128
+    tmp, ret = [], []
+    for x in items:
+        if x == line1:
+            ret.append(tmp)
+            tmp = []
+        tmp.append(x)
+    items = []
+    for i in range(len(ret) - 1, -1, -1):
+        items.extend(ret[i])
+    items.append(line1)
+    return items
 
 def main(args):
-    """
-    It is required to input only one of '--gnuarm' and '--armcc'.
-    """
-    if (args.gnuarm_compiler and args.armclang_compiler) or \
-        (not args.gnuarm_compiler and not args.armclang_compiler):
-        print("Error: Need \'--gnuarm\' or \'--armcc\'")
-        exit(0)
-
+    map_file, db_file = "", ""
+    if args.file_input.find(".map") >= 0:
+        map_file = args.file_input
+    else:
+        db_file = args.file_input
     """
     Class 'sq' is to create a sqlite3 database from map file of compiler.
     """
-    if args.map_file_input:
+    if map_file:
+        if not args.gnuarm_compiler and not args.armclang_compiler:
+            print("Error: Need --gnuarm or --armcc to create database")
+            exit(0)
+        if os.path.exists(args.db_name):
+            for infile in glob.glob(os.path.join(os.getcwd(), args.db_name)):
+                os.remove(infile)
         sq = SQ()
         sq.gnuarm = True if args.gnuarm_compiler else False
         sq.armcc = True if args.armclang_compiler else False
-        sq.file_path = args.map_file_input
+        sq.map_file = map_file
+        sq.db_name = args.db_name
         sq.update()
 
-    if os.path.exists('data.db'):
+    if (db_file and os.path.exists(db_file)) or (map_file and os.path.exists(args.db_name)):
         """
         Class 'ui' is to show the ui in terminal or export plaintext.
         """
         ui = UI()
         ui.gnuarm = True if args.gnuarm_compiler else False
         ui.armcc = True if args.armclang_compiler else False
-        output = ""
+        if db_file:
+            ui.db_file = db_file
+        if map_file:
+            ui.db_file = args.db_name
+        ui.open_db()
+        if args.sort_by_size:
+            ui.sort = "size"
+        if args.sort_by_name:
+            ui.sort = "name"
+        if args.sort_by_obj:
+            ui.sort = "obj_file"
+        if args.sort_by_lib:
+            ui.sort = "lib_file"
+        if args.sort_by_sec:
+            ui.sort = "section"
+
+        if args.desc:
+            ui.order = "DESC"
+        if args.asc:
+            ui.order = "ASC"
+
         if args.ui_show:
+            if args.sort_by_name or args.sort_by_obj or args.sort_by_lib or args.sort_by_sec:
+                print("UI mode cannot support sort. Use it in terminal mode.")
+                exit(0)
             ui.run()
-        else:
-            if args.all:
-                ui.draw_summary_page()
 
-            if args.list_function:
-                ui.draw_function_page("")
+        if args.all:
+            ui.draw_summary_page()
 
-            if args.function_name:
-                ui.draw_function_page(args.function_name)
+        if args.list_function:
+            ui.draw_function_page("")
 
-            if args.dump_function_name:
-                ui.function_name = args.dump_function_name
-                ui.draw_function_detail_page()
+        if args.function_name:
+            ui.draw_function_page(args.function_name)
 
-            if args.list_data:
-                ui.draw_data_page("")
+        if args.dump_function_name:
+            ui.function_name = args.dump_function_name
+            ui.draw_function_detail_page()
 
-            if args.data_name:
-                ui.draw_data_page(args.data_name)
+        if args.list_data:
+              ui.draw_data_page("")
 
-            if args.dump_data_name:
-                ui.data_name = args.dump_data_name
-                ui.draw_data_detail_page()
+        if args.data_name:
+            ui.draw_data_page(args.data_name)
 
-            if args.list_obj:
-                ui.draw_obj_page()
+        if args.dump_data_name:
+            ui.data_name = args.dump_data_name
+            ui.draw_data_detail_page()
 
-            if args.obj_name:
-                ui.obj_file = args.obj_name
-                ui.draw_obj_detail_page()
+        if args.list_obj:
+            if args.sort_by_obj:
+                ui.sort = "name"
+            if args.sort_by_sec:
+                print("Object files cannot sort by this option")
+                exit(0)
+            ui.draw_obj_page()
 
-            if args.list_library:
-                ui.draw_library_page()
+        if args.obj_name:
+            ui.obj_file = args.obj_name
+            ui.draw_obj_detail_page()
+            ui.items = reverse_terminal_text(ui.items)
 
-            if args.library_name:
-                ui.library_name = args.library_name
-                ui.draw_library_detail_page()
+        if args.list_library:
+            if args.sort_by_lib:
+                ui.sort = "name"
+            if args.sort_by_obj or args.sort_by_sec:
+                print("Libraries cannot sort by this option")
+                exit(0)
+            ui.draw_library_page()
 
-            if args.list_section:
-                ui.draw_section_page()
+        if args.library_name:
+            if args.sort_by_sec or args.sort_by_obj:
+                print("Library dump cannot sort by this option")
+                exit(0)
+            ui.library_name = args.library_name
+            ui.draw_library_detail_page()
+            ui.items = reverse_terminal_text(ui.items)
 
-            if args.section_name:
-                ui.section_name = args.section_name
-                ui.draw_section_lib()
+        if args.list_section:
+            if args.sort_by_sec:
+                ui.sort = "name"
+            if args.sort_by_lib or args.sort_by_obj:
+                print("Sections cannot sort by this option")
+                exit(0)
+            ui.draw_section_page()
 
-            output = ui.items
-            if output:
-                for s in output:
-                    print(s)
-        ui.con.close()
+        if args.section_name:
+            if args.sort_by_name or args.sort_by_obj or args.sort_by_lib or args.sort_by_sec:
+                print("Section dump cannot support sort.")
+                exit(0)
+            ui.section_name = args.section_name
+            ui.draw_section_lib()
+            ui.items = reverse_terminal_text(ui.items)
+
+        if "─" * 128 not in ui.items and "-" * 128 not in ui.items and ui.items:
+            max_len = 0
+            for x in ui.items:
+                max_len = max(max_len, len(x))
+            ui.items.insert(1, "-" * max_len)
+            ui.items.insert(0, "─" * max_len)
+            ui.items.append("─" * max_len)
+
+        if ui.items and not args.ui_show:
+            for s in ui.items:
+                print(s)
+
     else:
-        print(none_databse)
+        print(none_databse.format(db_file, db_file))
 
 def parse_args():
     """
@@ -103,66 +177,120 @@
     """
     parser = argparse.ArgumentParser()
 
-    parser.add_argument('-i', '--input',
-                        dest='map_file_input',
-                        help='map file path <path>/tfm_s.map')
-    parser.add_argument('-u', '--ui',
-                        dest='ui_show',
-                        action='store_true',
-                        help='show UI')
-    parser.add_argument('--gnuarm',
-                        dest='gnuarm_compiler',
-                        action='store_true',
-                        help='gnuarm map file input')
-    parser.add_argument('--armcc',
-                        dest='armclang_compiler',
-                        action='store_true',
-                        help='armclang map file input')
-    parser.add_argument('-a', '--all',
-                        dest='all',
-                        action='store_true',
-                        help='show total')
-    parser.add_argument('-s', '--list_section',
-                        dest='list_section',
-                        action='store_true',
-                        help='list section')
-    parser.add_argument('-l', '--list_library',
-                        dest='list_library',
-                        action='store_true',
-                        help='list library')
-    parser.add_argument('-o', '--list_obj',
-                        dest='list_obj',
-                        action='store_true',
-                        help='list object file')
-    parser.add_argument('-f', '--list_function',
-                        dest='list_function',
-                        action='store_true',
-                        help='list function')
-    parser.add_argument('-d', '--list_data',
-                        dest='list_data',
-                        action='store_true',
-                        help='list data')
-    parser.add_argument('--dump_section',
-                        dest='section_name',
-                        help='dump section')
-    parser.add_argument('--dump_library',
-                        dest='library_name',
-                        help='dump library')
-    parser.add_argument('--dump_obj',
-                        dest='obj_name',
-                        help='dump object file')
-    parser.add_argument('--dump_function',
-                        dest='dump_function_name',
-                        help='dump function')
-    parser.add_argument('--dump_data',
-                        dest='dump_data_name',
-                        help='dump data')
-    parser.add_argument('--search_func',
-                        dest='function_name',
-                        help='search function')
-    parser.add_argument('--search_data',
-                        dest='data_name',
-                        help='search data')
+    compiler_group = parser.add_mutually_exclusive_group()
+    compiler_group.add_argument('--gnuarm',
+                                dest='gnuarm_compiler',
+                                action='store_true',
+                                help='GNUARM model')
+    compiler_group.add_argument('--armcc',
+                                dest='armclang_compiler',
+                                action='store_true',
+                                help='ARMCLANG model')
+
+    parser.add_argument('file_input', help='map or database file')
+    parser.add_argument('--db-name',
+                        dest='db_name',
+                        metavar='<data.db>',
+                        default='data.db',
+                        help='database name to save')
+
+    terminal_opt = parser.add_mutually_exclusive_group()
+    terminal_opt.add_argument('-u', '--ui',
+                              dest='ui_show',
+                              action='store_true',
+                              help='start UI to analyze')
+    terminal_opt.add_argument('-S', '--Summary',
+                              dest='all',
+                              action='store_true',
+                              help='show summary message')
+    terminal_opt.add_argument('-s', '--list-section',
+                              dest='list_section',
+                              action='store_true',
+                              help='list section')
+    terminal_opt.add_argument('-l', '--list-library',
+                              dest='list_library',
+                              action='store_true',
+                              help='list library')
+    terminal_opt.add_argument('-o', '--list-obj',
+                              dest='list_obj',
+                              action='store_true',
+                              help='list object file')
+    terminal_opt.add_argument('-f', '--list-function',
+                              dest='list_function',
+                              action='store_true',
+                              help='list function')
+    terminal_opt.add_argument('-d', '--list-data',
+                              dest='list_data',
+                              action='store_true',
+                              help='list data')
+    terminal_opt.add_argument('--dump-sec',
+                              dest='section_name',
+                              metavar='<sec>',
+                              help='dump section')
+    terminal_opt.add_argument('--dump-lib',
+                              dest='library_name',
+                              metavar='<lib>',
+                              help='dump library')
+    terminal_opt.add_argument('--dump-obj',
+                              dest='obj_name',
+                              metavar='<obj>',
+                              help='dump object file')
+    terminal_opt.add_argument('--dump-func',
+                              dest='dump_function_name',
+                              metavar='<func>',
+                              help='dump function')
+    terminal_opt.add_argument('--dump-data',
+                              dest='dump_data_name',
+                              metavar='<data>',
+                              help='dump data')
+    terminal_opt.add_argument('--search-func',
+                              dest='function_name',
+                              metavar='<func>',
+                              help='search function')
+    terminal_opt.add_argument('--search-data',
+                              dest='data_name',
+                              metavar='<data>',
+                              help='search data')
+
+    sort_opt = parser.add_mutually_exclusive_group()
+    sort_opt.add_argument('--sort-by-size',
+                          dest='sort_by_size',
+                          action='store_true',
+                          default=True,
+                          help='list by size order')
+    sort_opt.add_argument('--sort-by-name',
+                          dest='sort_by_name',
+                          action='store_true',
+                          default=False,
+                          help='list by name order')
+    sort_opt.add_argument('--sort-by-obj',
+                          dest='sort_by_obj',
+                          action='store_true',
+                          default=False,
+                          help='list by object file name order')
+    sort_opt.add_argument('--sort-by-lib',
+                          dest='sort_by_lib',
+                          action='store_true',
+                          default=False,
+                          help='list by library file name order')
+    sort_opt.add_argument('--sort-by-sec',
+                          dest='sort_by_sec',
+                          action='store_true',
+                          default=False,
+                          help='list by section name order')
+
+    sort_ord = parser.add_mutually_exclusive_group()
+    sort_ord.add_argument('--desc',
+                          dest='desc',
+                          action='store_true',
+                          default=True,
+                          help='sort with desc order')
+    sort_ord.add_argument('--asc',
+                          dest='asc',
+                          action='store_true',
+                          default=False,
+                          help='sort with asc order')
+
     args = parser.parse_args()
     return args
 
diff --git a/code-size-analyze-tool/code_size_diff.py b/code-size-analyze-tool/code_size_diff.py
index ffd4d84..9459ba0 100644
--- a/code-size-analyze-tool/code_size_diff.py
+++ b/code-size-analyze-tool/code_size_diff.py
@@ -83,7 +83,7 @@
         print("{:<50}{:<10}{:<10}{:<50}".format(
             s['name'], s['sign'], s['delta'], s['obj']))
     print("─" * 120)
-    print("Total Function Size cahnge = {:<6} B\t= {:<8.2f} KB".format(
+    print("Total Function Size change = {:<6} B\t= {:<8.2f} KB".format(
         total_code_change, total_code_change/1024))
     print("─" * 120)
 
@@ -314,14 +314,14 @@
 
 def main(args):
     global con1, cur1, con2, cur2
-    if args.input_dbs:
-        if len(args.input_dbs) == 2:
-            con1 = sqlite3.connect(args.input_dbs[0])
-            cur1 = con1.cursor()
-            con2 = sqlite3.connect(args.input_dbs[1])
-            cur2 = con2.cursor()
-        else:
-            print("Error! Two database files shall be input.")
+
+    if args.based_db and args.compared_db:
+        con1 = sqlite3.connect(args.based_db)
+        cur1 = con1.cursor()
+        con2 = sqlite3.connect(args.compared_db)
+        cur2 = con2.cursor()
+    else:
+        print("Error! Two database files shall be input.")
     if args.diff_function:
         diff_function()
     if args.diff_data:
@@ -342,32 +342,29 @@
 def parse_args():
     parser = argparse.ArgumentParser()
 
-    parser.add_argument('-i', '--input',
-                        dest='input_dbs',
-                        nargs='*',
-                        required=True,
-                        metavar='input_dbs',
-                        help='Input two different data base files')
-    parser.add_argument('-a', '--diff_all',
-                        dest='diff_all',
-                        action='store_true',
-                        help='diff summary')
-    parser.add_argument('-f', '--diff_function',
-                        dest='diff_function',
-                        action='store_true',
-                        help='diff function')
-    parser.add_argument('-d', '--diff_data',
-                        dest='diff_data',
-                        action='store_true',
-                        help='diff data')
-    parser.add_argument('-o', '--diff_obj',
-                        dest='diff_obj',
-                        action='store_true',
-                        help='diff object file')
-    parser.add_argument('-l', '--diff_lib',
-                        dest='diff_lib',
-                        action='store_true',
-                        help='diff library')
+    parser.add_argument('based_db', help='based databse')
+    parser.add_argument('compared_db', help='compared databse')
+    opt = parser.add_mutually_exclusive_group(required=True)
+    opt.add_argument('-S', '--diff-Summary',
+                     dest='diff_all',
+                     action='store_true',
+                     help='diff summary')
+    opt.add_argument('-f', '--diff-function',
+                     dest='diff_function',
+                     action='store_true',
+                     help='diff function')
+    opt.add_argument('-d', '--diff-data',
+                     dest='diff_data',
+                     action='store_true',
+                     help='diff data')
+    opt.add_argument('-o', '--diff-obj',
+                     dest='diff_obj',
+                     action='store_true',
+                     help='diff object file')
+    opt.add_argument('-l', '--diff-lib',
+                     dest='diff_lib',
+                     action='store_true',
+                     help='diff library')
 
     args = parser.parse_args()
     return args
diff --git a/code-size-analyze-tool/src/sq.py b/code-size-analyze-tool/src/sq.py
index 11f620a..039563a 100644
--- a/code-size-analyze-tool/src/sq.py
+++ b/code-size-analyze-tool/src/sq.py
@@ -6,8 +6,6 @@
 # ------------------------------------------------------------------------------
 
 import sqlite3
-import os
-import glob
 from xlsxwriter.workbook import Workbook
 
 class SQ(object):
@@ -22,7 +20,8 @@
     - Variables:
       - SQ().armcc     - ARMCLANG option.
       - SQ().gnuarm    - GNUARM option.
-      - SQ().file_path - The map file path which detail information comes from.
+      - SQ().map_file  - The map file path which detail information comes from.
+      - SQ().db_name   - The database file name to be saved.
     """
     def __init__(self):
         """
@@ -30,27 +29,20 @@
         """
         self.gnuarm = False
         self.armcc = False
-        self.file_path = ""
+        self.map_file = ""
+        self.db_name = ""
 
         self.__gnuarm_info = []
         self.__sec_dict = {}
-        self.__delete()
-        self.__con = sqlite3.connect("data.db")
-        self.__cur = self.__con.cursor()
-
-    def __delete(self):
-        """
-        Search and delete the previous database file and excel file.
-        """
-        for infile in glob.glob(os.path.join(os.getcwd(), '*.db')):
-            os.remove(infile)
-        for infile in glob.glob(os.path.join(os.getcwd(), '*.xlsx')):
-            os.remove(infile)
+        self.__excel_name = ""
 
     def __new(self):
         """
         Create tables in a new empty database.
         """
+        self.__con = sqlite3.connect(self.db_name)
+        self.__cur = self.__con.cursor()
+        self.__excel_name = self.db_name +'.xlsx'
         self.__cur.execute('''create table Summary
                              (Code               INT     NOT NULL,
                               RO_data            INT     NOT NULL,
@@ -82,7 +74,7 @@
                               lib_file           TEXT    NOT_NULL);''')
         self.__cur.execute('''create table Library
                              (name               TEXT    NOT NULL,
-                              flashsize          INT     NOT NULL,
+                              size               INT     NOT NULL,
                               ramsize            INT     NOT NULL,
                               code               INT     NOT NULL,
                               rodata             INT     NOT NULL,
@@ -92,8 +84,8 @@
                               Debug              INT     NOT NULL);''')
         self.__cur.execute('''create table Object
                              (name               TEXT    NOT NULL,
-                              library            TEXT    NOT NULL,
-                              flashsize          INT     NOT NULL,
+                              lib_file           TEXT    NOT NULL,
+                              size               INT     NOT NULL,
                               ramsize            INT     NOT NULL,
                               code               INT     NOT NULL,
                               rodata             INT     NOT NULL,
@@ -101,6 +93,9 @@
                               zidata             INT     NOT NULL,
                               incdata            INT     NOT_NULL,
                               Debug              INT     NOT NULL);''')
+        self.__cur.execute('''create table Compiler
+                             (Compiler           TEXT    NOT NULL,
+                              flag               INT     NOT NULL);''')
         if self.gnuarm:
             self.__cur.execute('''create table Unknown
                              (name               TEXT    NOT NULL,
@@ -111,6 +106,12 @@
                               obj_file           TEXT    NOT_NULL,
                               lib_file           TEXT    NOT_NULL);''')
 
+    def __collect_compiler(self):
+        if self.gnuarm:
+            self.__cur.execute("insert into Compiler values (?, ?)", ("gnuarm", 1))
+        if self.armcc:
+            self.__cur.execute("insert into Compiler values (?, ?)", ("armcc", 0))
+
     def __collect_summary(self):
         code_size = ro_data = rw_data = zi_data = flash_size = ram_size = extra_ram = extra_flash = 0
         if self.gnuarm:
@@ -150,7 +151,7 @@
             """
             For Secure image, the TFM_DATA part is loaded from Flash.
             """
-            for line in open(self.file_path, "r"):
+            for line in open(self.map_file, "r"):
                 if line.find("load address") >= 0:
                     extra_flash_addr = int(line.split()[-1] ,16)
                     extra_flash_data = int(line.split()[-4], 16)
@@ -158,7 +159,7 @@
                         flash_size += extra_flash_data
 
         elif self.armcc:
-            for line in open(self.file_path, "r"):
+            for line in open(self.map_file, "r"):
                 if line.find("gram Size: Code=") > 0:
                     content = line.split()
                     code_size = int(content[2].split('=')[1])
@@ -208,7 +209,7 @@
             section_addr = ""
             section_size = 0
             section_pad_size = 0
-            for line in open(self.file_path, "r"):
+            for line in open(self.map_file, "r"):
                 line_idx += 1
 
                 if line.find("Execution Region") > 0:
@@ -284,7 +285,7 @@
 
         elif self.armcc:
             line_idx, line_start = 0, 0
-            for line in open(self.file_path, "r"):
+            for line in open(self.map_file, "r"):
                 line_idx += 1
                 if line.find("Code (inc. data)   RO Data    RW Data    ZI Data      Debug   Library Name") > 0:
                     line_start = line_idx + 1
@@ -325,7 +326,7 @@
                                      0, 0))
         elif self.armcc:
             line_idx, line_start = 0, 0
-            for line in open(self.file_path, "r"):
+            for line in open(self.map_file, "r"):
                 line_idx += 1
                 if line.find("Code (inc. data)   RO Data    RW Data    ZI Data      Debug   Object Name") > 0:
                     line_start = line_idx + 1
@@ -346,7 +347,7 @@
                     else:
                         break
             line_idx, line_start = 0, 0
-            for line in open(self.file_path, "r"):
+            for line in open(self.map_file, "r"):
                 line_idx += 1
                 if line.find("Code (inc. data)   RO Data    RW Data    ZI Data      Debug   Library Member Name") > 0:
                     line_start = line_idx + 1
@@ -355,7 +356,7 @@
                     if len(content) == 7:
                         obj_name = content[6]
                         library_file = ""
-                        for line in open(self.file_path, "r"):
+                        for line in open(self.map_file, "r"):
                             if line.find(obj_name) > 0:
                                 ch_r = line[line.find(obj_name) + len(obj_name)]
                                 ch_l = line[line.find(obj_name) - 1]
@@ -379,7 +380,7 @@
 
     def __get_ram_and_flash_start_addr(self):
         start = False
-        for line in open(self.file_path, "r"):
+        for line in open(self.map_file, "r"):
             if line.find('Memory Configuration') >= 0:
                 start = True
             if line.find('Linker script and memory map') == 0:
@@ -397,7 +398,7 @@
         def get_key_content():
                 start, end, real_start = False, False, False
                 content = ""
-                for line in open(self.file_path, "r"):
+                for line in open(self.map_file, "r"):
                     if line.find('Linker script and memory map') >= 0:
                         start = True
                     if line.find('OUTPUT(') == 0:
@@ -558,7 +559,7 @@
         table_list = ["Summary", "Section", "Library", "Object", "Function", "Data"]
         if self.gnuarm:
             table_list.append("Unknown")
-        workbook = Workbook('data.xlsx')
+        workbook = Workbook(self.__excel_name)
         title_m = workbook.add_format({'bold': True,
                                        'align': 'left',
                                        'font_size': 12})
@@ -603,6 +604,7 @@
         self.__new()
         if self.gnuarm:
             self.__get_info_from_gnuarm_map()
+        self.__collect_compiler()
         self.__collect_summary()
         self.__collect_section()
         self.__collect_library()
diff --git a/code-size-analyze-tool/src/ui.py b/code-size-analyze-tool/src/ui.py
index e555e59..6b5a704 100644
--- a/code-size-analyze-tool/src/ui.py
+++ b/code-size-analyze-tool/src/ui.py
@@ -20,6 +20,7 @@
     - Methods:
       - UI().run()              - Run the UI in terminal.
       - UI.draw_<symbol>_page() - Get the information of specific symbol
+      - UI.open_db()            - Open database.
 
     - Variables:
       - UI().items              - The result searched from database.
@@ -31,6 +32,9 @@
       - UI().section_name       - Specific section name.
       - UI().library_name       - Specific library name.
       - UI().obj_file           - Specific object file name.
+      - UI().db_file            - Database file.
+      - UI().sort               - Database list order: size, name and so on.
+      - UI().order              - Database sort order: DESC and ASC.
     """
 
     def __init__(self):
@@ -45,9 +49,10 @@
         self.gnuarm = False
         self.armcc = False
         self.items = []
-        self.con = sqlite3.connect("data.db")
+        self.db_file = ""
+        self.sort = "size"
+        self.order = "DESC"
 
-        self.__cur = self.con.cursor()
         self.__window = None
         self.__width = 0
         self.__height = 0
@@ -62,6 +67,17 @@
         self.__cmd_func="Enter the function name:"
         self.__cmd_data="Enter the data name:"
 
+    def open_db(self):
+        self.con = sqlite3.connect(self.db_file)
+        self.__cur = self.con.cursor()
+        cursor = self.__cur.execute("select * from Compiler")
+        for row in cursor:
+            compiler = row[1]
+            if compiler == 1:
+                self.gnuarm = True
+            elif compiler == 0:
+                self.armcc = True
+
     def __init_curses(self):
         """
         Setup the curses
@@ -413,7 +429,7 @@
         self.items = ["{:<50}{:<16}{:<16}{:<16}".
                       format("Name", "Size", "Address", "PAD size")]
 
-        cursor = self.__cur.execute("select * from Section ORDER BY size DESC")
+        cursor = self.__cur.execute("select * from Section ORDER BY {} {}".format(self.sort, self.order))
         for row in cursor:
             self.items.append("{:<50}{:<16}{:<16}{:<16}".
                               format(row[0], row[1], row[2], row[3]))
@@ -559,7 +575,7 @@
         Dump library information.
         """
         self.items = [self.__line1]
-        insert_column_line("\t\t\t\t\t\t\tSection libraries")
+        insert_column_line(" " * ((128 - len("Section libraries"))//2) + "Section libraries")
         for s in lib_list:
             if s['Name'].find(".o") > 0:
                 exsit_no_lib_obj = True
@@ -571,7 +587,7 @@
         """
         Dump object file information.
         """
-        insert_column_line("\t\t\t\t\t\t\tSection object files")
+        insert_column_line(" " * ((128 - len("Section object files"))//2) + "Section object files")
         for s in obj_list:
             quick_insert_data_line(s)
         ret = sum_data(obj_list)
@@ -581,8 +597,8 @@
         Dump NOT-IN-LIBRARY object file information.
         """
         if exsit_no_lib_obj:
-            insert_column_line(
-                "\t\t\t\t\t\t\tSection NOT-IN-LIBRARY object files")
+            insert_column_line(" " * ((128 - len("Section NOT-IN-LIBRARY object files"))//2) +
+                "Section NOT-IN-LIBRARY object files")
             tmp_list = []
             for s in lib_list:
                 if s['Name'].find(".o") > 0:
@@ -600,14 +616,14 @@
                               format(self.section_name, row[1], total_flash_size, total_ram_size, row[3]))
             break
         self.items.insert(0, self.__line2)
-        self.items.insert(0, "\t\t\t\t\t\t\tSection information")
+        self.items.insert(0, " " * ((128 - len("Section information"))//2) + "Section information")
         self.items.insert(0, self.__line1)
 
         """
         Dump detail information of the section.
         """
         index = 4 * ' '
-        self.items.append("\t\t\t\t\t\t\tDetail information")
+        self.items.append(" " * ((128 - len("Detail information"))//2) + "Detail information")
         self.items.append(self.__line2)
         for s in lib_list:
             self.items.append("{} Code Size = {} RO Data = {} RW Data = {} ZI Data = {}".
@@ -617,10 +633,12 @@
                     self.items.append(index + "{} Code Size = {} RO Data = {} RW Data = {} ZI Data = {}".format(
                         t['Name'], t['Code'], t['RO'], t['RW'], t['ZI']))
                     count = 0
-                    cursor = self.__cur.execute("select * from Function WHERE section = '{}' and lib_file = '{}' and obj_file = '{}' ORDER BY size DESC".
+                    cursor = self.__cur.execute("select * from Function WHERE section = '{}' and lib_file = '{}' and obj_file = '{}' ORDER BY {} {}".
                                                 format(self.section_name,
                                                        s['Name'],
-                                                       t['Name']))
+                                                       t['Name'],
+                                                       self.sort,
+                                                       self.order))
                     for row in cursor:
                         if row and count == 0:
                             self.items.append(index * 2 + "Code size = {}".
@@ -631,11 +649,13 @@
 
                     def get_certain_data(type_name, s, t):
                         count = 0
-                        cursor = self.__cur.execute("select * from Data WHERE section = '{}' and lib_file = '{}' and obj_file = '{}'  and type = '{}' ORDER BY size DESC".
+                        cursor = self.__cur.execute("select * from Data WHERE section = '{}' and lib_file = '{}' and obj_file = '{}'  and type = '{}' ORDER BY {} {}".
                                                     format(self.section_name,
                                                            s['Name'],
                                                            t['Name'],
-                                                           type_name))
+                                                           type_name,
+                                                           self.sort,
+                                                           self.order))
                         for row in cursor:
                             if row and count == 0:
                                 self.items.append(index * 2 + "{} Data = {}".
@@ -648,6 +668,7 @@
                     get_certain_data('RW', s, t)
                     get_certain_data('ZI', s, t)
             self.items.append(self.__line2)
+        self.items[-1] = self.__line1
 
     def draw_section_func(self):
         self.items = ["{:<50}{:<32}{:<10}{:<16}{:<40}{:<40}".
@@ -657,8 +678,8 @@
                              "Address",
                              "Object File",
                              "Library")]
-        cursor = self.__cur.execute("select * from Function WHERE section = '{}' ORDER BY size DESC".
-                                  format(self.section_name))
+        cursor = self.__cur.execute("select * from Function WHERE section = '{}' ORDER BY {} {}".
+                                  format(self.section_name, self.sort, self.order))
         for row in cursor:
             self.items.append("{:<50}{:<32}{:<10}{:<16}{:<40}{:<40}".
                               format(row[0], row[1], row[2], row[3], row[4], row[5]))
@@ -673,8 +694,8 @@
                              "Object File",
                              "Library")]
 
-        cursor = self.__cur.execute("select * from Data WHERE section = '{}' ORDER BY size DESC".
-                                  format(self.section_name))
+        cursor = self.__cur.execute("select * from Data WHERE section = '{}' ORDER BY {} {}".
+                                  format(self.section_name, self.sort, self.order))
         for row in cursor:
             data_name = row[0]
             if len(data_name) >= 50:
@@ -718,7 +739,7 @@
                              "Debug")]
 
         cursor = self.__cur.execute(
-            "select * from Library ORDER BY flashsize DESC")
+            "select * from Library ORDER BY {} {}".format(self.sort, self.order))
         for row in cursor:
             self.items.append("{:<50}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}".
                               format(row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]))
@@ -761,8 +782,8 @@
                                  "Inc. data"))
         self.items.append(self.__line2)
 
-        cursor = self.__cur.execute("select * from Object WHERE library = '{}' ORDER BY flashsize DESC".
-                                  format(self.library_name))
+        cursor = self.__cur.execute("select * from Object WHERE lib_file = '{}' ORDER BY {} {}".
+                                  format(self.library_name, self.sort, self.order))
         for row in cursor:
             self.items.append("{:<50}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}".
                               format(row[0], row[2], row[3], row[4], row[5], row[6], row[7], row[8]))
@@ -770,8 +791,8 @@
         """
         Draw functions.
         """
-        cursor = self.__cur.execute("select * from Function WHERE lib_file = '{}' ORDER BY size DESC".
-                                  format(self.library_name))
+        cursor = self.__cur.execute("select * from Function WHERE lib_file = '{}' ORDER BY {} {}".
+                                  format(self.library_name, self.sort, self.order))
         for row in cursor:
             if not flag:
                 self.__quick_append()
@@ -782,22 +803,22 @@
         """
         Draw RO data.
         """
-        cursor = self.__cur.execute("select * from Data WHERE type = 'RO' and lib_file = '{}' ORDER BY size DESC".
-                                  format(self.library_name))
+        cursor = self.__cur.execute("select * from Data WHERE type = 'RO' and lib_file = '{}' ORDER BY {} {}".
+                                  format(self.library_name, self.sort, self.order))
         self.__quick_append_data(cursor)
 
         """
         Draw RW data.
         """
-        cursor = self.__cur.execute("select * from Data WHERE type = 'RW' and lib_file = '{}' ORDER BY size DESC".
-                                  format(self.library_name))
+        cursor = self.__cur.execute("select * from Data WHERE type = 'RW' and lib_file = '{}' ORDER BY {} {}".
+                                  format(self.library_name, self.sort, self.order))
         self.__quick_append_data(cursor)
 
         """
         Draw ZI data.
         """
-        cursor = self.__cur.execute("select * from Data WHERE type = 'ZI' and lib_file = '{}' ORDER BY size DESC".
-                                  format(self.library_name))
+        cursor = self.__cur.execute("select * from Data WHERE type = 'ZI' and lib_file = '{}' ORDER BY {} {}".
+                                  format(self.library_name, self.sort, self.order))
         self.__quick_append_data(cursor)
         self.items.append(self.__line1)
 
@@ -813,13 +834,12 @@
                              "ZI data",
                              "Inc. data",
                              "Debug")]
-        cursor = self.__cur.execute(
-            "select * from Object WHERE library = 'no library' ORDER BY flashsize DESC")
+        cursor = self.__cur.execute("select * from Object WHERE lib_file = 'no library' ORDER BY {} {}".format(self.sort, self.order))
         for row in cursor:
             self.items.append("{:<50}{:<50}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}".
                               format(row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9]))
         cursor = self.__cur.execute(
-            "select * from Object WHERE library != 'no library' ORDER BY flashsize DESC")
+            "select * from Object WHERE lib_file != 'no library' ORDER BY {} {}".format(self.sort, self.order))
         for row in cursor:
             self.items.append("{:<50}{:<50}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}".
                               format(row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9]))
@@ -845,8 +865,8 @@
                               format(row[0], row[2], row[3], row[4], row[5], row[6], row[7], row[8]))
             break
 
-        cursor = self.__cur.execute("select * from Function WHERE obj_file = '{}' ORDER BY size DESC".
-                                  format(self.obj_file))
+        cursor = self.__cur.execute("select * from Function WHERE obj_file = '{}' ORDER BY {} {}".
+                                  format(self.obj_file, self.sort, self.order))
         for row in cursor:
             if not flag:
                 self.__quick_append()
@@ -854,16 +874,16 @@
                               format(row[0], row[1], row[2], "Code", row[4]))
             flag = True
 
-        cursor = self.__cur.execute("select * from Data WHERE type = 'RO' and obj_file = '{}' ORDER BY size DESC".
-                                  format(self.obj_file))
+        cursor = self.__cur.execute("select * from Data WHERE type = 'RO' and obj_file = '{}' ORDER BY {} {}".
+                                  format(self.obj_file, self.sort, self.order))
         self.__quick_append_data(cursor)
 
-        cursor = self.__cur.execute("select * from Data WHERE type = 'RW' and obj_file = '{}' ORDER BY size DESC".
-                                  format(self.obj_file))
+        cursor = self.__cur.execute("select * from Data WHERE type = 'RW' and obj_file = '{}' ORDER BY {} {}".
+                                  format(self.obj_file, self.sort, self.order))
         self.__quick_append_data(cursor)
 
-        cursor = self.__cur.execute("select * from Data WHERE type = 'ZI' and obj_file = '{}' ORDER BY size DESC".
-                                  format(self.obj_file))
+        cursor = self.__cur.execute("select * from Data WHERE type = 'ZI' and obj_file = '{}' ORDER BY {} {}".
+                                  format(self.obj_file, self.sort, self.order))
         self.__quick_append_data(cursor)
         self.items.append(self.__line1)
 
@@ -880,8 +900,7 @@
             cursor = self.__cur.execute("select * from Function WHERE name LIKE '%{}%'".
                                       format(search_func))
         else:
-            cursor = self.__cur.execute(
-                "select * from Function ORDER BY size DESC")
+            cursor = self.__cur.execute("select * from Function ORDER BY {} {}".format(self.sort, self.order))
         for row in cursor:
             self.items.append("{:<50}{:<50}{:<10}{:<16}{:<40}{:<40}".
                               format(row[0], row[1], row[2], row[3], row[4], row[5]))
@@ -917,7 +936,7 @@
             cursor = self.__cur.execute("select * from Data WHERE name LIKE '%{}%'".
                                       format(search_data))
         else:
-            cursor = self.__cur.execute("select * from Data ORDER BY size DESC")
+            cursor = self.__cur.execute("select * from Data ORDER BY {} {}".format(self.sort, self.order))
         for row in cursor:
             data_name = row[0]
             if len(data_name) >= 50:
@@ -948,6 +967,7 @@
         """
         Continue running the TUI until get interrupted
         """
+        self.open_db()
         self.__init_curses()
         try:
             self.__draw_page()
@@ -955,4 +975,5 @@
         except KeyboardInterrupt:
             pass
         finally:
+            self.con.close()
             curses.endwin()