LINUX.ORG.RU

4
Всего сообщений: 27

Макросы + история успеха

Комрады. Сабж собственно - чем макросы racket лучше/хуже макросов cl и наоборот?

Второе - где, какой диалект и для чего (лиспа) вы применяете?

Всем спасибо.

З.Ы.: интерес к этому так как начали писать с коллегами большую система на racket. Стало интересно. Делаем just for fun

 , , ,

silver-bullet-bfg ()

Макрос на VBA для Libreoffice, странная ошибка

Доброго времени суток. Написал функцию в Libreoffice Calc на VBA. Она отрабатывает правильно и без ошибок, но в момент открытия документа появляется следующая ошибка ровно столько раз, сколько эта функция используется в формулах:

BASIC runtime error.
'1'

Type: com.sun.star.uno.RuntimeException
Message: unsatisfied query for interface of type com.sun.star.sheet.XSpreadsheetView!

Причем если закрыть окна с этой ошибкой, то все будет работать как будто ее и не было, но дело в том, что функция используется много раз и закрывать каждый раз тоже приходится много окон.

Знатоки макросов в Libreoffice, подскажите, в чем проблема?

Сам макрос (сумма чисел в строке с заданным отступом и промежутком):

REM  *****  BASIC  *****

Sub Main

End Sub

Option VBASupport 1
Option Explicit

Function SumEvery(startCell As Range, row As Boolean, gape As Integer) As Double
	On Error GoTo ErrorHandler
	
	Dim sht As Worksheet
	Set sht = ActiveSheet
	
	Dim lastCell As Range
	If row Then
		Set lastCell =  Cells(startCell.Row, sht.Columns.Count)
	Else
		Set lastCell = Cells(sht.Rows.Count, startCell.Column)
	End If
	
	Dim resRan As Range
	Set resRan = Range(startCell, lastCell)
	
	Dim res As Double
	res = 0.0

	Dim c As Integer
	For c = 1 to resRan.Cells.Count
		If (c - 1) Mod gape = 0 Then
			res = res + resRan.Cells(c).Value
		End If	
	Next
	
	SumEvery = res
	
	Exit Function
	
	ErrorHandler:
	Stop
End Function

Выяснил, что проблемный участок кода здесь:

Dim sht As Worksheet
Set sht = ActiveSheet

Что с ним можно сделать? Если заменить на

Dim sht As Object
Set sht = ThisComponent.getCurrentController().getActiveSheet()

то ситуация та же самая, но ошибка изменяется на:

BASIC runtime error.
'91'
Object variable not set.

Ошибка исправлена созданием новой библиотеки в Macros Organizer. Но теперь использование макроса возвращает ошибку #NAME? пока он не будет открыт на редактирование

Причина ошибки #NAME? здесь https://stackoverflow.com/questions/26442049/name-error-after-opening-spreadsheet-with-macro

В итоге вернул функцию обратно в docname.ods - Standard - Module1 и добавил игнорирование ошибок. В описании исправленная функция

 , , , ,

Rot1 ()

Вопрос про гигиенические макросы

Здравствуйте, мои маленькие любители макросов!

Есть такой макрос на CL:

(defun has-tag-p (tag record) ... )

