comments macro in vs2008

本文介绍了一个简单的VBA子程序,用于在文档中插入当前的日期和时间作为注释。此子程序检查特定条件并格式化时间显示,确保注释易于阅读。通过选中文档的一部分并运行此子程序,它会在选中的位置插入带有当前日期和时间的注释。

    Sub AddCommentDateTime()
        'DESCRIPTION: Add current date&&time as comment
        Dim nHour = DateAndTime.Now.Hour
        Dim strMinute = DateAndTime.Now.Minute

        If nHour > 9 And nHour < 16 And len(strMinute) = 1 Then
            strMinute = "0" + strMinute
        End If
        Dim str As String
        str = "/* nick " & Right(CStr(Year(Now)), 2) & "-" & CStr(Month(Now)) & "-" & CStr(Day(Now)) & " " _
         & CStr(nHour) & ":" & strMinute & "  */"


        Dim sel = CType(DTE.ActiveDocument.Selection(), EnvDTE.TextSelection)
        sel.Text = str
        sel.WordLeft(False, 1)
        sel.CharLeft(False, 1)

    End Sub

import json import os import re import logging import sys from pathlib import Path from shutil import copy2 from datetime import datetime from utils import resource_path # ------------------------------- # 日志配置 # ------------------------------- PROJECT_ROOT = Path(__file__).parent.parent.resolve() LOG_DIR = PROJECT_ROOT / "output" / "log" LOG_DIR.mkdir(parents=True, exist_ok=True) LOG_FILE = LOG_DIR / f"range_sync_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log" class CLMRangeSynchronizer: def __init__(self, c_file_path=None, dry_run=False,config_path="config/config.json"): self.logger = logging.getLogger(__name__) # === Step 1: 使用 resource_path 解析所有路径 === self.config_file_path = resource_path(config_path) logging.info(f"配置文件: {self.config_file_path}") if not os.path.exists(self.config_file_path): raise FileNotFoundError(f"配置文件不存在: {self.config_file_path}") try: with open(self.config_file_path, 'r', encoding='utf-8') as f: self.config = json.load(f) print(f"配置文件已加载: {self.config_file_path}") except json.JSONDecodeError as e: raise ValueError(f"配置文件格式错误,JSON 解析失败: {self.config_file_path}") from e except Exception as e: raise RuntimeError(f"读取配置文件时发生未知错误: {e}") from e self.dry_run = dry_run if c_file_path is None: # 使用内置默认 C 文件(被打包进 exe 的) if "target_c_file" not in self.config: raise KeyError(" config 文件缺少 'target_c_file' 字段") internal_c_path = self.config["target_c_file"] logging.info(f"使用内置 C 文件: {internal_c_path}") self.c_file_path = Path(resource_path(internal_c_path)) self._is_internal_c_file = True else: # 用户传入自定义路径 self.c_file_path = Path(c_file_path) self._is_internal_c_file = False if not self.c_file_path.exists(): raise FileNotFoundError(f"找不到 C 源文件: {self.c_file_path}") self.used_ranges = [] self.array_macros = {} # array_name -> [RANGE_xxx, ...] # self.array_macros = { # "channel_ranges_2g_20m": [ # "RANGE_2G_20M_1_11", # "RANGE_2G_20M_6_6" # ], # "channel_ranges_5g_80m": [ # "RANGE_5G_80M_36_48", # "RANGE_5G_80M_149_161" # ] # } self.struct_entries = {} # array_name -> [{"low": int, "high": int}, ...] # self.struct_entries = { # "channel_ranges_2g_20m": [ # {"low": 1, "high": 11}, # {"low": 6, "high": 6} # ], # "channel_ranges_5g_80m": [ # {"low": 36, "high": 48}, # {"low": 149, "high": 161} # ] # } self.enum_to_index = {} # RANGE_xxx -> index (from enum) if "STR_CHANNEL_RANGE" not in self.config: raise KeyError(" config 文件缺少 'STR_CHANNEL_RANGE' 字段") self.start_marker = self.config["STR_CHANNEL_RANGE"] if "END_CHANNEL_RANGE" not in self.config: raise KeyError(" config 文件缺少 'END_CHANNEL_RANGE' 字段") self.end_marker = self.config["END_CHANNEL_RANGE"] def offset_to_lineno(self, content: str, offset: int) -> int: """将字符偏移量转换为行号(从1开始)""" return content.count('\n', 0, offset) + 1 def load_config(self): """加载并解析 config.json""" with open(self.config_file_path, 'r', encoding='utf-8') as f: data = json.load(f) if "used_ranges" not in data: raise KeyError(" config 文件缺少 'used_ranges' 字段") valid_ranges = [] for item in data["used_ranges"]: if isinstance(item, str) and re.match(r'^RANGE_[\w\d_]+_\d+_\d+$', item): valid_ranges.append(item) else: self.logger.warning(f"跳过无效项: {item}") self.used_ranges = sorted(set(valid_ranges)) self.logger.info(f"已从 {self.config_file_path} 加载 {len(self.used_ranges)} 个有效 RANGE 宏") def parse_c_arrays(self): """解析 C 文件中的 channel_ranges_xxx[] 数组 和 enum range_xxx""" content = self.c_file_path.read_text(encoding='utf-8') start_idx = content.find(self.start_marker) end_idx = content.find(self.end_marker) if start_idx == -1 or end_idx == -1: raise ValueError("未找到 CHANNEL RANGES 注释锚点") block = content[start_idx:end_idx] start_line = self.offset_to_lineno(content, start_idx) end_line = self.offset_to_lineno(content, end_idx) self.logger.info( f"找到标记范围:{self.start_marker} → 第 {start_line} 行, {self.end_marker} → 第 {end_line} 行") # === 1. 解析数组:static const struct clm_channel_range xxx[] = { ... }; array_pattern = re.compile( r'static\s+const\s+struct\s+clm_channel_range\s+(channel_ranges_[\w\d]+)\s*\[\s*\]\s*=\s*\{(.*?)\}\s*;', re.DOTALL | re.MULTILINE ) for array_name, body in array_pattern.findall(block): entries = [] for low, high in re.findall(r'\{\s*(\d+)\s*,\s*(\d+)\s*\}', body): entries.append({"low": int(low), "high": int(high)}) self.struct_entries[array_name] = entries self.array_macros[array_name] = [] # 先留空,后续从 enum 填充 self.logger.info(f" 解析数组 {array_name}: {len(entries)} 个范围项") # === 2. 解析枚举:enum range_xxx { RANGE_A = 0, ... } enum_pattern = re.compile(r'enum\s+range_([a-z\d_]+)\s*\{([^}]*)\}', re.DOTALL | re.IGNORECASE) if enum_pattern.search(block): self.logger.info("block 中存在匹配的 enum range") else: self.logger.info("未找到匹配的 enum range") #self.logger.info(f"block 片段预览:\n{block[:2500]}") for match in enum_pattern.finditer(block): suffix = match.group(1) # 如 '2g_40m' enum_body = match.group(2) array_name = f"channel_ranges_{suffix}" #self.logger.info(f" 解析 {enum_body} {suffix}") if array_name not in self.struct_entries: self.logger.warning(f" 找到 enum {match.group(0)[:30]}... 但无对应数组") continue # 提取 RANGE_xxx = N for macro, idx_str in re.findall(r'(RANGE_[\w\d_]+)\s*=\s*(\d+)', enum_body): idx = int(idx_str) if idx >= len(self.struct_entries[array_name]): self.logger.warning(f" 索引越界: {macro} = {idx} > 数组长度 {len(self.struct_entries[array_name])}") continue self.enum_to_index[macro] = idx if macro not in self.array_macros[array_name]: self.array_macros[array_name].append(macro) #self.logger.info(f" 关联 {macro} → {array_name}[{idx}]") self.logger.info(f" 总共建立 {len(self.enum_to_index)} 个宏与数组项的映射关系") def get_array_name_for_range(self, range_macro): """根据 RANGE 宏推断应属于哪个数组""" match = re.match(r'RANGE_([0-9]+[A-Za-z])_([0-9]+)M_', range_macro, re.IGNORECASE) if not match: self.logger.warning(f"无法推断数组名: {range_macro}") return None band = match.group(1).lower() # '2g' bw = match.group(2) # '20' return f"channel_ranges_{band}_{bw}m" def extract_channels_from_macro(self, macro): """ 从宏字符串中提取信道范围。 Args: macro (str): 格式如 RANGE_2G_20M_1_11 Returns: tuple: (low, high) 或 (None, None) """ match = re.search(r'_(\d+)_(\d+)$', macro) if match: low = int(match.group(1)) high = int(match.group(2)) return low, high self.logger.warning(f"宏格式错误,无法提取信道: {macro}") return None, None def validate_and_repair(self): """确保每个 used_range 都在正确的数组中""" modified = False changes = [] for range_macro in self.used_ranges: array_name = self.get_array_name_for_range(range_macro) if not array_name: self.logger.warning(f"无法识别数组类型,跳过: {range_macro}") continue # --- 检查宏是否已在 enum 映射中 --- existing_idx = None for macro, idx in self.enum_to_index.items(): if macro == range_macro and self.get_array_name_for_range(macro) == array_name: existing_idx = idx break if existing_idx is None: # 新宏,需分配新索引 next_idx = len(self.struct_entries[array_name]) low, high = self.extract_channels_from_macro(range_macro) if low is not None and high is not None: self.struct_entries[array_name].append({"low": low, "high": high}) #self.logger.info(f"数组{array_name}: {self.struct_entries[array_name]}") self.array_macros[array_name].append(range_macro) #self.logger.info(f"枚举: {array_name}: {self.array_macros[array_name]}") self.enum_to_index[range_macro] = next_idx changes.append(f"扩展枚举: {range_macro} → {{{low}, {high}}} (index={next_idx})") #self.logger.info(f"扩展枚举: {range_macro} → {{{low}, {high}}} (index={next_idx})") modified = True else: self.logger.warning(f"无法解析信道范围: {range_macro}") if modified and not self.dry_run: self._write_back_in_block() self.logger.info("C 文件已更新") elif modified and self.dry_run: self.logger.info("DRY-RUN MODE: 有变更但不会写入文件") else: self.logger.info(" 所有 RANGE 已存在,无需修改") if modified: self.logger.info(f" 共需添加 {len(changes)} 项:\n" + "\n".join(f" → {ch}" for ch in changes)) return modified def _infer_array_from_enum(self, enum_decl): """从 enum 声明推断对应的数组名""" match = re.search(r'enum\s+range_([a-z\d_]+)', enum_decl) if match: return f"channel_ranges_{match.group(1)}" return None def _format_array_body(self, structs, indent=" "): """格式化结构体数组内容,每行最多4个,数字右对齐""" items = [f"{{ {s['low']:>2d}, {s['high']:>2d} }}" for s in structs] lines = [] for i in range(0, len(items), 4): group = items[i:i + 4] lines.append(indent + ", ".join(group)) return "\n".join(lines) def _write_back_in_block(self): """安全地一次性更新 C 文件中的数组和枚举定义""" if self.dry_run: self.logger.info("DRY-RUN: 跳过写入文件") return try: content = self.c_file_path.read_text(encoding='utf-8') start_idx = content.find(self.start_marker) end_idx = content.find(self.end_marker) + len(self.end_marker) if start_idx == -1 or end_idx == -1: raise ValueError("未找到 CHANNEL RANGES 标记块") header = content[:start_idx] footer = content[end_idx:] block = content[start_idx:end_idx] replacements = [] # (start, end, replacement) # === 工具函数:移除注释避免误匹配 === def remove_comments(text): text = re.sub(r'//.*$', '', text, flags=re.MULTILINE) text = re.sub(r'/\*.*?\*/', '', text, flags=re.DOTALL) return text # === 1. 更新 channel_ranges_xxx[] 数组:只在末尾添加新项 === array_pattern = re.compile( r'(\b(channel_ranges_[\w\d]+)\s*\[\s*\]\s*=\s*\{)(.*?)(\}\s*;\s*)', re.DOTALL | re.MULTILINE ) matches = list(array_pattern.finditer(block)) self.logger.info(f" 找到 {len(matches)} 个 channel_ranges 数组") for i, match in enumerate(matches): self.logger.info(f" 匹配 {i + 1}: 数组名={match.group(2)}, 起始位置={match.start()}") for match in array_pattern.finditer(block): array_name = match.group(2) if array_name not in self.struct_entries: self.logger.warning(f" 未找到 {array_name} 数组") continue structs = self.struct_entries[array_name] body_content = match.group(3) # 直接就是 {} 中间的原始内容(含空格换行) original_end = match.end() # 不变,仍是整个声明结束位置 self.logger.info(f" 数组 {array_name} 内容: {body_content}") # 提取第一行缩进(用于新行) first_line = body_content.split('\n')[0] if body_content.strip() else "" indent_match = re.match(r'^(\s*)', first_line) indent = indent_match.group(1) if indent_match else " " # === 智能插入 {low, high}, 条目(支持同行追加 & 对齐)=== existing_items = [] item_pattern = r'\{\s*(\d+)\s*,\s*(\d+)\s*\}' for m in re.finditer(item_pattern, body_content): low, high = int(m.group(1)), int(m.group(2)) existing_items.append((low, high)) all_matches = list(re.finditer(item_pattern, body_content)) if not all_matches: insert_pos_in_body = len(body_content) else: last_match = all_matches[-1] close_brace_pos = body_content.find('}', last_match.start()) insert_pos_in_body = close_brace_pos + 2 if close_brace_pos != -1 else last_match.end() inserted_count = len(existing_items) if inserted_count >= len(structs): continue new_item = structs[inserted_count] low, high = new_item['low'], new_item['high'] if (low, high) in existing_items: self.logger.warning(f"已存在 {low}, {high} 项,跳过") continue # 分析最后一行用于格式继承 lines = [line for line in body_content.split('\n') if line.strip()] last_line = lines[-1] if lines else "" # 推断缩进和对齐位置 indent_match = re.match(r'^(\s*)', last_line) if last_line else None line_indent = (indent_match.group(1) if indent_match else "") if last_line else " " expanded_last = last_line.expandtabs(4) if last_line else "" first_struct_match = re.search(r'\{', remove_comments(last_line)) if last_line else None if first_struct_match: raw_before = last_line[:first_struct_match.start()] expanded_before = raw_before.expandtabs(4) target_struct_start_col = len(expanded_before) else: target_struct_start_col = len(line_indent.replace('\t', ' ')) # 计算当前行已有多少个结构体 clean_last = remove_comments(last_line) if last_line else "" visible_structs = len(re.findall(r'\{\s*\d+\s*,\s*\d+\s*\}', clean_last)) MAX_PER_LINE = 8 formatted_item = f"{{ {low:>2d}, {high:>2d} }}" # 决定插入方式 if visible_structs < MAX_PER_LINE and last_line.strip(): # 同行追加 insertion = f" {formatted_item}," else: # 换行对齐 raw_indent_len = len(line_indent.replace('\t', ' ')) leading_spaces = max(0, target_struct_start_col - raw_indent_len) padding = ' ' * leading_spaces insertion = f"\n{line_indent}{padding}{formatted_item}," # 记录插入点 insert_offset_in_block = match.start(3) + insert_pos_in_body replacements.append((insert_offset_in_block, insert_offset_in_block, insertion)) self.logger.info(f"插入: {insertion.strip()} → 偏移 {insert_offset_in_block}") range_macro = f"RANGE_{array_name.upper().replace('CHANNEL_RANGES_', '').replace('_', '_')}_{low}_{high}" self.logger.info(f"扩展数组: {range_macro} → {{{low}, {high}}} (index={inserted_count})") # === 2. 更新 enum range_xxx:精确继承上一行宏名左对齐与 '=' 对齐 === enum_pattern = re.compile(r'(enum\s+range_[\w\d_]+\s*\{)([^}]*)\}\s*;', re.DOTALL) for match in enum_pattern.finditer(block): enum_name_match = re.search(r'range_([a-zA-Z0-9_]+)', match.group(0)) if not enum_name_match: continue inferred_array = f"channel_ranges_{enum_name_match.group(1)}" if inferred_array not in self.array_macros: continue macro_list = self.array_macros[inferred_array] enum_body = match.group(2) # 解析已有宏及其值 existing_macros = dict(re.findall(r'(RANGE_[\w\d_]+)\s*=\s*(\d+)', remove_comments(enum_body))) next_id = len(existing_macros) if next_id >= len(macro_list): continue new_macro = macro_list[next_id] # 获取非空行 lines = [line for line in enum_body.split('\n') if line.strip()] last_line = lines[-1] if lines else "" if not last_line.strip(): # fallback 缩进 line_indent = " " target_macro_start_col = 4 target_eq_col = 32 else: indent_match = re.match(r'^(\s*)', last_line) line_indent = indent_match.group(1) if indent_match else " " # 展开 tab(统一按 4 空格处理) expanded_last = last_line.expandtabs(4) # 提取第一个 RANGE_xxx 宏名 first_macro_match = re.search(r'RANGE_[\w\d_]+', remove_comments(last_line)) if not first_macro_match: target_macro_start_col = len(line_indent) target_eq_col = 32 else: macro_text = first_macro_match.group(0) macro_start = first_macro_match.start() # 计算视觉起始列(基于展开后的字符串) raw_before = last_line[:macro_start] expanded_before = raw_before.expandtabs(4) target_macro_start_col = len(expanded_before) # 找第一个 "=" 的视觉列 eq_match = re.search(r'=\s*\d+', last_line[macro_start:]) if eq_match: eq_abs_start = macro_start + eq_match.start() raw_eq_part = last_line[:eq_abs_start] expanded_eq_part = raw_eq_part.expandtabs(4) target_eq_col = len(expanded_eq_part) else: # fallback target_eq_col = target_macro_start_col + len(macro_text) + 8 # 现在我们知道: # - 宏名应该从第 target_macro_start_col 列开始(视觉) # - `=` 应该出现在 target_eq_col 列 # 计算当前宏名需要多少前置空格才能对齐 current_visual_len = len(new_macro.replace('\t', ' ')) padding_to_eq = max(1, target_eq_col - target_macro_start_col - current_visual_len) full_padding = ' ' * padding_to_eq formatted_new = f"{new_macro}{full_padding}= {next_id}" # 判断是否同行追加(最多 4 个) clean_last = remove_comments(last_line) visible_macros = len(re.findall(r'RANGE_[\w\d_]+', clean_last)) if visible_macros < 4 and last_line.strip(): # 同行追加:前面加两个空格分隔 separator = " " updated_content = last_line + separator + formatted_new + "," new_body = enum_body.rsplit(last_line, 1)[0] + updated_content else: # 换行:使用原始 indent 开头,然后补足到 target_macro_start_col raw_indent_len = len(line_indent.replace('\t', ' ')) leading_spaces_needed = max(0, target_macro_start_col - raw_indent_len) prefix_padding = ' ' * leading_spaces_needed new_line = f"{line_indent}{prefix_padding}{formatted_new}," trailing = enum_body.rstrip() maybe_comma = "," if not trailing.endswith(',') else "" new_body = f"{trailing}{maybe_comma}\n{new_line}" # 重建 enum new_enum = f"{match.group(1)}{new_body}\n}};" replacements.append((match.start(), match.end(), new_enum)) self.logger.info(f"扩展枚举: {new_macro} = {next_id}") # === 应用替换:倒序防止 offset 错乱 === replacements.sort(key=lambda x: x[0], reverse=True) result_block = block for start, end, r in replacements: result_block = result_block[:start] + r + result_block[end:] # 写回前备份 backup_path = self.c_file_path.with_suffix('.c.bak') copy2(self.c_file_path, backup_path) self.logger.info(f"已备份 → {backup_path}") # 写入新内容 self.c_file_path.write_text(header + result_block + footer, encoding='utf-8') self.logger.info(f" 成功保存修改: {self.c_file_path}") except Exception as e: self.logger.error(f"写回文件失败: {e}", exc_info=True) raise def run(self): self.logger.info("开始同步 CLM RANGE 定义...") try: self.load_config() self.parse_c_arrays() was_modified = self.validate_and_repair() if was_modified: if self.dry_run: self.logger.info(" 预览模式:检测到变更,但不会写入文件") else: self.logger.info(" 同步完成:已成功更新 C 文件") else: self.logger.info(" 所有 RANGE 已存在,无需修改") return was_modified except Exception as e: self.logger.error(f" 同步失败: {e}", exc_info=True) raise def main(): logging.basicConfig( level=logging.INFO, format='%(asctime)s [%(levelname)s] %(name)s: %(message)s', handlers=[ logging.FileHandler(LOG_FILE, encoding='utf-8'), logging.StreamHandler(sys.stdout) ], force=True ) logger = logging.getLogger(__name__) # 固定配置 c_file_path = "input/wlc_clm_data_6726b0.c" dry_run = False log_level = "INFO" config_path = "config/config.json" logging.getLogger().setLevel(log_level) print(f" 开始同步 RANGE 定义...") print(f" C 源文件: {c_file_path}") if dry_run: print(" 启用 dry-run 模式:仅预览变更,不修改文件") try: sync = CLMRangeSynchronizer( c_file_path=None, dry_run=dry_run, config_path=config_path, ) sync.run() print(" 同步完成!") print(f" 详细日志已保存至: {LOG_FILE}") except FileNotFoundError as e: logger.error(f"文件未找到: {e}") print(" 请检查文件路径是否正确。") sys.exit(1) except PermissionError as e: logger.error(f"权限错误: {e}") print(" 无法读取或写入文件,请检查权限。") sys.exit(1) except Exception as e: logger.error(f"程序异常退出: {e}", exc_info=True) sys.exit(1) if __name__ == '__main__': main() 帮我把源代码中其中使用used_ranges的地方同步更改成新的"used_ranges_by_band": { “2g”: [ “RANGE_2G_20M_11_11”, “RANGE_2G_20M_1_1”, “RANGE_2G_20M_1_11”, “RANGE_2G_20M_2_10”, “RANGE_2G_40M_3_3”, “RANGE_2G_40M_4_8”, “RANGE_2G_40M_9_9” ], “5g”: [ “RANGE_5G_160M_50_114”, “RANGE_5G_20M_149_165”, “RANGE_5G_20M_36_48”, “RANGE_5G_20M_52_144”, “RANGE_5G_40M_151_159”, “RANGE_5G_40M_38_38”, “RANGE_5G_40M_46_46”, “RANGE_5G_40M_54_142”, “RANGE_5G_80M_155_155”, “RANGE_5G_80M_42_42”, “RANGE_5G_80M_58_138” ], “6g”: [] }, “used_ranges_count_per_band”: { “2g”: 7, “5g”: 11, “6g”: 0 },
10-29
def _write_back_in_block(self): """安全地一次性更新 C 文件中的数组和枚举定义""" if self.dry_run: self.logger.info("DRY-RUN: 跳过写入文件") return try: content = self.c_file_path.read_text(encoding='utf-8') start_idx = content.find(self.start_marker) end_idx = content.find(self.end_marker) + len(self.end_marker) if start_idx == -1 or end_idx == -1: raise ValueError("未找到 CHANNEL RANGES 标记块") header = content[:start_idx] footer = content[end_idx:] block = content[start_idx:end_idx] replacements = [] # (start, end, replacement) # === 工具函数:移除注释避免误匹配 === def remove_comments(text): text = re.sub(r'//.*$', '', text, flags=re.MULTILINE) text = re.sub(r'/\*.*?\*/', '', text, flags=re.DOTALL) return text clean_block = remove_comments(block) # === 1. 更新 channel_ranges_xxx[] 数组:只在末尾添加新项 === array_pattern = re.compile( r'(static\s+const\s+struct\s+clm_channel_range\s+(channel_ranges_[\w\d]+)\s*\[\s*\]\s*=\s*\{)([^}]*)};', re.DOTALL ) for match in array_pattern.finditer(clean_block): array_name = match.group(2) if array_name not in self.struct_entries: continue structs = self.struct_entries[array_name] body_content = match.group(3) # 不 strip(),保留原始空白 original_end = match.end() # 提取第一行缩进(用于新行) first_line = body_content.split('\n')[0] if body_content.strip() else "" indent_match = re.match(r'^(\s*)', first_line) indent = indent_match.group(1) if indent_match else " " # 解析已有 {low, high} 结构体 existing_items = [] item_pattern = r'\{\s*(\d+)\s*,\s*(\d+)\s*\}' for m in re.finditer(item_pattern, body_content): low, high = int(m.group(1)), int(m.group(2)) existing_items.append((low, high)) # 查找最后一个结构体结束位置(用于插入点) all_matches = list(re.finditer(item_pattern, body_content)) if all_matches: last_match = all_matches[-1] insert_pos_in_body = body_content.find('}', last_match.start()) + 1 else: insert_pos_in_body = len(body_content) # 找出第一个尚未插入的项 inserted_count = len(existing_items) if inserted_count >= len(structs): continue new_item = structs[inserted_count] low, high = new_item['low'], new_item['high'] # 检查是否已存在 if (low, high) in existing_items: continue # 构造新条目 formatted_item = f" {{ {low}, {high}}}" comma = ",\n" insertion = f"{indent}{formatted_item}{comma}" # 计算插入位置在整个 block 中的真实 offset body_start = match.start(3) insert_offset = body_start + insert_pos_in_body final_insert = block[:insert_offset] + insertion + block[insert_offset:] # 重建整个声明 new_decl = f"{match.group(1)}{final_insert[match.start(3):]}{indent}}};" replacements.append((match.start(), original_end, new_decl)) range_macro = f"RANGE_{array_name.upper().replace('CHANNEL_RANGES_', '').replace('_', '_')}_{low}_{high}" self.logger.info(f"扩展数组: {range_macro} → {{{low}, {high}}} (index={inserted_count})") # === 2. 更新 enum range_xxx:精确继承上一行宏名左对齐与 '=' 对齐 === enum_pattern = re.compile(r'(enum\s+range_[\w\d_]+\s*\{)([^}]*)\}\s*;', re.DOTALL) for match in enum_pattern.finditer(block): enum_name_match = re.search(r'range_([a-zA-Z0-9_]+)', match.group(0)) if not enum_name_match: continue inferred_array = f"channel_ranges_{enum_name_match.group(1)}" if inferred_array not in self.array_macros: continue macro_list = self.array_macros[inferred_array] enum_body = match.group(2) # 解析已有宏及其值 existing_macros = dict(re.findall(r'(RANGE_[\w\d_]+)\s*=\s*(\d+)', remove_comments(enum_body))) next_id = len(existing_macros) if next_id >= len(macro_list): continue new_macro = macro_list[next_id] # 获取非空行 lines = [line for line in enum_body.split('\n') if line.strip()] last_line = lines[-1] if lines else "" if not last_line.strip(): # fallback 缩进 line_indent = " " target_macro_start_col = 4 target_eq_col = 32 else: indent_match = re.match(r'^(\s*)', last_line) line_indent = indent_match.group(1) if indent_match else " " # 展开 tab(统一按 4 空格处理) expanded_last = last_line.expandtabs(4) # 👉 提取第一个 RANGE_xxx 宏名 first_macro_match = re.search(r'RANGE_[\w\d_]+', remove_comments(last_line)) if not first_macro_match: target_macro_start_col = len(line_indent) target_eq_col = 32 else: macro_text = first_macro_match.group(0) macro_start = first_macro_match.start() # 计算视觉起始列(基于展开后的字符串) raw_before = last_line[:macro_start] expanded_before = raw_before.expandtabs(4) target_macro_start_col = len(expanded_before) # 👉 找第一个 "=" 的视觉列 eq_match = re.search(r'=\s*\d+', last_line[macro_start:]) if eq_match: eq_abs_start = macro_start + eq_match.start() raw_eq_part = last_line[:eq_abs_start] expanded_eq_part = raw_eq_part.expandtabs(4) target_eq_col = len(expanded_eq_part) else: # fallback target_eq_col = target_macro_start_col + len(macro_text) + 8 # ✅ 现在我们知道: # - 宏名应该从第 target_macro_start_col 列开始(视觉) # - `=` 应该出现在 target_eq_col 列 # 计算当前宏名需要多少前置空格才能对齐 current_visual_len = len(new_macro.replace('\t', ' ')) padding_to_eq = max(1, target_eq_col - target_macro_start_col - current_visual_len) full_padding = ' ' * padding_to_eq formatted_new = f"{new_macro}{full_padding}= {next_id}" # 判断是否同行追加(最多 4 个) clean_last = remove_comments(last_line) visible_macros = len(re.findall(r'RANGE_[\w\d_]+', clean_last)) if visible_macros < 4 and last_line.strip(): # 同行追加:前面加两个空格分隔 separator = " " updated_content = last_line + separator + formatted_new + "," new_body = enum_body.rsplit(last_line, 1)[0] + updated_content else: # 换行:使用原始 indent 开头,然后补足到 target_macro_start_col raw_indent_len = len(line_indent.replace('\t', ' ')) leading_spaces_needed = max(0, target_macro_start_col - raw_indent_len) prefix_padding = ' ' * leading_spaces_needed new_line = f"{line_indent}{prefix_padding}{formatted_new}," trailing = enum_body.rstrip() maybe_comma = "," if not trailing.endswith(',') else "" new_body = f"{trailing}{maybe_comma}\n{new_line}" # 重建 enum new_enum = f"{match.group(1)}{new_body}\n}};" replacements.append((match.start(), match.end(), new_enum)) self.logger.info(f"扩展枚举: {new_macro} = {next_id}") # === 应用替换:倒序防止 offset 错乱 === replacements.sort(key=lambda x: x[0], reverse=True) result_block = block for start, end, r in replacements: result_block = result_block[:start] + r + result_block[end:] # 写回前备份 backup_path = self.c_file_path.with_suffix('.c.bak') copy2(self.c_file_path, backup_path) self.logger.info(f"已备份 → {backup_path}") # 写入新内容 self.c_file_path.write_text(header + result_block + footer, encoding='utf-8') self.logger.info(f"✅ 成功保存修改: {self.c_file_path}") except Exception as e: self.logger.error(f"写回文件失败: {e}", exc_info=True) raise def format_enum_item_aligned(reference_line: str, macro_name: str, value: int): """根据 reference_line 中最后一个宏的布局,返回对齐的新宏文本""" expanded_ref = reference_line.expandtabs(4) clean_ref = remove_comments(reference_line) matches = list(re.finditer(r'RANGE_[\w\d_]+\s*=\s*\d+', clean_ref)) if not matches: return f"{macro_name} = {value}" # fallback last_match = matches[-1] last_macro = last_match.group(0) start_in_ref = last_match.start() # 计算最后一个宏结束后的位置(含值) eq_match = re.search(r'=\s*\d+', last_macro) value_end_rel = eq_match.end() if eq_match else len(last_macro) value_abs_end = start_in_ref + value_end_rel # 获取其后的空白长度(决定间距) trailing = reference_line[value_abs_end:] spacing_match = re.match(r'\s*', trailing) inter_spacing = len(spacing_match.group(0)) # 计算新宏应从哪一列开始(视觉) prefix_until_value_end = reference_line[:value_abs_end] visual_end_pos = len(prefix_until_value_end.expandtabs(4)) + inter_spacing # 计算当前行已有内容的视觉长度(不含新增部分) base_part = reference_line[:value_abs_end + inter_spacing] base_visual_len = len(base_part.expandtabs(4)) # 新宏从 base_visual_len 开始 macro_visual_len = len(macro_name.replace('\t', ' ')) padding_len = max(1, visual_end_pos - base_visual_len - macro_visual_len) padding = ' ' * padding_len return f"{macro_name}{padding}= {value}" 在此基础上修改
10-17
#!/bin/bash Config sync script for synchronizing config macros with js_list files Usage: ./config_sync.sh <model_name> Example: ./config_sync.sh MR100v3 MODEL_NAME=“$1” if [ -z “$MODEL_NAME” ]; then echo “Usage: $0 <model_name>” echo “Example: $0 MR100v3” exit 1 fi CONFIG_PATH=“config” # Fixed config directory CONFIG_FILE=“ C O N F I G P A T H / CONFIG P ​ ATH/{MODEL_NAME}.config” HELP_LIST_FILE=“ C O N F I G P A T H / CONFIG P ​ ATH/{MODEL_NAME}/multipleLanguage/help.js_list” STR_LIST_FILE=“ C O N F I G P A T H / CONFIG P ​ ATH/{MODEL_NAME}/multipleLanguage/str.js_list” CONFIG_MAP_FILE=“config_map.txt” if [ ! -f “$CONFIG_FILE” ]; then echo “Error: Config file $CONFIG_FILE not found!” exit 1 fi if [ ! -f “$HELP_LIST_FILE” ]; then echo “Error: Help list file $HELP_LIST_FILE not found!” exit 1 fi if [ ! -f “$STR_LIST_FILE” ]; then echo “Error: String list file $STR_LIST_FILE not found!” exit 1 fi if [ ! -f “$CONFIG_MAP_FILE” ]; then echo “Error: Config map file $CONFIG_MAP_FILE not found!” exit 1 fi echo “Synchronizing config for model: $MODEL_NAME” echo “Config file: $CONFIG_FILE” echo “Help list: $HELP_LIST_FILE” echo “String list: $STR_LIST_FILE” echo “Config map: $CONFIG_MAP_FILE” echo “----------------------------------------” Function to check if a macro is enabled in config Handles all formats: - INCLUDE_XXX=y (enabled) - # INCLUDE_XXX=y (disabled) - # INCLUDE_XXX is not set (disabled) - #INCLUDE_XXX is not set (disabled) is_macro_enabled() { local macro=“ParseError: KaTeX parse error: Expected group after '^' at position 20: … if grep -q "^̲{macro}=y” “ParseError: KaTeX parse error: Expected 'EOF', got '#' at position 38: … return 0 #̲ enabled el…{macro}=y|^#.*${macro}[[:space:]]*is[[:space:]]*not[[:space:]]*set” “$CONFIG_FILE”; then return 1 # disabled (commented out) else return 2 # not found fi } Function to process a single token in a specific file Parameters: token, file_path, macro_enabled process_single_token() { local token=“$1” local file=“$2” local macro_enabled=“$3” # Skip if token is empty if [ -z "$token" ]; then return fi # Determine file type for logging based on file path local file_type="help" [[ "$file" == *"str.js_list" ]] && file_type="str" # Find lines containing this token (exact match) local found_lines=$(grep -n "[[:space:]]*${token}[[:space:]]*$" "$file" 2>/dev/null || true) if [ -z "$found_lines" ]; then # Try exact match as fallback found_lines=$(grep -n "^#*${token}$" "$file" 2>/dev/null || true) fi if [ -z "$found_lines" ]; then echo "Warning: Token '$token' not found in $file_type file" return fi # Process each matching line (usually just one) while IFS= read -r line_info; do local line_num=$(echo "$line_info" | cut -d: -f1) local line_content=$(echo "$line_info" | cut -d: -f2-) # Check current status if [[ "$line_content" =~ ^[[:space:]]*#.* ]]; then local item_enabled=false else local item_enabled=true fi # Sync status if needed if [ "$macro_enabled" != "$item_enabled" ]; then if [ "$macro_enabled" = "true" ]; then # Enable: remove the # comment sed -i "${line_num}s/^[[:space:]]*#[[:space:]]*//" "$file" echo "Enabled: $token in $file_type ($line_num)" else # Disable: add # comment sed -i "${line_num}s/^[[:space:]]*/#/" "$file" echo "Disabled: $token in $file_type ($line_num)" fi changes_made=true else echo "Already synchronized: $token in $file_type" fi done <<< "$found_lines" } Function to find and check/set status of items in js_list files Processes fixed pair of tokens: first for str.js_list, second for help.js_list process_token_mapping() { local macro=“$1” local macro_enabled=“$2” local string_token=“$3” local help_token=“$4” # Process string token (first token - always goes to str.js_list) process_single_token "$string_token" "$STR_LIST_FILE" "$macro_enabled" # Process help token (second token - always goes to help.js_list) process_single_token "$help_token" "$HELP_LIST_FILE" "$macro_enabled" } echo “Starting synchronization…” changes_made=false Process config map file line by line while IFS= read -r line; do # Skip empty lines and comments [[ -z “$line” || “$line” =~ *# ]] && continue # Parse line: MACRO string_token help_token read -ra parts <<< "$line" if [ ${#parts[@]} -ne 3 ]; then echo "Warning: Invalid mapping line format. Expected: MACRO string_token help_token. Got: $line" continue fi macro="${parts[0]}" string_token="${parts[1]}" help_token="${parts[2]}" # Check if macro exists in config file is_macro_enabled "$macro" macro_check_result=$? if [ $macro_check_result -eq 2 ]; then echo "Warning: Macro '$macro' not found in config file, skipping..." continue elif [ $macro_check_result -eq 0 ]; then macro_enabled=true else macro_enabled=false fi echo "Processing: $macro (enabled: $macro_enabled) -> str: $string_token, help: $help_token" # Process the pair of tokens for this macro process_token_mapping "$macro" "$macro_enabled" "$string_token" "$help_token" done < “$CONFIG_MAP_FILE” echo “----------------------------------------” if [ “$changes_made” = true ]; then echo " Synchronization completed with changes made" else echo " Synchronization completed - all files already in sync" fi exit 0整理脚本格式,仅整理格式
11-19
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值