История коммита: добавляем новую опцию в Doxygen

Я использую Doxygen для генерации документации для одной из своих библиотек, libSDL2pp. Однажды, просматривая оную документацию я наткнулся на интересный факт: мой email в сгенерированном HTML был изменён до неузнаваемости, очевидно в целях помешать спам-ботам собирать адреса. Меня такое поведение категорически не устраивало, а в Doxygen не было настройки чтобы его отключить, поэтому я решил её добавить.

Вот так выглядит изменённый email:

То же в HTML (отформатировано для читаемости):

<a href="#" onclick="location.href='mai'+'lto:'+'amd'+'mi'+'3@a'+'md'+'mi3'+'.r'+'u'; return false;">
	amdmi<span style="display: none;">.nosp@m.</span>3@am<span style="display: none;">.nosp@m.</span>dmi3.<span style="display: none;">.nosp@m.</span>ru
</a>

Отступление: в начале я как-то не осознал что <span>ы вставляемые в адрес должны быть невидимы из-за display: none, но этот встроенный стиль не работал из-за заголовка Content-Security-Policy у меня на сервере. Это отдельная проблема в Doxygen которую также нужно исправить.

Это прямо серьёзная обфускация! Мне, однако, она совершенно не нужна:

  • Я хочу чтобы мой email и читался в виде текста, и работал в качестве ссылки, даже при отключенном javascript.
  • Спам меня не сильно беспокоит, даже при том что мой email опубликован в открытом виде на сотнях сайтов и я не использую никаких фильтров, поэтому роботов я не боюсь.
  • Так как адрес уже опубликован на других сайтах, прятать его на каком-то одном вообще не имеет смысла.

Поэтому почему бы, подумал я, не добавить возможность отключить это поведение Doxygen.

Начнём с того что найдём в коде место ответственное за обфускацию. Для этого просто поищем по исходникам мусорный текст которые вставляется в адрес. Нужное место находится сразу:

% git clone https://github.com/doxygen/doxygen/ .
% grep -R nosp@m . 
./src/htmldocvisitor.cpp:      if (*p) m_t << "<span style=\"display: none;\">.nosp@m.</span>";

Итак, мы в функции которая, судя по названию, как-то обрабатывает URLы:

375void HtmlDocVisitor::visit(DocURL *u)
376{
377  if (m_hide) return;
378  if (u->isEmail()) // mail address
379  {
380    QCString url = u->url();
381    // obfuscate the mail address link
382    writeObfuscatedMailAddress(url);
383    const char *p = url.data();
384    // also obfuscate the address as shown on the web page
385    uint size=5;
386    while (*p)
387    {
388      for (uint j=0;j<size && *p;j++)
389      {
390        p = writeUTF8Char(m_t,p);
391      }
392      if (*p) m_t << "<span style=\"display: none;\">.nosp@m.</span>";
393      if (size==5) size=4; else size=5;
394    }
395    m_t << "</a>";
396  }
397  else // web address
398  {
399    m_t << "<a href=\"";
400    m_t << u->url() << "\">";
401    filter(u->url());
402    m_t << "</a>";
403  }
404}

Тут не нужно вникать в алгоритм обфускации, достаточно осмотреться и увидеть что нам приходит URL (в нашем случае email) в аргументе url, с ним производятся какие-то манипуляции и результат выводится в поток m_t. Можно заметить что URL передаётся также в функцию writeObfuscatedMailAddress() которая ответственна за вывод открывающего HTML тэга ссылки (<a href="mailto:...">) и также обфусцирует в нём email адрес.

Нужно просто обернуть код обфускации в этих двух местах в ifы проверяющие соответствующую настройку, в else ветках которых выводить неизменённые адреса.

Осталось добавить опцию и научиться получать её значение из кода. Для последнего я просто поискал [Cc]onfig в том же исходном файле и сразу получил пример: Config_getBool(DOT_CLEANUP). Теперь можно найти где определяется DOT_CLEANUP (а там же и остальные опции). Обычно это будет #define или enum значение в каком-то заголовочном файле, но в случае Doxygen определение нашлось в .xml:

% grep -R DOT_CLEANUP .
...
./src/config.xml:    <option type='bool' id='DOT_CLEANUP' defval='1'>
...

Значит Doxygen строит код обработки опций (а скорее всего, и документацию по ним) из определений в .xml файле - что-ж, удобно. Добавляем в этот .xml определение новой опции по аналогии с существующей, хотя бы той-же DOT_CLEANUP.

Всё готово, можно собрать Doxygen (cmake . && cmake --build . после чего получим бинарник в bin/doxygen) и протестировать новую опцию. При выключении обфускации сгенерированный HTML выглядит как ожидается:

<a href="mailto:amdmi3@amdmi3.ru">amdmi3@amdmi3.ru</a>

Можно создавать пулл реквест (упрощённые изменения).

Мои изменения были приняты на следующий день, и должны попасть в следующий релиз Doxygen 1.9.3.

На будущее: перед отправкой PR стоит посмотреть на стиль кода принятый в проекте и убедиться что изменения ему соответствуют, чтобы потом не исправить.