(defmacro select (query records)
  (let ((rec (gensym "record")))
    (labels ((query-helper (q)
               (if (and (listp q)
                        (member (car q) '(and or not)))
                   `(,(car q) ,@(mapcar #'query-helper (cdr q)))
                   `(has-tag-p ,q ,rec))))
      `(remove-if-not (lambda (,rec) ,(query-helper query)) ,records))))

Аналогичный макрос (без гигиены) на guile:

(define (has-tag? tag record) ... )

(define-macro (select query records)
  (define rec (gensym "record"))
  (define (query-helper q)
    (if (and (list? q)
             (memq (car q) '(and or not)))
        `(,(car q) ,@(map query-helper (cdr q)))
        `(has-tag? ,q ,rec)))
  `(filter (lambda (,rec) ,(query-helper query)) ,records))

Вопрос: как написать такое же, но с гигиеной, используя (1) только стандарт R5RS, (2) стандарт R7RS, (3) Racket?

Призываю @monk’а и прочих знатоков Scheme.

Ну и с интересом выслушаю замечания бывалых лисперов по приведённому коду.

 , , , ,

aeralahthu ()

Проблема с xml macros для мыши Razer

Предоставляю часть макроса. Его суть состоит в том, чтобы сопутствовать упрощению контроля прицела на мыше Razer. Интересует усовершенствование данного макроса, для более точного контроля. Возможно использование других значений или методик для достижения той же цели. Еще наглядный пример как выглядеть он в самой программе: Сюда!

<?xml version="1.0" encoding="utf-8"?>
<Macro xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>Test</Name>
  <Guid>919191b2-fa7a-4b7c-b475-83febe612615</Guid>
  <MacroEvents>
    <MacroEvent>
      <Type>3</Type>
      <MouseMovement>
        <MouseMovementEvent>
          <Type>3</Type>
          <X>971</X>
          <Y>250</Y>
        </MouseMovementEvent>
        <MouseMovementEvent>
          <Type>3</Type>
          <X>966</X>
          <Y>260</Y>
        </MouseMovementEvent>
        <MouseMovementEvent>
          <Type>3</Type>
          <X>961</X>
          <Y>269</Y>
        </MouseMovementEvent>
        <MouseMovementEvent>
          <Type>3</Type>
          <X>956</X>
          <Y>275</Y>
        </MouseMovementEvent>
        <MouseMovementEvent>
          <Type>3</Type>
          <X>953</X>
          <Y>281</Y>
        </MouseMovementEvent>
        <MouseMovementEvent>
          <Type>3</Type>
          <X>949</X>
          <Y>288</Y>
        </MouseMovementEvent>
        <MouseMovementEvent>
          <Type>3</Type>
          <X>946</X>
          <Y>294</Y>
 </MouseMovementEvent>
      </MouseMovement>
    </MacroEvent>
  </MacroEvents>
</Macro>

 , ,

SysError ()

Макрос

Как в линуксе забиндить одну кнопку на двойное нажатие второй? К примеру я нажимаю кнопку «v» и мне дважды наживаеться кнопка «b», с минимальной задержкой?

 ,

alexandrovich_ff ()

Как создать макросы в убунту?

Я использую программу cherrytree для создания заметок. Так вот, мне приходиться для каждого заголовка нажать несколько сочетаний горячих клавиш. Например, чтобы сделать его h2 - ctrl+b. И еще раз нажать shift+alt+f - чтобы поменять цвет.

Я нашел два решение: 1. xodotool - мне понравилось. Например, чтобы автоматизировать прописания кода для данного форума

bash -c 'sleep 0.5; xdotool getactivewindow type "

" && sleep 0.5 && xdotool key Left Left Left Left Left Left Left'

Только я не понимаю как прописать нажатие на несколько клавиш одновременно.

2. Autokey-gtk - тут приходится прописать скрипты, до этого я еще не дорос.

Что мне посоветуете? Заранее благодарен.

 , ,

seriiserii825 ()

Xorg macros не могу найти на Trisquel ?

Хочу установить графический драйвер intel, скаченный отсюда http://www.linuxfromscratch.org/blfs/view/svn/x/x7driver.html#xorg-intel-driver

Не получается:

# ./autogen.sh
.
autoreconf: Entering directory `.'
autoreconf: configure.ac: not using Gettext
autoreconf: running: aclocal -I m4
configure.ac:55: error: must install xorg-server macros before running autoconf/autogen.
  Hint: either install from source, git://anongit.freedesktop.org/xorg/xserver or,
  depending on your distribution, try package 'xserver-xorg-dev' or 'xorg-x11-server-devel'
configure.ac:55: the top level
autom4te: /usr/bin/m4 failed with exit status: 1
aclocal: error: echo failed with exit status: 1
autoreconf: aclocal failed with exit status: 1


# apt-get install xutils-dev xutils x11-utils x11-xserver-utils

# ./autogen.sh
..не работает с той же ошибкой..


# apt-cache search x*macr | nc termbin.com 9999
http://termbin.com/bgxm

# apt-cache search x*util | nc termbin.com 9999
http://termbin.com/492k

#  apt-file search macros | grep xorg
xutils-dev: /usr/share/aclocal/xorg-macros.m4
xutils-dev: /usr/share/pkgconfig/xorg-macros.pc


# apt-cache policy xutils-dev
xutils-dev:
  Установлен: 1:7.7+3ubuntu2
  Кандидат:   1:7.7+3ubuntu2
  Таблица версий:
 *** 1:7.7+3ubuntu2 500
        500 https://archive.trisquel.info/trisquel flidas/main amd64 Packages
        100 /var/lib/dpkg/status


# echo $PKG_CONFIG_PATH

#

Подскажите, пожалуйста, пользователи Линукс, что надо настроить?

 , ,

znavko ()

В C++20 могут появиться макросы, как в Rust

...если комитет примет предложение представленное в этом пропозале.

Предлагается добавить «нативные» C++-макросы.

Из пропозала

So what would one of these native C++ macro functions look like?

 // Macro functions look just like a free function except for the # at the
 // end of the function name. Note that the # counts as part of the identifier,
 // so return# does not collide with the return keyword.
 template<class T>
 inline int return#(T v)
 {
	 if(v > 0)
		return -> v; // control flow keyword + ’->’ means it affects the
	 // calling function, not this macro function
	 if(v < 0)
		break ->;
	 // Also this break is executed in the calling function
	 // If break isn’t valid at the point of use
	 // in the calling function, it will not compile
	 // We can inject variable declarations into the calling function
	 // with typename + ’->’. This is useful for RAII triggered cleanup
	 // i.e. these get destructed when the scope of the call point exits.
	 // Note that the actual name of the variable injected will
	 // be some very unique identifier which cannot collide with any
	 // other variable, including those injected by other macro functions
	 int -> a = 5;
	 // Otherwise this function macro has a local scope, and code
	 // executed here remains here
	 size_t n = 0;
	 for(; n < 5; n++)
	 {
		 // We can also refer to variables previously injected into the
		 // caller’s scope by this macro function like this.
		 // This lets one keep state across invocations of the macro function
		 (-> a) ++;
	 }
	 // This returns a value from this function macro to the caller
	 // If you wrote return -> a, that would be a compile error
	 // as there is no variable called a in this scope.
	 return (-> a);
}

Такие макросы могут быть полезны для реализации некоторых фич, требующих вставки кучи служебного кода, например, корутин или оператора try, без внесения модификаций в Core Language, чисто на уровне библиотек.

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

 , ,

utf8nowhere ()

Имплементация Scheme r5rs макросов

Добрый день!

Подскажите, пожалуйста, есть ли какие-нибудь стандартные алгоритмы для имплементации макросов Scheme R5RS?
Гуглятся какие-то простые примеры на самой же Scheme, либо какой-нибудь спагетти код в котором черт ногу сломит.

Если какие-нибудь канонические реализации (на Java/C++?) или статьи?

Ну, и в общих чертах, с чего начинать?
Реализовал уже весь R5RS, а вот с макросами даже не знаю с чего начать.

Спасибо.
PS: в данный момент изучаю как оно реализовано в Kawa, уж не знаю, поможет ли

 , ,

kovrik ()

готовый макрос возвращающий дату/время в ядре

Есть ли в недрах линукс ядра какой-либо макрос, который разворачивался бы в дату/время, мне это нужно подставлять в ядерный модуль, чтобы знать какой версии пользователь запускает модуль. То есть хорошо бы это поместить в MODULE_DESCRIPTION например.

Спасибо.

 , , ,

cruz7 ()

Вопрос по short-hand специальных форм в Scheme

Являются ли short-hand специальных форм макросами в Схеме?

Например, quote - есть special form.
Что есть ее short-hand вариант '?

Пример:

'(+ 1 2) => (quote (+ 1 2)) => (+ 1 2)

Превращение из 'form в (quote form) происходит на фазе read или macroexpand?
Т.е. когда ридер видит ', то должен ли он вернуть токен ' без изменений (который потом во время macroexpansion превратится в quote) или же ридер сразу должен вернуть список (quote form) без каких либо макросов?

Или без разницы и зависит от имплементации?

 , ,

kovrik ()

Макросы в расте

Знатоки раста, подскажите пожалуйста, как в макросах раста раскрыть блок и обработать элементы?
Т.е. я хочу вот такой вариант:

opt_m!({
  a <- f1();
  b <- f2();
  let c = a + b;
  mret(c);
})
транслировать в такой:
{
  let mut res = None;
  loop {
    let a = match f1() {
      Some(x) => x,
      None => break
    }
    let b = match f2() {
      Some(x) => x,
      None => break
    }
    let c = a + b;
    res = Some(c);
    break;
  }
  res
}

 ,

Aswed ()

Экспорт CSV-файла в LDIF-файл для последующего импорта в ClawsMail

В продолжение темы о Thunderbirdтемы об OperaMail)

Да, можно было написать на чём угодно другом, но

  • уже даже есть скрипт на perl на сайте clawsmail, но таскать perl везде не хочется - как он работает не проверял;
  • да, нужно, чтобы был установлен OpenOffice или LibreOffice (+ jre, jdk или openjdk), но предположу, что у пользователя ClawsMail что-нибудь из этого установлено;
  • всё равно csv предварительно удобнее править в табличном процессоре, а писать громоздкое GUI-приложение для такой мелкой задачи слишком долго (для меня);
  • мне нужно было, чтобы импортированные в clawsmail записи Ф.И.О. выглядели определённым образом;
  • раз уж установлен OpenOffice или LibreOffice (+ jre, jdk или openjdk), то макрос легко подправить под свой формат и порядок следования полей.

поэтому написано в OpenOffice BASIC.

Макрос экспортирует csv-файл (первая строка - названия полей):

Имя,Фамилия,"Отображаемое имя","Электронная почта",Телефон,Адрес,Должность,Отдел
"Иван Иванович",Иванов,"Иванов Иван Иванович",ivanov@ivan.iv,"223-322, 322-223","корпус 1, этаж 2, к. 3","Начальник отдела","Отдел 001"
"Пётр Петрович",Петров,"Петров Пётр Петрович",petrov@petr.pe,"322-223, 223-322","корпус 3, этаж 2, к. 1","Заместитель начальника отдела","Отдел 002"
в выходной файл формата LDIF:
cn: Иванов Иван Иванович
sn:  Иванович
givenName: Иванов Иван
displayName: Иванов Иван Иванович
mail: ivanov@ivan.iv
адрес: корпус 1, этаж 2, к. 3
телефон: 223-322, 322-223
отдел: Отдел 001
должность: Начальник отдела

cn: Петров Пётр Петрович
sn:  Петрович
givenName: Петров Пётр
displayName: Петров Пётр Петрович
mail: petrov@petr.pe
адрес: корпус 3, этаж 2, к. 1
телефон: 322-223, 223-322
отдел: Отдел 002
должность: Заместитель начальника отдела

Имя выходного файла выбирается пользователем в появляющемся при запуске макроса диалога «Save As». Названия полей LDIF должны начинаться со строчной буквы. Сохраняются только названия полей, которых достаточно для последующего импорта адресной книги в ClawsMail.

Сам макрос нужно запускать после открытия csv-файла в OpenOffice:

REM Экспорт Адрессной книги из открытого .CSV файла в файл в формате LDIF для последующего испорта в Адресную книгу ClawsMail
REM Export AddressBook from opened .CSV to LDIF formated file for import to ClawsMail AddressBook
Sub ClawsMail_LDIF_export

  oDoc=ThisComponent
  oSheet = oDoc.CurrentController.getActiveSheet()
  oCellCursor = oSheet.createCursor()
  oCellCursor.GotoEndOfUsedArea(True) ' Select Used Cells Range 
  End_Row = oCellCursor.getRangeAddress.EndRow
  End_Col = oCellCursor.getRangeAddress.EndColumn

  Dim AddrItem(End_Row - 1, End_Col) as String
  Dim AddrItemNew(End_Row - 1, End_Col + 1) as String
  
  REM Чтение AddrItem (Address Item) в формате:
  REM Имя,Фамилия,"Отображаемое имя","Электронная почта",Телефон,Адрес,Должность,Отдел
  REM Name (or "Name" + "Patronymic"),Surname,"Display Name","e-mail address",phone,address,position,department
  For i = 0 To End_Row - 1   ' AddrItem Row number
    For j = 0 To End_Col
      AddrItem(i, j) = oSheet.getCellByPosition(j, i + 1).Formula
    Next j	
  Next i
  
  For i = 0 To End_Row - 1
    SpacePos = InStr(AddrItem(i, 0), " ")
    If SpacePos > 0 Then
      AddrItemNew(i, 1) = " " + Mid(AddrItem(i, 0), SpacePos+1, Len(AddrItem(i, 0))-SpacePos+1)
    Else
      AddrItemNew(i, 1) = ""
    End If
    AddrItemNew(i, 2) = AddrItem(i, 1) + " " + Mid(AddrItem(i, 0), 1, InStr(AddrItem(i, 0), " ")-1)
    AddrItemNew(i, 0) = AddrItemNew(i, 2) + AddrItemNew(i, 1)
    AddrItemNew(i, 3) = AddrItem(i, 2)
    AddrItemNew(i, 4) = AddrItem(i, 3)
    AddrItemNew(i, 5) = AddrItem(i, 5)
    AddrItemNew(i, 6) = AddrItem(i, 4)
    AddrItemNew(i, 7) = AddrItem(i, 7)
    AddrItemNew(i, 8) = AddrItem(i, 6)
  Next i
  Dim LDIF_field_name(9) As String ' Поля адресной книги в формате LDIF
  LDIF_field_name = Array("cn: ", "sn: ", "givenName: ", "displayName: ", "mail: ", "адрес: ", _
                          "телефон: ", "отдел: ", "должность: ")
  REM LDIF_field_name = Array("cn: ", "sn: ", "givenName: ", "displayName: ", "mail: ", "address: ", _
  REM                        "phone: ", "department: ", "position: ")


  ' Open file to write
  sFileName = ""
  sFilename = FilePickSave
  
  If sFilename <> "" Then
  
    ' Opening file to write in UTF-8 as LDIF must use UTF-8 codepage
    encoding = "UTF-8"  ' set codepage
    ' names of codepage are described here:
    ' http://www.iana.org/assignments/character-sets/character-sets.xhtml
    
    fileaccess = createUnoService ("com.sun.star.ucb.SimpleFileAccess")
    
    REM удаление выходного файла если он существует
    REM if output file exists then delete it
    If fileaccess.exists(sFileName) Then
      fileaccess.kill(sFileName) 
    End If
    
    intextstream = createUnoService ("com.sun.star.io.TextOutputStream")
    intextstream.setEncoding( encoding )
    intext = fileaccess.openFileWrite( sFileName )
    intextstream.setOutputStream( intext )  
  
    For i = 0 to End_Row - 1
      For j = 0 To End_Col+1
        If AddrItemNew(i, j) <> "" Then
          intextstream.writeString( LDIF_field_name(j) &  AddrItemNew(i, j) & CHR$(13) & CHR$(10))
        End If
      Next j
      ' write empty string
      intextstream.writeString(CHR$(13) & CHR$(10))
    Next i
  
    ' closing file
    intextstream.closeOutput()
  End If ' sFilename <> ""
  
End Sub ' ClawsMail_LDIF_export 

REM *** Функция выбора файла для сохранения | Function: File to Save As
REM *** Взята здесь | From : https://forum.openoffice.org/en/forum/viewtopic.php?f=45&t=26774
' ******* FilePicker Save File ******************************************
Function FilePickSave As String
Dim FilePicker As Object
Dim FPtype(0) As Integer

FilePicker = CreateUnoService("com.sun.star.ui.dialogs.FilePicker")
FPtype(0)=com.sun.star.ui.dialogs.TemplateDescription.FILESAVE_SIMPLE
FilePicker.initialize(FPtype())

If FilePicker.execute() Then
   FilePickSave = ConvertToURL(FilePicker.Files(0))
EndIf

End Function
' ******* End FilePicker Save File ******************************************

 , , , ,

grem ()

nasm macro

Не могу осилить макрос, по этой теме вроде ничего сложного нет. но выдает ошибку

test.asm:20: error: symbol `str' undefined

%macro print 2
    section .data
    .str db  %1,10,0
    section .text
    mov rdi, str
    mov rsi, %2
    mov rax, 0
    call printf
%endmacro

foo:
section .text
    push rbp

print_max:
    print "begin[max] = %d", ebx

    pop rbp
    ret

подскажите что я делаю не так.

 , ,

SmilePlz ()

OpenOffice BASIC: cкорость чтения из текстового файла

Есть макрос для OpenOffice Calc, который

  • просит пользователя указать директорию с которой будет дальше работать;
  • получает список директорий из указанной;
  • в каждой из этих (обычно 10-30 шт) директорий открывает текстовый файл примерно в 18-20 тыс. строк каждый с результатами расчёта, просматривает его в поисках определённых полей и чтения соответствующих им значений;
  • записывает значения найденных полей в ячейки активного листа.

Время отработки макроса порядка 15-30 секунд и все они тратятся на чтение из файла. Сегодня переписал этот макрос на MS VBA для Excel 2003, изменив только функцию выбора директории и некоторые переменные (так как отличались методы указания активной ячейки). Функции чтения из файла остались такими же. Макрос при этом отрабатывает практически мгновенно. То есть на просмотр того же количества строк в файлах уходит не больше 2 секунд. Почему чтение из файла в OO Basic может работать так медленно?

Есть ли у кого опыт написания макросов для OpenOffice на Python, насколько быстрее написанное на нём чтение из таких файлов будет отрабатывать быстрее?

 , , ,

grem ()

Какие языки поддерживают макросы-генераторы кода?

В моём любимом Perl мне часто не хватает одной, казалось бы, простой, вещи: макрорасширений.

Для чего они нужны в моём случае?

Для того, чтобы объяснить компилятору, что данный кусок кода не нужно всякий раз вызывать как полноценную процедуру, а можно его просто копипастить, подставляя по месту соотв. статические, то есть вычисляемые на этапе компиляции, параметры.

Собственно, такая штука была в чудесном MASM'е, и она позволяла сэкономить немало тактов процессора на отсутствии ненужных вызовов процедур там, где их параметры были известны уже на этапе компиляции.

Думаю, что хотя оптимизирующие компиляторы и умеют разворачивать циклы и вообще удалять целые «ненужные» куски кода, но вряд ли они сумеют сами догадаться о том, что данной процедуре совершенно не обязательно пихать в стек параметры-константы и делать лишние malloc'и для локальных переменных (ну или пихать их в стек, если они туда помещаются), а можно просто сгенерировать соотв. копию кода процедуры и выполнить потом этот код в общем потоке исполнения.

Пожалуй, трудно поспорить с тем, что те же преобразования «строк-цифр» в «цифры-цифры» и обратно - занятие для процессора куда более утомительное, но... одно дело - принципиальные конструктивные недостатки языка, а другое - отсутствие в нём полезной функциональности.

Вопрос: в каких языках, кроме собственно макроассемблеров, есть механизм генерации кода?

 , ,

DRVTiny ()

автоматизация некоторых действий в incskape. как?

Категорически вас приветствую!

Ребята, мне нужно часто делать однотипные действия в incskap'e. Мне нужно частно выставлять одинаковые параметры для разных документов.

У меня есть шаблон для inkscape. В нём много слоёв, в которые я импортирую изображения. И изначально они располагаются «как попало» на листе. Мне нужно выставить для этих слоёв размеры и положение изображений на листе. Реализуются эти действия как нибудь «из коробки»?

спасибо!

 ,

hope13 ()

C++ Арифметика с макросами

Хочется изменять переменные на этапе компиляции. Что-нибудь подобное:

#define VV 0
INC(VV)

и VV стало 1


Как-то можно сделать? можно m4, boost или другие стандартные средства. Спасибо

 ,

kasha ()

Передача параметра в макрос очереди

Из Dial можно вызвать macro-update и передать параметр ${CALLERID(num)}:

exten=> s,n,Dial(Local/${AGENT}@phones,60,gM(update^${CALLERID(num)}))
Из Queue тоже можно вызвать macro-test:
exten=> s,n,Queue(reference,tTh,,,,,test)
но как передать/поймать параметр ${CALLERID(num)} в macro-test?

 , ,

petav ()

Импорт адресной книги из OperaMail (OperaMail Addressbook import)

Захотелось мне недавно экспортировать адресную книгу из OperaMail хотя бы в файл формата .csv (простенькую таблицу). Но оказалось, что из самой программы экспортировать её можно только в родной формат-файл contacts.adr. Порывшись на просторах интернета, к сожалению, нашёл только онлайн-конверторы, представляющие собой скрипт на perl (который можно сохранить и выполнить локально). Пользоваться онлайн-услугой не захотелось, как и ставить perl. А так как на тот момент я решил немного почитать про OpenOffice BASIC, то захотелось попробовать написать простой макрос, который открывает файл с адресной книгой формата OperaMail и импортирует её в таблицу активного листа в открытой книги OpenOffice Calc, которую уже можно обработать и сохранить как csv, для последующего импорта в другие почтовые клиенты.

Если кому пригодится, то хорошо. Если нет, то сильно не ругайтесь из-за простыни.


P.S.
1) Можно было бы использовать более простую функцию чтения из файла, но в windows она упорно читала данные, считая, что они в кодировке cp1251 (не знаю почему).
2) Порядок полей и их позиция в таблице заданы явно потому, что не каждая запись в адресной книге имеет все эти поля, поэтому если они не встречаются, то ячейка в получившейся таблице должна остаться пустой.
3) Никаких диалоговых окон для выбора файла макрос не создаёт. Путь к файлу contacts.adr задаётся в переменной «FileName»
3) При запуске макроса открывается диалоговое окно выбора файла.
4) За счёт введения массива сократил «простыню» отвечающую за парсинг и запись данных в лист книги (надеюсь, что перед идентификатором в исходном файле адресной книги будет не больше одного символа табуляции).

