[0001] [0002] [0003] [0004] [0005] [0006] [0007] [0008] [0009] [0010] [0011] [0012] [0013] [0014] [0015] [0016] [0017] [0018] [0019] [0020] [0021] [0022] [0023] [0024] [0025] [0026] [0027] [0028] [0029] [0030] [0031] [0032] [0033] [0034] [0035] [0036] [0037] [0038] [0039] [0040] [0041] [0042] [0043] [0044] [0045] [0046] [0047] [0048] [0049] [0050] [0051] [0052] [0053] [0054] [0055] [0056] [0057] [0058] [0059] [0060] [0061] [0062] [0063] [0064] [0065] [0066] [0067] [0068] [0069] [0070] [0071] [0072] [0073] [0074] [0075] [0076] [0077] [0078] [0079] [0080] [0081] [0082] [0083] [0084] [0085] [0086] [0087] [0088] [0089] [0090] [0091] [0092] [0093] [0094] [0095] [0096] [0097] [0098] [0099] [0100] [0101] [0102] [0103] [0104] [0105] [0106] [0107] [0108] [0109] [0110] [0111] [0112] [0113] [0114] [0115] [0116] [0117] [0118] [0119] [0120] [0121] [0122] [0123] [0124] [0125] [0126] [0127] [0128] [0129] [0130] [0131] [0132] [0133] [0134] [0135] [0136] [0137] [0138] [0139] [0140] [0141] [0142] [0143] [0144] [0145] [0146] [0147] [0148] [0149] [0150] [0151] [0152] [0153] [0154] [0155] [0156] [0157] [0158] [0159] [0160] [0161] [0162] [0163] [0164] [0165] [0166] [0167] [0168] [0169] [0170] [0171] [0172] [0173] [0174] [0175] [0176] [0177] [0178] [0179] [0180] [0181] [0182] [0183] [0184] [0185] [0186] [0187] [0188] [0189] [0190] [0191] [0192] [0193] [0194] [0195] [0196] [0197] [0198] [0199] [0200] [0201] [0202] [0203] [0204] [0205] [0206] [0207] [0208] [0209] [0210] [0211] [0212] [0213] [0214] [0215] [0216] [0217] [0218] [0219] [0220] [0221] [0222] [0223] [0224] [0225] [0226] [0227] [0228] [0229] [0230] [0231] [0232] [0233] [0234] [0235] [0236] [0237] [0238] [0239] [0240] [0241] [0242] [0243] [0244] [0245] [0246] [0247] [0248] [0249] [0250] [0251] [0252] [0253] [0254] [0255] [0256] [0257] [0258] [0259] [0260] [0261] [0262] [0263] [0264] [0265] [0266] [0267] [0268] [0269] [0270] [0271] [0272] [0273] [0274] [0275] [0276] [0277] [0278] [0279] [0280] [0281] [0282] [0283] [0284] [0285] [0286] [0287] [0288] [0289] [0290] [0291] [0292] [0293] [0294] [0295] [0296] [0297] [0298] [0299] [0300] [0301] [0302] [0303] [0304] [0305] [0306] [0307] [0308] [0309] [0310] [0311] [0312] [0313] [0314] [0315] [0316] [0317] [0318] [0319] [0320] [0321] [0322] [0323] [0324] [0325] [0326] [0327] [0328] [0329] [0330] [0331] [0332] [0333] [0334] [0335] [0336] [0337] [0338] [0339] [0340] [0341] [0342] [0343] [0344] [0345] [0346] [0347] [0348] [0349] [0350] [0351] [0352] [0353] [0354] [0355] [0356] [0357] [0358] [0359] [0360] [0361] [0362] [0363] [0364] [0365] [0366] [0367] [0368] [0369] [0370] [0371] [0372] [0373] [0374] [0375] [0376] [0377] [0378] [0379] [0380] [0381] [0382] [0383] [0384] [0385] [0386] [0387] [0388] [0389] [0390] [0391] [0392] [0393] [0394] [0395] [0396] [0397] [0398] [0399] [0400] [0401] [0402] [0403] [0404] [0405] [0406] [0407] [0408] [0409] [0410] [0411] [0412] [0413] [0414] [0415] [0416] [0417] [0418] [0419] [0420] [0421] [0422] [0423] [0424] [0425] [0426] [0427] [0428] [0429] [0430]
/* * Utility routines for script programs. These routines rationally handle * record mode access to the network logical link (zero length records are * valid, unlike in the C RTL). * * int net_link_open ( ) * int net_link_close() * int net_link_read ( char *buffer, int bufsize, int *read ) * int net_link_write ( char *buffer, int bufsize ) * int net_link_fetch ( char *tag, char *buffer, int bufsize, int *read ) * int net_link_set_rundown ( char *tag ); * int net_link_set_mode ( int mode ); * char * net_unescape_string ( char *arg, int *length ) * int net_link_printf ( char *ctl, ... ) * int net_link_saved_output ( char **buffer, int *length ); * * Date: 8-APR-1994 * Revised: 29-APR-1994 Added net_unquote_arg() and net_link_printf() * Revised: 1-MAY-1994 * Revised: 7-OCT-1994 Bug in unescape. * Revised: 26-DEC-1996 Add saved output mode (bit 1). */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <rms.h> /* Symbol and structure definitions for RMS */ #include <stdarg> #include "scriptlib.h" /* Validate prototypes against actual */ #define LINK_LOGICAL "NET_LINK:" #define IO_SIZE 1000 /* * Define module-side varaibles. */ static int net_link; /* I/O channel to DECnet link */ static int bin_mode = 0; /* If non-zero, do binary printfs */ static int save_puts = 0; /* If non-zero, save output */ static int saved_put_alloc = 0; /* Size of put data buffer */ static int saved_put_length = 0; static char *saved_put_data; /* Buffer to hold saved data */ static struct FAB net_fab; /* RMS file access block */ static struct RAB net_rab; /* RMS record access block */ static int printf_used; /* printf buffer used */ static struct { void *fwd_link; /* Next block in chain */ int (*handler)(); /* exit handler */ int arg_count; int *condition; /* Exit reason */ int reason; int link_open; /* flag */ char rundown_tag[512]; /* Exit string */ } exit_block; static char printf_buffer[8192]; /**************************************************************************/ /* Call close function if link still open, this will flush the printf buffer. */ static int exit_handler ( int *reason ) { if ( !exit_block.link_open ) return 1; net_link_close(); return 1; } /**************************************************************************/ /* Initialize network connection. Make RMS open for PPF assigned to * net link logical name. Return value is RMS compleition status. */ int net_link_open ( ) { int status, SYS$OPEN(), SYS$CONNECT(), SYS$DCLEXH(); /* * Open network link as file. */ net_fab = cc$rms_fab; /* Set default values */ net_fab.fab$l_fna = LINK_LOGICAL; net_fab.fab$b_fns = strlen(net_fab.fab$l_fna); net_fab.fab$b_fac = FAB$M_GET + FAB$M_PUT; net_fab.fab$b_rfm = FAB$C_VAR; printf_used = 0; status = SYS$OPEN ( &net_fab ); if ( (status&1) == 0 ) return status; /* * Connect record stream to open file. */ net_rab = cc$rms_rab; net_rab.rab$l_fab = &net_fab; net_rab.rab$b_rac = RAB$C_SEQ; status = SYS$CONNECT ( &net_rab ); if ( (status&1) == 0 ) return status; /* * Establish exit handler to cleanly close link. */ exit_block.handler = &exit_handler; exit_block.arg_count = 1; exit_block.condition = &exit_block.reason; exit_block.link_open = 1; exit_block.rundown_tag[0] = '\0'; status = SYS$DCLEXH ( &exit_block ); return status; } /**************************************************************************/ /* Set string that close will automatically send at link close. * If string is zero-length, no final message will be sent. */ int net_link_set_rundown ( char *tag ) { strncpy ( exit_block.rundown_tag, tag, sizeof(exit_block.rundown_tag)-1 ); exit_block.rundown_tag[sizeof(exit_block.rundown_tag)-1] = '\0'; return 1; } /**************************************************************************/ /* Flush printf_buffer to network connection. */ static int net_link_flush ( ) { int status, SYS$PUT(); if ( printf_used <= 0 ) return 1; if ( save_puts == 0 ) { net_rab.rab$w_rsz = printf_used; net_rab.rab$l_rbf = printf_buffer; printf_used = 0; status = SYS$PUT ( &net_rab ); } else { if ( (printf_used + saved_put_length) > saved_put_alloc ) { while ( (printf_used + saved_put_length) > saved_put_alloc ) { saved_put_alloc += 20000; } saved_put_data = (char *) realloc(saved_put_data, saved_put_alloc); } memcpy (&saved_put_data[saved_put_length], printf_buffer, printf_used); saved_put_length += printf_used; printf_used = 0; status = 1; } return status; } /**************************************************************************/ /* Set value for mode flag, bit mask: * <0> 0 - text mode (default), 1 - binary mode. * <1> 0 - pass puts to net_link, 1 - save puts to buffer. * * In binary mode, printf does not expand linefeed to cr/lf pairs. * * Return value is previous mode. */ int net_link_set_mode ( int new_mode ) { int prev_mode; net_link_flush(); prev_mode = bin_mode | (save_puts<<1); bin_mode = (new_mode&1); if ( new_mode&2 ) { save_puts = 1; if ( saved_put_alloc == 0 ) { /* do initial allocation of put buffer */ saved_put_alloc += 20000; saved_put_data = (char *) malloc ( saved_put_alloc ); } } else { save_puts = 0; } return prev_mode; } /**************************************************************************/ /* Close link openned by net_link_open. */ int net_link_close() { int status, SYS$CLOSE ( ); /* * Flush pending printfs and rundown tag if present. */ #ifdef DEBUG printf("closing connection, printf buffer used: %d, rundown tag: '%s'\n", printf_used, exit_block.rundown_tag ); #endif if ( printf_used > 0 ) status = net_link_flush(); if ( *exit_block.rundown_tag ) status = net_link_write (exit_block.rundown_tag, strlen(exit_block.rundown_tag) ); exit_block.rundown_tag[0] = '\0'; net_fab.fab$l_fop = 0; status = SYS$CLOSE ( &net_fab ); exit_block.link_open = 0; return status; } /**************************************************************************/ /* Read record from network connection. Return value is VMS condition code. */ int net_link_read ( void *buffer, int bufsize, int *nread ) { int status, SYS$GET(); if ( printf_used > 0 ) status = net_link_flush(); net_rab.rab$l_ubf = buffer; net_rab.rab$w_usz = bufsize; status = SYS$GET ( &net_rab ); *nread = net_rab.rab$w_rsz; /* size of record read */ return status; } /**************************************************************************/ /* Write user's buffer to network connection. */ int net_link_write ( void *buffer, int bufsize ) { int status, SYS$PUT(); if ( printf_used > 0 ) status = net_link_flush(); if ( save_puts == 0 ) { net_rab.rab$w_rsz = bufsize; net_rab.rab$l_rbf = buffer; status = SYS$PUT ( &net_rab ); } else { /* * Save data in large char array for retrieval by net_link_saved_output. */ if ( (bufsize + saved_put_length) > saved_put_alloc ) { while ( (bufsize + saved_put_length) > saved_put_alloc ) { saved_put_alloc += 20000; } saved_put_data = (char *) realloc(saved_put_data, saved_put_alloc); } memcpy ( &saved_put_data[saved_put_length], buffer, bufsize ); saved_put_length += bufsize; status = 1; } return status; } /**************************************************************************/ /* Write tag as prompt and read response into buffer. */ int net_link_query ( void *tag, void *buffer, int bufsize, int *nread ) { int status, tag_length; status = net_link_write ( tag, strlen ( tag ) ); if ( (status&1) == 1 ) status = net_link_read ( buffer, bufsize, nread ); return status; } /**************************************************************************/ /* Provide formatted output to net_link, replacing printf calls to stdout. * Newline chars in format string are replaced with carriage-return/linefeed * pairs. */ int net_link_printf ( char *fmt, ... ) { va_list alist; int state, out_len, status, j; char *fc, *conv, *out_buffer; char conv_buffer[4096], conv_spec[64], c_arg; /* * Setup pointer to variable argument list. */ va_start ( alist, fmt ); /* * Transfer characters from control string to output buffer. */ out_len = printf_used; out_buffer = printf_buffer; for ( state = 0, fc = fmt; *fc; fc++ ) { if ( state == 0 ) { /* Looking for next conversion character */ if ( *fc == '%' ) { /* Begin parse of conversion specification. */ state = 1; conv_spec[0] = '%'; conv = &conv_spec[1]; out_buffer[out_len] = '\0'; } else { /* add CR to precede LF in out_buf */ if ( *fc == '\n' ) if ( !bin_mode ) out_buffer[out_len++] = '\r'; out_buffer[out_len++] = *fc; } } else { /* * Append character to conversion string and see if it * is terminal. */ *conv++ = *fc; if ( strchr ( "-0123456789.l", *fc ) == NULL ) { long long_arg; int int_arg; char *char_arg; double dbl_arg; *conv = '\0'; /* terminate specifier string */ switch ( *fc ) { case 'd': case 'o': case 'x': case 'D': case 'O': case 'X': case 'u': case 'U': if ( state == 1 ) { int_arg = va_arg ( alist, int ); sprintf ( conv_buffer, conv_spec, int_arg ); } else { long_arg = va_arg ( alist, int ); sprintf ( conv_buffer, conv_spec, long_arg ); } break; case 's': case 'S': char_arg = va_arg ( alist, char * ); sprintf ( conv_buffer, conv_spec, char_arg ); break; case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': dbl_arg = va_arg ( alist, double ); sprintf ( conv_buffer, conv_spec, dbl_arg ); break; case 'c': case 'C': c_arg = va_arg ( alist, char ); sprintf ( conv_buffer, conv_spec, c_arg ); break; default: /* Copy contents to output string */ strcpy ( conv_buffer, &conv_spec[1] ); } /* * Conversion complete, Copy chars to out_buffer, replacing * '\n' with '\r\n'; */ state = 0; for ( conv = conv_buffer; *conv; out_buffer[out_len++] = *conv++ ) { if ( *conv == '\n' ) { if ( !bin_mode ) out_buffer[out_len++] = '\r'; } } } else if ( *fc == 'l' ) state = 2; /* Long */ } /* * Flush buffer if full. */ while ( out_len >= IO_SIZE ) { printf_used = IO_SIZE; status = net_link_flush(); if ( (status&1) == 0 ) return status; /* Transfer characters not moved to beginning of buffer */ for ( j = IO_SIZE; j < out_len; j++ ) { out_buffer[printf_used++] = out_buffer[j]; } out_len = printf_used; } } va_end ( alist ); /* * Flush conversion spec buffer if needed and send final output to * server. */ printf_used = out_len; if ( state != 0 ) { /* Dangling conversion specification */ status = net_link_flush(); if ( (status&1) == 0 ) return status; *conv = '\0'; strcpy ( out_buffer, &conv_spec[1] ); printf_used = strlen ( out_buffer ); } return 1; } /**************************************************************************/ /* Convert escaped characters in string to actual values. * * Arguments: * string Character string. Modified. * length Int. On input, original length of string. * On output, final length of unescaped string. */ char * net_unescape_string ( char *string, int *length ) { int i, j, reslen, modified; /* * Scan string. */ for ( modified = reslen = i = 0; i < *length; i++ ) { if ( string[i] == '%' ) { /* * Escape seen, decode next 2 characters as hex and replace * all three with single byte. */ char value[4]; int val; value[0] = string[i+1]; value[1] = string[i+2]; value[2] = '\0'; i += 2; sscanf ( value, "%2x", &val ); if ( val > 127 ) val |= (-1 ^ 255); /* Sign extend */ string[reslen] = val; modified = 1; } else { /* Only copy bytes if escape edit took place. */ if ( modified ) string[reslen] = string[i]; } reslen++; } /* Return value is point to string editted. */ *length = reslen; return string; } /*****************************************************************************/ /* Return pointer to saved buffer region and saved length. Mode is NOT reset, * so additional writes may reallocate buffer. */ int net_link_saved_output ( char **buffer, int *length ) { int status; if ( saved_put_alloc <= 0 ) return 0; /* allocation failure */ status = net_link_flush(); *buffer = saved_put_data; *length = saved_put_length; return status; }