131 lines
5.3 KiB
Python
131 lines
5.3 KiB
Python
|
|
#!/usr/bin/env python3
|
|||
|
|
# -*- coding: utf-8 -*-
|
|||
|
|
|
|||
|
|
"""
|
|||
|
|
Шестой проход КВС — сортировка CSV по адресам
|
|||
|
|
- Сортирует все записи по числовому значению адреса
|
|||
|
|
- Записи с адресом "BSS" помещает в конец (после всех реальных адресов)
|
|||
|
|
- Обеспечивает правильный порядок байтов в итоговом ELF-файле
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
import sys
|
|||
|
|
import csv
|
|||
|
|
|
|||
|
|
|
|||
|
|
def get_addr_value(addr_str):
|
|||
|
|
"""
|
|||
|
|
Преобразует адрес в число для сортировки
|
|||
|
|
BSS и пустые адреса отправляются в конец (большое число)
|
|||
|
|
"""
|
|||
|
|
if not addr_str or addr_str == '':
|
|||
|
|
return 999999999 # Пустые адреса в конец
|
|||
|
|
if addr_str == 'BSS':
|
|||
|
|
return 999999999 # BSS в самый конец (после всех реальных адресов)
|
|||
|
|
if addr_str.startswith('0x'):
|
|||
|
|
try:
|
|||
|
|
return int(addr_str, 16)
|
|||
|
|
except ValueError:
|
|||
|
|
return 999999999
|
|||
|
|
return 999999999
|
|||
|
|
|
|||
|
|
|
|||
|
|
def sort_csv_by_address(input_csv, output_csv):
|
|||
|
|
"""
|
|||
|
|
Сортирует CSV по адресам (числовым значениям)
|
|||
|
|
BSS и пустые адреса помещаются в конец
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
input_csv: входной CSV файл
|
|||
|
|
output_csv: выходной CSV файл
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
print(f"\n=== ШЕСТОЙ ПРОХОД КВС: сортировка CSV ===")
|
|||
|
|
print(f"Чтение: {input_csv}")
|
|||
|
|
|
|||
|
|
# Читаем CSV
|
|||
|
|
with open(input_csv, 'r', encoding='utf-8') as f:
|
|||
|
|
reader = csv.DictReader(f, delimiter=';')
|
|||
|
|
fieldnames = reader.fieldnames
|
|||
|
|
rows = list(reader)
|
|||
|
|
|
|||
|
|
print(f"Найдено записей: {len(rows)}")
|
|||
|
|
|
|||
|
|
# Подсчёт статистики до сортировки
|
|||
|
|
bss_count = sum(1 for row in rows if row.get('адрес') == 'BSS')
|
|||
|
|
empty_count = sum(1 for row in rows if not row.get('адрес') or row.get('адрес') == '')
|
|||
|
|
normal_count = len(rows) - bss_count - empty_count
|
|||
|
|
|
|||
|
|
print(f" Обычных записей (с числовыми адресами): {normal_count}")
|
|||
|
|
print(f" BSS-записей: {bss_count}")
|
|||
|
|
print(f" Пустых адресов: {empty_count}")
|
|||
|
|
|
|||
|
|
# Сортировка
|
|||
|
|
def sort_key(row):
|
|||
|
|
addr = row.get('адрес', '')
|
|||
|
|
value = get_addr_value(addr)
|
|||
|
|
return (value, 0)
|
|||
|
|
|
|||
|
|
rows.sort(key=sort_key)
|
|||
|
|
|
|||
|
|
# Записываем отсортированный CSV
|
|||
|
|
with open(output_csv, 'w', newline='', encoding='utf-8') as f:
|
|||
|
|
writer = csv.DictWriter(f, fieldnames=fieldnames, delimiter=';', restval='')
|
|||
|
|
writer.writeheader()
|
|||
|
|
writer.writerows(rows)
|
|||
|
|
|
|||
|
|
print(f"\n✅ CSV отсортирован и сохранён: {output_csv}")
|
|||
|
|
|
|||
|
|
# Показываем первые 10 адресов для проверки
|
|||
|
|
print("\n📊 Первые 10 адресов после сортировки:")
|
|||
|
|
for i, row in enumerate(rows[:10]):
|
|||
|
|
addr = row.get('адрес', '')
|
|||
|
|
seg = row.get('сегмент', '')
|
|||
|
|
source = row.get('исходная_команда', '')[:30]
|
|||
|
|
print(f" {i+1:2d}. {addr:12s} [{seg:10s}] {source}")
|
|||
|
|
|
|||
|
|
# Показываем последние 5 адресов (должны быть BSS)
|
|||
|
|
if bss_count > 0:
|
|||
|
|
print("\n📊 Последние 5 записей (BSS в конце):")
|
|||
|
|
for i, row in enumerate(rows[-5:]):
|
|||
|
|
addr = row.get('адрес', '')
|
|||
|
|
seg = row.get('сегмент', '')
|
|||
|
|
source = row.get('исходная_команда', '')[:30]
|
|||
|
|
print(f" {len(rows)-5+i+1:2d}. {addr:12s} [{seg:10s}] {source}")
|
|||
|
|
|
|||
|
|
# Проверка: убеждаемся, что после сортировки нет числовых адресов после BSS
|
|||
|
|
found_bss = False
|
|||
|
|
for row in rows:
|
|||
|
|
addr = row.get('адрес', '')
|
|||
|
|
if addr == 'BSS':
|
|||
|
|
found_bss = True
|
|||
|
|
elif found_bss and addr and addr != '' and addr.startswith('0x'):
|
|||
|
|
print(f"\n⚠️ ВНИМАНИЕ: Найден числовой адрес {addr} после BSS!")
|
|||
|
|
print(" Это может указывать на проблему в данных.")
|
|||
|
|
break
|
|||
|
|
else:
|
|||
|
|
if found_bss:
|
|||
|
|
print("\n✅ Проверка пройдена: все BSS-записи в конце, числовых адресов после них нет.")
|
|||
|
|
else:
|
|||
|
|
print("\n✅ BSS-записей не найдено.")
|
|||
|
|
|
|||
|
|
|
|||
|
|
def main():
|
|||
|
|
if len(sys.argv) not in (2, 3):
|
|||
|
|
print("Использование: python kvs_pass6.py <входной.csv> [выходной.csv]")
|
|||
|
|
print(" Если выходной не указан, перезаписывается входной файл")
|
|||
|
|
sys.exit(1)
|
|||
|
|
|
|||
|
|
input_csv = sys.argv[1]
|
|||
|
|
|
|||
|
|
# Определяем выходной файл
|
|||
|
|
if len(sys.argv) >= 3:
|
|||
|
|
output_csv = sys.argv[2]
|
|||
|
|
else:
|
|||
|
|
# По умолчанию: перезаписываем исходный файл
|
|||
|
|
output_csv = input_csv
|
|||
|
|
|
|||
|
|
sort_csv_by_address(input_csv, output_csv)
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
main()
|