REM *** OpenOffice Basic macros for converting OperaMail AddressBook (file "contacts.adr")
REM *** to current OpenOffice Calc Sheet using UTF-8 codepage.
REM *** After launching macros you need to choose "contacts.adr" 
REM *** in appearing OpenFIle Dialog window amd press OK/Open

Sub AddrBookConv_utf

' Variables for reading from file
Dim CurrentLine as String
DIm Buf as String
Dim FileName as String
Dim encoding as string
Dim i, j as Integer

' AddressBook record items
Dim AddrBookItem(13) As String
AddrBookItem = Array("ID", "NAME", "URL", "CREATED", "DESCRIPTION", "SHORT NAME", "ACTIVE", _
                     "MAIL", "PHONE", "FAX", "POSTALADDRESS", "PICTUREURL", "ICON", "M2INDEXID")
' symbol _ is using here for string wraping in openoffice basic code

' Variables for writing current Calc Sheet
Dim oDocument as object
Dim sContent as String
Dim oSheet as object
oDocument = ThisComponent
oSheet = oDocument.CurrentController.getActiveSheet()

' Open file
Filename = ""
FileName = ConvertFromUrl(fOpenFile())

' Checking that FIle was chosen and filename string is not empty now
' before start converting.
If Filename <> "" Then

  ' Writing AddressBook Item's Names (Column Names)
  i = 0
  For j = 0 To 13
    oSheet.getCellByPosition(j,0).Formula = AddrBookItem(j)
  Next j

  ' Opening file to read in UTF-8
  encoding = "UTF-8"  ' кодировка входного файла
  ' names of codepage are described here:
  ' http://www.iana.org/assignments/character-sets/character-sets.xhtml

  fileaccess = createUnoService ("com.sun.star.ucb.SimpleFileAccess")
  intextstream = createUnoService ("com.sun.star.io.TextInputStream")
  intextstream.setEncoding( encoding )
  intext = fileaccess.openFileRead( FileName )
  intextstream.setInputStream( intext )
        
  ' Check of reaching of the End of File
  Do While not intextstream.isEOF

    ' Reading line from File and parsing
    CurrentLine = intextstream.readLine
    If CurrentLine <> "" then
      SplitStringPar(CurrentLine, Buf)
      If InStr(Buf, AddrBookItem(0)) = 1 Then
        i = i + 1 
      End if

      For j = 0 To 13
        If InStr(Buf, AddrBookItem(j)) = 1 Then
          SplitString(CurrentLine, Buf)
          oSheet.getCellByPosition(j,i).Formula = Buf
        End if  
      Next j          
    End if

  Loop

