скрипт для добавления пространства имен в файлы C ++ - PullRequest
3 голосов
/ 01 ноября 2011

Итак, у меня есть гигантская кодовая база, к которой нужно добавить пространство имен.Вместо того, чтобы делать это вручную, я подумал об использовании grep, xargs & sed для добавления пространства имен ко всем исходным файлам ...

Но мои навыки не на должном уровне.В идеале

namespace foo 
{

будет добавлено после всех включений, а '}' будет добавлено после #endif в файлах .h.

Для файлов .cpp добавление 'с использованием пространства имен foo'после всех включений было бы достаточно.

Я возился с sed, но не очень далеко продвинулся.

Любая помощь будет принята с благодарностью.Спасибо!

Ответы [ 3 ]

3 голосов
/ 01 ноября 2011

Это не простая задача. Вещи, которые делают это проблематичным, включают

  • Материал, который вы не хотите помещать в новое пространство имен, например
    • Конструкции типа language "C" { C-stuff }
    • Переадресация объявлений не принадлежащих вам классов. Это становится в n раз сложнее, если вы используете какой-то внешний пакет, который также не использует пространства имен.
  • Даже найти, где разместить namespace Foo { и закрывающий '}', может быть сложно.
    • Вы хотите приложить предварительные декларации, кроме тех, которые не принадлежат вам.
    • Обычно вы хотите заключить в область видимости что-либо, включающее пару фигурных скобок - за исключением таких вещей, как language C.
    • Программисты по техническому обслуживанию (если ваш код существует достаточно долго) сделают все, что угодно, с вашим кодом. Они будут выдвигать объявления внутри классов или функций, между классами и функциями, где угодно, кроме вершины, которая облегчает выполнение сценария.
    • Вы не хотите делать двойные гнезда. Удивительно легко это сделать.
    • По разным причинам некоторые люди помещают то, что кажется посторонним, в конец заголовка. Это может быть особенно неприятной проблемой.
    • Если вы решите попытаться включить каждый класс, структуру и перечисление, вам нужно выяснить, где на самом деле находится начало объявления. Вы хотите обернуть template декларацию, если есть, и, конечно, комментарии doxygen и тому подобное.
    • Найти конец класса может быть просто противно. Люди имеют эту неприятную тенденцию вставлять несоответствующие скобки в комментарии и строки.

Удачи! Написание сценария займет чуть больше получаса. Это займет гораздо меньше времени, чем переписывание всего вашего кода. Я предлагаю вам использовать что-то более мощное, чем Sed. Perl, python и ruby ​​- три хороших варианта.

1 голос
/ 15 марта 2016

Это дало мне половину пути:

#!/bin/sh
NAMESPACE=my_namespace
for x in $(find . -name "*.h"); do
    sed -i "$(grep -n "^#" $x | tail -2 | head -1 | sed 's/:.*//')a\\\nnamespace $NAMESPACE {\n" $x
    sed -i "$(($(grep -n "^#" $x | tail -1 | sed 's/:.*//')-1))a} // namespace $NAMESPACE\n" $x
done

for x in $(find . -name "*.cpp"); do
    sed -i "$(grep -n "#include" $x | tail -1 | sed 's/:.*//')a\\\nnamespace $NAMESPACE {\n" $x
    echo >> $x
    echo "} // namespace $NAMESPACE" >> $x
done

Он в основном находит одну, но последнюю директиву препроцессора в файле h и добавляет туда пространство имен. он ограничивает пространство имен непосредственно перед последней директивой препроцессора (я предполагаю, что у меня есть #endif в конце моих h-файлов). Если это не так, скрипт может быть адаптирован соответствующим образом.

В случае cpp я ищу последнее включение, чтобы открыть пространство имен и закрыть его в конце файла.

Это далеко не идеально, но с более чем 100 файлами это значительно облегчило работу.

0 голосов
/ 28 ноября 2017

Обратите внимание, что это не учитывает закрывающую охрану #endif строк, но перенос их в namespace {};, похоже, не повредит.

Не комментируйте строки в соответствии с вашими предпочтениями.

#!/usr/bin/env bash
namespace="namespace m {"
pad="    "

function processFile {
    # dos2unix "$1"
    local fn=$1
    local tmp="$1.tmp"
    echo "Processing '$fn'"
    rm -f "$tmp"
    local -i skipping=1
    local regSkip="^(#include.*|#pragma.*|//.*|)"'$'
    local line
    while IFS= read -r line
    do
        if (( skipping )); then
            if [[ $line =~ $regSkip ]]; then :
            else skipping=0; echo "$namespace" >> "$tmp"
            fi
            echo "$line" >> "$tmp"
        else
            echo "$pad$line" >> "$tmp"
        fi
    done < "$1"
    echo "$line" >> "$tmp"
    echo "};" >> "$tmp"
    mv -f "$fn" "$fn.ori"
    # optionally reformat
    astyle --options='e:\git\sfink.ini' < "$tmp" > "$fn" && rm "$tmp"
    # else just move
    # mv -f "$tmp" "$fn"
}

# for fn in $( find . -name '*.h' ); do processFile "$fn"; done
# for fn in $( find . -name '*.cpp' ); do processFile "$fn"; done
for fn in "$@"; do processFile "$fn"; done

n.b., Файлы должны быть в формате перевода строки Unix

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...