|
rpcgenНАЗВАНИЕ СИНТАКСИС rpcgen вх_файл rpcgen -h [-o вых_файл] [вх_файл] rpcgen -c [-o вых_файл] [вх_файл] rpcgen -m [-o вых_файл] [вх_файл] rpcgen -l [-o вых_файл] [вх_файл] rpcgen [-s транспорт]* [-o вых_файл] [вх_файл] ОПИСАНИЕ Все остальные варианты вызова компилятора связаны с созданием только одного выходного файла. К рассмотрению каждого из вариантов мы перейдем ниже. Все выходные файлы перед интерпретацией rpcgen проходят обработку Си-препроцессором cpp(CP), поэтому директивы cpp во входном файле rpcgen допустимы. Каждому типу выходного файла соответствует специальный символ cpp: RPC_HDR, RPC_XDR, RPC_SVC и RPC_CLNT. Rpcgen, кроме того, сам выполняет некоторую предварительную обработку входных данных. Любая строка, открывающаяся символом "%", передается сразу в выходной файл, без интерпретации. Отдельные XDR-процедуры можно настраивать, не определяя их
тип. При этом rpcgen будет предполагать существование процедуры с
именем, состоящим из имени неопределенной структуры и приставки
xdr_.
Настоятельно рекомендуем вам, прежде чем приступить к использованию утилиты rpcgen, прочитать главы, посвященные RPC и XDR, в
"Руководстве программиста SCO NFS".
ОПЦИИ
ИСПОЛЬЗОВАНИЕ [unsigned] char [unsigned] short [unsigned] int [unsigned] long unsigned float double void boolЕсли не считать типа bool (булевы данные), во всем остальном RPCL подобен Си. В выходном файле заголовков rpcgen преобразует определения
bool в определения int (точнее говоря, в определения bool_t, которые операцией #define описаны как int). Кроме того, тип void
может появиться только в определениях union и program. Для типов
с приставкой unsigned допустимо использование аббревиатуры uchar,
ushort, uint и ulong.
ОПРЕДЕЛЕНИЯ
Rpcgen используется для генерации процедуры XDR и/или файла заголовков, описывающего типы данных из входного файла. Для каждого описываемого zetype утилита rpcgen создает соответствующую процедуру XDR, именуемую xdr_zetype и обязательную для создания RPC-программ. Существуют шесть способов описания типа: описание_типа: typedef перечислимый_тип-def структура-def массив_переменной_длины-def размеченное_объединение-def программа-def Первые три очень похожи на своих тезок в Си. Вместе с тем в Си отсутствует формальный механизм описания массивов переменной длины, а XDR-объединения совершенно не похожи на соответствующие объекты в Си. Вложенность описаний типов в XDR не допускается. Например, следующая запись для rpcgen будет непонятна: struct dontdoit { struct ididit { int oops; } sorry; enum ididitagain { OOPS, WHOOPS } iapologize; }; Оператор typedef в XDR выглядит следующим образом: typedef: typedef имя_типа идентификатор_объекта ;"Идентификатор объекта" является именем нового типа, в то время как "имя_типа" относится к исходному типу. Например: typedef longa; Синтаксис описания перечислимого типа: перечислимый_тип-def: enum идентификатор_типа { список_типов }; список_типов: символьный_идентификатор [=присваивание] символьный_идентификатор [=присваивание], список_типов (в правой части оператора, после знака равенства может распо- лагаться целая или символьная константа)Если явного присваивания нет, неявно будет присвоено значение предыдущего элемента перечисления, увеличенное на 1. Первый элемент по умолчанию имеет нулевое значение. Структуры: структура-def: struct идентификатор_структуры { список_описаний }; список_описаний: описание; описание; список_описанийМассивы переменной длины: массив_переменной_длины-def: array идентификатор_массива { unsigned идентификатор_длины ; векторное_определение ; };Описание массива переменной длины похоже на описание структуры. Пример: array mp_int { unsigned len; short val[MAX_MP_LENGTH]; };Эта запись преобразуется компилятором в: struct mp_int { unsigned len; short *val; }; typedef struct mp_int mp_int;Размеченное объединение: размеченное_объединение-def: union идентификатор_объединения switch (описание_дискриминанта) { список_случаев [default: описание;] }; список_случаев: case идентификатор_случая : описание; case идентификатор_случая : описание; список_случаев описание_дискриминанта: описание Описание объединения похоже на пересечение Си-объединения с Си-переключателем. Пример: union net_object switch (net_kind kind) { case MACHINE: struct sockaddr_in sin; case USER: int uid; default: string whatisit; };Эта запись преобразуется компилятором в: struct net_object { net_kind kind; union { struct sockaddr_in sin; int uid; char *whatisit; } net_object; }; typedef struct net_object net_object; Обратите внимание на то, что имя объединяющей компоненты в выходной структуре совпадает с именем самого типа. Описания программ: программа-def: program идентификатор_программы { список_версий }=номер_программы; список_версий: версия версия список_версий версия: version идентификатор_версии { список_процедур }=номер_версии; список_процедур: описание_процедуры описание_процедуры список_процедур описание_процедуры: имя_типа идентификатор_процедуры(имя_типа)=номер_процедуры; Описания программ не похожи ни на что из ранее виденного вами, поэтому нам ничего больше не остается, как прибегнуть к примеру. Предположим, что нам нужно создать механизм (серверный) получения или установки даты. Его описание может выглядеть следующим образом: program DATE_PROG { version DATE_VERS { date DATE_GET(timezone) = 1; void DATE_SET(date) = 2; /* время по Гринвичу */ } = 1; } = 100;В файле заголовков эта запись будет иметь следующий вид: #define DATE_PROG 100 #define DATE_VERS 1 #define DATE_GET 1 #define DATE_SET 2 Если вы используете rpcgen для компиляции серверных процедур, вам необходимо ознакомиться с некоторыми важными моментами. Сервер взаимодействует с вашими локальными процедурами через Си-функцию, имя которой совпадает с именем в описании программы, но записывается строчными буквами и оканчивается номером версии. Рассмотрим локальную процедуру реализации DATE_GET: date * /* всегда возвращает указатель на результаты */ date_get_l(tz) timezone *tz; /* всегда получает указатель на аргументы */ { static date d; /* должна быть статической! */ /* * получение даты * и сохранение ее в d */ return(&d); } Имя процедуры совпадает с именем, объявленным в #define, но
записывается строчными буквами и оканчивается номером версии. XDR
рекурсивно освобождает аргумент после получения результатов из
локальной процедуры, поэтому всю необходимую вам информацию из
аргумента следует скопировать между обращениями. При этом XDR не
манипулирует вашими результатами. Вам следует позаботиться об их
сохранении самим.
Вывод правил компиляции заголовков .SUFFIXES:.x .x.c: rpcgen -c $< -o $@ .x.h: rpcgen -h $< -o $@Пример: Рассмотрим программу example, в которой описываются данные трех типов: const NFS_PORT = 2059; enum nfsstat { NFS_OK=0 }; struct gnumbers { long g_assets; long g_liabilities; };Утилита rpcgen, вызванная без аргументов, создает файл заголовков example.h и файл XDR с именем example_xdr.c. example.h #define NFS_PORT 2059 enum nfsstat { NFS_OK = 0, }; typedef enum nfsstat nfsstat; bool_t xdr_nfsstat(); struct gnumbers { long g_assets; long g_liabilities; }; typedef struct gnumbers gnumbers; bool_t xdr_gnumbers(); example_xdr.c #include <rpc/rpc.h> #include "infile.h" bool_t xdr_nfsstat (xdrs, objp) XDR *xdrs; nfsstat *objp; { if (!xdr_enum(xdrs, (enum_t *)objp)) { return (FALSE); } return (TRUE); } bool_t xdr_numbers (xdrs, objp) XDR *xdrs; gnumbers *objp; { if (!xdr_long(xdrs, &objp->g_assets)) { return (FALSE); } if (!xdr_long(xdrs, &objp->g_liabilities)) { return (FALSE); } return (TRUE); } СМ. ТАКЖЕ ЗАМЕЧАНИЯ Вложенность также не поддерживается. Чтобы сымитировать эффект вложенности, объявление структур можно производить на верхнем уровне с тем, чтобы использовать их имена внутри других процедур. |
|