' closing file
intextstream.closeInput()

End if

End Sub



REM *** Removing part of string before delimiter "="

Sub SplitString(InputStr as String, OutputStr as String)

        Dim DelimStr as String   ' delimiter
        Dim DelimPos as Integer  ' position of delimiter
        Dim StrLen As Integer    ' length of string
  
        DelimStr = "="
        StrLen = Len(InputStr)
        DelPos = InStr(InputStr, DelimStr)

        ' Removing string before delimeter
        OutputStr = Mid(InputStr, DelPos+1, StrLen-DelPos+1)
        
End Sub


REM *** Removing part of string after delimiter "=" and initial tabulation symbol

Sub SplitStringPar(InputStr as String, OutputStr as String)

        Dim DelimStr as String   ' delimiter
        Dim DelimPos as Integer  ' position of delimiter
        Dim StrLen As Integer    ' length of string

        DelimStr = "="
        StrLen = Len(InputStr)
        DelPos = InStr(InputStr, DelimStr)

        ' Removing string after delimiter
        OutputStr = Trim(Mid(InputStr, 1, DelPos-1))

        ' Removing initial tabulation symbol
        StrLen = Len(OutputStr)
        DelimStr = Chr(9) ' tabulation symbol
        DelPos = InStr(OutputStr, DelimStr)
        OutputStr = Mid(OutputStr, DelPos+1, StrLen-DelPos+1)

