скрипт для добавления пространства имен в файлы c

#c #regex #linux #sed

#c #регулярное выражение #linux #sed

Вопрос:

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

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

 namespace foo 
{
  

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

Для файлов .cpp достаточно добавить ‘using namespace foo’ после всех включений.

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

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

Комментарии:

1. Я рекомендую вам использовать язык сценариев, такой как Ruby, с регулярными выражениями, для выполнения этой работы. С вашими требованиями и некоторыми примерами Ruby в Google, вы можете выполнить этот скрипт за 30 минут-1 час. Вы можете использовать rubular.com чтобы проверить ваше регулярное выражение. Черт возьми, я только что написал скрипт Ruby для поиска зависимостей пространства имен / модуля между всеми моими файлами .hpp и .cpp — потребовалось около часа, чтобы написать с использованием regex.

2. sed — одна из первых программ, которая использовала регулярные выражения в качестве основного инструмента для работы с текстом. Удачи всем.

Ответ №1:

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

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

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

Ответ №2:

Это заставило меня на полпути:

 #!/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 $NAMESPACEn" $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 файлами, это значительно упростило работу.

Ответ №3:

Обратите внимание, это не учитывает закрытие защитных #endif строк, но их обертывание в a 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:gitsfink.ini' < "$tmp" > "$fn" amp;amp; 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