End Sub



REM *** Opens a Open File Dialog to allow the end user to select a file to import into the program.
REM *** This code is from Andrew Pitonyak's free Useful Macros book
Function fOpenFile() as String

        Dim oFileDialog as Object
        Dim iAccept as Integer
        Dim sPath as String
        Dim InitPath as String
        Dim oUcb as object
        Dim filterNames(2) as String

        filterNames(0) = "*.adr"
        filterNames(1) = "*.*"

        GlobalScope.BasicLibraries.LoadLibrary("Tools")
        'Note: The following services must be called in the following order,
        ' otherwise the FileDialog Service is not removed.
        oFileDialog = CreateUnoService("com.sun.star.ui.dialogs.FilePicker")
        oUcb = createUnoService("com.sun.star.ucb.SimpleFileAccess")

        AddFiltersToDialog(FilterNames(), oFileDialog)
        'Set your initial path here!
        InitPath = ConvertToUrl("~")

        If oUcb.Exists(InitPath) Then
        oFileDialog.SetDisplayDirectory(InitPath)
        End If

        iAccept = oFileDialog.Execute()
        If iAccept = 1 Then
        sPath = oFileDialog.Files(0)
                fOpenFile = sPath
        End If
        oFileDialog.Dispose()

End Function

 , ,

grem ()