John Forkosh Associates ®
V M S l i b   S o u r c e   L i s t i n g
Copyright © 1986-2010, John Forkosh Associates, Inc.
All rights reserved.

Click for:   homepage,   resume



VV      VV MM      MM   SSSSSSS  LLLLL        IIIIII   BBBBBBBB                CCCCCCC 
VV      VV MMM    MMM  SSSSSSSSS LLLLL        IIIIII   BBBBBBBBB              CCCCCCCCC
VV      VV MMMM  MMMM SS          LL            II      BB     BB            CC      CC
VV      VV MM MMMM MM  SSSSSSS    LL            II      BBBBBBBB    .        CC        
 VV    VV  MM  MM  MM   SSSSSSS   LL            II      BBBBBBBB   ...       CC        
  VV  VV   MM      MM         SS  LL     LL     II      BB     BB .....      CC      CC
   VVVV    MM      MM SSSSSSSSS  LLLLLLLLLL   IIIIII   BBBBBBBBB   ...        CCCCCCCCC
    VV     MM      MM  SSSSSSS   LLLLLLLLLL   IIIIII   BBBBBBBB     .          CCCCCCC 

  1: /****************************************************************************
  2:  *
  3:  * Copyright (c) 1986-1999 John Forkosh Associates, Inc.  All rights reserved.
  4:  * --------------------------------------------------------------------------
  5:  *
  6:  * Purpose:     Library of "wrappers" for VMS system functions.
  7:  *              For example, application-level code (usually) need not
  8:  *              #include < descrip.h > or other VMS-specific headers.
  9:  *              Only standard C datatypes are passed to library functions.
 10:  *              Also, housekeeping is done internally where possible,
 11:  *              and various parameters are defaulted to what I feel is
 12:  *              most typical usage (which you may need to modify for
 13:  *              purposes I've failed to anticipate).
 14:  *              Note: cc/define=TESTDRIVE to compile test driver main()
 15:  *              at bottom of this file.
 16:  *
 17:  * Functions:
 18:  *              vmsascefc(efcn,name) associate event flag cluster
 19:  *              vmsbeep(nbeeps) beep the terminal
 20:  *              vmsclrefn(efcn,efn) clear event flag efn in cluster efcn
 21:  *              vmscrelnm(lognam,logval,tabnam) create logical name in table
 22:  *              vmscrembx(mbxnam,chan) create/assign mailbox
 23:  *              vmscrmpsc(gsdnam,pagcnt,inadr) create/map global section
 24:  *              vmsdellnm(lognam,tabnam) deletes logical name in table
 25:  *              vmsdeltatime(millisecs) convert millisecs to vms quadword
 26:  *              vmsetefn(efcn,efn) set event flag efn in cluster efcn
 27:  *              vmsforcex(pid) force process id pid to exit
 28:  *              vmsgrpmbx() set temp mailboxes in group table for ipc
 29:  *              vmsleepms(millisecs) sleep for millisecs
 30:  *              vmsmsg(vms_stat) description of SS$_status symbol
 31:  *              vmspawn(cmdstr,efn,isnotify) spawn subprocess
 32:  *              vmsrdefn(efn) check whether event flag is set
 33:  *              vmsrdmbx(chan,message,msglen,iswait) read msg from mailbox
 34:  *              vmstime(year,month,day,hour,min,sec,hundredths,wkday) time
 35:  *              vmstrnlnm(lognam,logval) translate logical name
 36:  *              vmswflor(mask,flag) wait for any event flag in mask to be set
 37:  *              vmswrtmbx(chan,message,msglen,iswait) write msg to mailbox
 38:  *
 39:  * Source:      VMSLIB.C
 40:  *
 41:  * --------------------------------------------------------------------------
 42:  * Revision History:
 43:  * 12/02/98     J.Forkosh       Cleaned up prior to copyright registration.
 44:  *
 45:  ****************************************************************************/
 46: 
 47: /* -------------------------------------------------------------------------
 48: Header files and other definitions
 49: -------------------------------------------------------------------------- */
 50: /* --- standard vms headers --- */
 51: #include < stdio.h >
 52: #include < descrip.h >
 53: #include < ssdef.h >
 54: #include < iodef.h >
 55: #include < lnmdef.h >
 56: #include < secdef.h >
 57: /* --- debugging and error handling --- */
 58: #ifndef MSGLEVEL
 59: #define MSGLEVEL 1
 60: #endif
 61: static  int msglevel = MSGLEVEL;                /* message level for debug */
 62: char    *vmsmsg();                              /* description of errors */
 63: /* --- vms "data types" --- */
 64: #define WORD short                              /* 16-bits */
 65: #define LONGWORD int                            /* 32-bits */
 66: /* --- other definitions --- */
 67: extern  int sys$qiow(), sys$qio();              /* for int (*sys$func)() */
 68: #define PAGSIZE 512
 69: char    inbuf[64];                              /* dummy target for crmpsc */
 70: #define setbit(x,bit) ( x |= (1<< bit) )        /* set 'bit' position of x */
 71: /* --- flag word masks for lib$spawn --- */
 72: #define NOWAIT          1
 73: #define NOCLISYM        2
 74: #define NOLOGNAM        4
 75: #define NOKEYPAD        8
 76: #define NOTIFY          16
 77: #define NOCONTROL       32
 78: /* --- item list (layout from descrip.h) --- */
 79: #define ITMLST struct itmlst
 80: ITMLST
 81:   {
 82:   short buflen;                         /* max length of buffer */
 83:   short item_code;                      /* type of item requested in buffer*/
 84:   char  *bufadr;                        /* address of buffer */
 85:   short *retlenadr;                     /* addr of returned buffer length */
 86:   } ;
 87: 
 88: 
 89: /* ==========================================================================
 90:  * Function:    vmsascefc ( efcn, name )
 91:  * Purpose:     Associate a common event flag cluster with a process
 92:  *              for the execution of the current image.
 93:  * --------------------------------------------------------------------------
 94:  * Arguments:   efcn (I)        int containing either 2 or 3, to associate
 95:  *                              with cluster 2 or 3, respectively.
 96:  *              name (I)        addr of char string containing the name of
 97:  *                              the common event flag cluster with which
 98:  *                              to associate.
 99:  * --------------------------------------------------------------------------
100:  * Returns:     ( int )         SS$_NORMAL for successful completion,
101:  *                              VMS error status otherwise.
102:  * --------------------------------------------------------------------------
103:  * Notes:       Cluster 2 contains event flag numbers 64 to 95,
104:  *              cluster 3 contains efn's 96 to 127.  Clusters 0 and 1
105:  *              are always process-local event flag clusters.
106:  * ======================================================================= */
107: /* --- entry point --- */
108: int     vmsascefc ( efcn, name )
109: int     efcn;
110: char    *name;
111: {
112: /* -------------------------------------------------------------------------
113: Allocations and Declarations
114: -------------------------------------------------------------------------- */
115: struct  dsc$descriptor_s                        /* name descriptor */
116:         nam_desc = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, name };
117: int     efn;                                    /* efn for cluster efcn */
118: int     vms_stat;                               /* VMS return status */
119: /* -------------------------------------------------------------------------
120: Issue $ascefc and return
121: -------------------------------------------------------------------------- */
122: nam_desc.dsc$w_length = strlen(name);           /* desc string length */
123: efn = 32*efcn;                                  /* first efn in cluster */
124: vms_stat = SYS$ASCEFC
125:                 (
126:                 efn,                            /* event flag in cluster */
127:                 &nam_desc,                      /* cluster name descriptor */
128:                 0,                              /* prot - any proc in group */
129:                 0                               /* perm - temp cluster */
130:                 );
131: return ( vms_stat );
132: } /* --- end-of-function vmsascefc() --- */
133: 
134: 
135: /* ==========================================================================
136:  * Function:    vmsbeep ( nbeeps )
137:  * Purpose:     Beep the terminal nbeeps times.
138:  * --------------------------------------------------------------------------
139:  * Arguments:   nbeeps (I)      int containing #beeps to emit at terminal.
140:  * --------------------------------------------------------------------------
141:  * Returns:     ( int )         SS$_NORMAL if beeped successfully (always).
142:  * --------------------------------------------------------------------------
143:  * Notes:     o Probably pretty portable.
144:  * ======================================================================= */
145: /* --- entry point --- */
146: int     vmsbeep ( nbeeps )
147: int     nbeeps;
148: {
149: char    bel = '\007';                           /* ^G usually beeps */
150: while ( --nbeeps >= 0 ) printf("%c",bel);       /* issue beeps to user */
151: return ( SS$_NORMAL );                          /* back after beep-beeping */
152: } /* --- end-of-function vmsbeep() --- */
153: 
154: 
155: /* ==========================================================================
156:  * Function:    vmclrefn ( efcn, efn )
157:  * Purpose:     Clear event flag efn in cluster efcn.
158:  * --------------------------------------------------------------------------
159:  * Arguments:   efcn (I)        int containing either 2 or 3, to clear
160:  *                              flag in cluster 2 or 3, respectively.
161:  *              efn (I)         int containing the number of the event flag
162:  *                              to be cleared, 0-31.
163:  * --------------------------------------------------------------------------
164:  * Returns:     ( int )         0 if efn was previously clear (SS$_WASCLR),
165:  *                              1 if efn was already set (SS$_WASSET), or
166:  *                              -1 for VMS error.
167:  * --------------------------------------------------------------------------
168:  * Notes:
169:  * ======================================================================= */
170: /* --- entry point --- */
171: int     vmsclrefn ( efcn, efn )
172: int     efcn;
173: int     efn;
174: {
175: /* --- Allocations and Declarations --- */
176: int     vms_stat;                               /* $clref VMS return status*/
177: int     efn_stat = (-1);                        /* previous state of efn */
178: /* --- Clear event flag and return to caller. --- */
179: if ( efcn < 0 || efcn > 3 )                     /* efn contains all info */
180:   efcn = efn/32;                                /* get cluster from efn */
181: vms_stat = SYS$CLREF                            /* clear the flag */
182:         ( 32*efcn + efn%32 );                   /* 1st efn + flag to clear */
183: if ( vms_stat == SS$_WASSET ) efn_stat=1;       /* return 1 if efn was set */
184: else if ( vms_stat == SS$_WASCLR ) efn_stat=0;  /* or 0 if efn was clear */
185: else if ( msglevel >= 1 )                       /* or report error */
186:   printf("vmsclrefn() error: %s\n",vmsmsg(vms_stat));
187: return ( efn_stat );                            /* previous state to caller*/
188: } /* --- end-of-function vmsclrefn() --- */
189: 
190: 
191: /* ==========================================================================
192:  * Function:    vmscrelnm ( lognam, logval, tabnam )
193:  * Purpose:     Creates a VMS logical name in specified table.
194:  * --------------------------------------------------------------------------
195:  * Arguments:   lognam (I)      addr of char string containing logical name
196:  *                              to be created.
197:  *              logval (I)      addr of char string containing equivalence
198:  *                              name to be assigned to lognam.
199:  *              tabnam (I)      addr of char string containing name of
200:  *                              logical name table in which to create
201:  *                              the logical name - defaults to group table
202:  *                              if you pass NULL address.
203:  * --------------------------------------------------------------------------
204:  * Returns:     SS$_NORMAL      for successful completion
205:  * --------------------------------------------------------------------------
206:  * Notes:
207:  * ======================================================================= */
208: /* --- entry point --- */
209: int     vmscrelnm( lognam, logval, tabnam )
210: char    *lognam;
211: char    *logval;
212: char    *tabnam;
213: {
214: /* --------------------------------------------------------------------------
215: Allocations and Declarations
216: -------------------------------------------------------------------------- */
217: char    tabbuf[64];                     /* buffer for table name */
218: struct  dsc$descriptor_s                /*local descriptor for logical name*/
219:         tab_desc = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, &tabbuf[0] },
220:         log_desc = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, lognam };
221: short   vallen;                         /* len of created equivalence name */
222: int     vms_stat;                       /* VMS return status */
223: ITMLST crelst[] =
224:   {
225:     { 0, LNM$_STRING, logval, &vallen },
226:     { 0,0,0,0 }
227:   };
228: /* --------------------------------------------------------------------------
229: Initialize args
230: -------------------------------------------------------------------------- */
231: strcpy ( tabbuf, "LNM$" );              /*user need not pass this in tabnam*/
232: if ( tabnam != (char *)NULL )           /* caller passed table name arg */
233:      strcat ( tabbuf, tabnam );         /* so concat tabnam passed by user */
234: else strcat ( tabbuf, "GROUP");         /* or default to group table */
235: tab_desc.dsc$w_length = strlen(tabbuf); /* set tabnam length in descriptor */
236: log_desc.dsc$w_length = strlen(lognam); /* set lognam length in descriptor */
237: crelst[0].buflen = strlen(logval);      /* and length of equivalence name */
238: /* --------------------------------------------------------------------------
239: Issue $crelnm, and Return. 
240: -------------------------------------------------------------------------- */
241: vms_stat = SYS$CRELNM                   /* issue $crelnm */
242:         (
243:         0,                              /* attributes controlling search */
244:         &tab_desc,                      /* list of table names to search */
245:         &log_desc,                      /* logical name to be translated */
246:         0,                              /* access mode */
247:         &crelst[0]                      /* item list */
248:         );
249: return( vms_stat );
250: } /* --- end-of-function vmscrelnm() --- */
251: 
252: 
253: /* ==========================================================================
254:  * Function:    vmscrembx ( mbxnam, chan )
255:  * Purpose:     Creates vms mailbox (or assigns channel to existing mailbox)
256:  * --------------------------------------------------------------------------
257:  * Arguments:   mbxnam (I)      addr of char string containing "logical"
258:  *                              name of mailbox to be created (assigned).
259:  *              chan (O)        addr of int returning channel assigned
260:  *                              to mailbox ( or -1 for error).
261:  * --------------------------------------------------------------------------
262:  * Returns:     ( int )         SS$_NORMAL if successful,
263:  *                              vms error otherwise.
264:  * --------------------------------------------------------------------------
265:  * Notes:     o
266:  * ======================================================================= */
267: /* --- entry point --- */
268: int     vmscrembx ( mbxnam, chan )
269: char    *mbxnam;
270: int     *chan;
271: {
272: /* -------------------------------------------------------------------------
273: Allocations and Declarations
274: -------------------------------------------------------------------------- */
275: struct  dsc$descriptor_s                        /* mailbox descriptor */
276:         mbx_desc = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, mbxnam };
277: int     status;                                 /* vms status of $crembx */
278: WORD    mbxchan;                                /* 16-bit channel arg */
279: LONGWORD maxmsg=4096,                           /* maximum message size */
280:         bufquo=16384;                           /* total buffer size */
281: /* -------------------------------------------------------------------------
282: Issue $crembx and return
283: -------------------------------------------------------------------------- */
284: mbx_desc.dsc$w_length = strlen(mbxnam);         /* desc string length */
285: status = SYS$CREMBX
286:                 (
287:                 0,                              /* prmflg - temp/perm flag*/
288:                 &mbxchan,                       /* chan - assigned to mbx */
289:                 maxmsg,                         /* maxmsg-msg size in bytes*/
290:                 bufquo,                         /* bufquo - mailbox size */
291:                 0,                              /* promsk - protection mask*/
292:                 0,                              /* acmode - access */
293:                 &mbx_desc,                      /* lognam - mailbox name */
294:                 0                               /* flags */
295:                 );
296: *chan = (int)mbxchan;                           /* return channel to caller*/
297: if ( status != SS$_NORMAL )                     /* unless $crembx failed */
298:   { *chan = (-1);                               /* in which case return -1 */
299:     if ( msglevel >= 1 )                        /* error messages wanted */
300:       printf("vmscrembx() $crembx error %s\n",vmsmsg(status)); }
301: else
302:     if ( msglevel >= 99 )                       /* debug messages wanted */
303:       printf("vmscrembx() assigned chan %d to mbx %s\n",*chan,mbxnam);
304: return ( status );                              /* back with $crembx status*/
305: } /* --- end-of-function vmscrembx() --- */
306: 
307: 
308: /* ==========================================================================
309:  * Function:    vmscrmpsc ( gsdnam, pagcnt, inadr )
310:  * Purpose:     Creates and maps a global section.
311:  * --------------------------------------------------------------------------
312:  * Arguments:   gsdnam (I)      addr of char string containing
313:  *                              name of the global section to be created.
314:  *              pagcnt (I)      int containing number of 512-byte pages
315:  *                              in the global section.
316:  *              inadr (O)       ptr to addr of unsigned char returning
317:  *                              starting addr where section was mapped.
318:  * --------------------------------------------------------------------------
319:  * Returns:     ( int )         SS$_NORMAL if mapped to existing section,
320:  *                              SS$_CREATED if section was just created,
321:  *                              VMS error status otherwise.
322:  * --------------------------------------------------------------------------
323:  * Notes:
324:  * ======================================================================= */
325: /* --- entry point --- */
326: int     vmscrmpsc ( gsdnam, pagcnt, inadr )
327: char    *gsdnam;
328: int     pagcnt;
329: void    **inadr;
330: {
331: /* -------------------------------------------------------------------------
332: Allocations and Declarations
333: -------------------------------------------------------------------------- */
334: int     inadr_quadwd[2],retadr_quadwd[2];       /* inadr,retadr quadwords */
335: int     flags;                                  /* type of section */
336: static  char gsdbuf[64];                        /* section name buffer */
337: struct  dsc$descriptor_s                        /* gsdnam descriptor */
338:         gsd_desc = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, &gsdbuf[0] };
339: int     vms_stat;                               /* sys$crmpsc return status*/
340: /* -------------------------------------------------------------------------
341: Issue $crmpsc and return
342: -------------------------------------------------------------------------- */
343: flags = SEC$M_GBL | SEC$M_WRT | SEC$M_PAGFIL | SEC$M_EXPREG;
344: inadr_quadwd[0] = inbuf;                        /* starting addr of section*/
345: inadr_quadwd[1] = 0;                            /* ending addr of section */
346: strcpy ( gsdbuf, gsdnam );                      /*local desc copy of gsdnam*/
347: gsd_desc.dsc$w_length = strlen(gsdbuf);         /* desc string length */
348: vms_stat = SYS$CRMPSC
349:                 (
350:                 inadr_quadwd,                   /* requested virtual addrs*/
351:                 retadr_quadwd,                  /* actual virtual addrs */
352:                 0,                              /* access mode */
353:                 flags,                          /* type of section mask */
354:                 &gsd_desc,                      /* section name descriptor */
355:                 0,                              /* ident - version number */
356:                 0,                              /* relpag- 1st page mapped */
357:                 0,                              /* chan- for file accessed */
358:                 pagcnt,                         /* number pages in section */
359:                 0,                              /* vbn- virtual blk in file*/
360:                 0,                              /* prot - file protection */
361:                 0                               /* pfc - cluster size */
362:                 );
363: if ( (vms_stat == SS$_CREATED) || (vms_stat == SS$_NORMAL) )
364:         *inadr = (void *)(retadr_quadwd[0]);    /* start addr of sect*/
365: else
366:         *inadr = NULL;                          /* return 0 if not mapped */
367: return ( vms_stat );
368: } /* --- end-of-function vmscrmpsc() --- */
369: 
370: 
371: /* ==========================================================================
372:  * Function:    vmsdellnm ( lognam, tabnam )
373:  * Purpose:     Deletes a VMS logical name.
374:  * --------------------------------------------------------------------------
375:  * Arguments:   lognam (I)      addr of char string containing logical name
376:  *                              to be deleted.
377:  *              tabnam (I)      addr of char string containing name of
378:  *                              logical name table in which to delete
379:  *                              the logical name - defaults to group table
380:  *                              if you pass NULL address.
381:  * --------------------------------------------------------------------------
382:  * Returns:     SS$_NORMAL      for successful completion
383:  * --------------------------------------------------------------------------
384:  * Notes:
385:  * ======================================================================= */
386: /* --- entry point --- */
387: int     vmsdellnm( lognam, tabnam )
388: char    *lognam;
389: char    *tabnam;
390: {
391: /* --------------------------------------------------------------------------
392: Allocations and Declarations
393: -------------------------------------------------------------------------- */
394: char    tabbuf[64];                     /* buffer for table name */
395: struct  dsc$descriptor_s                /* descrip for table,logical name */
396:         tab_desc = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, &tabbuf[0] },
397:         log_desc = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, lognam };
398: int     vms_stat;                       /* VMS returned status */
399: /* --------------------------------------------------------------------------
400: Initialize args
401: -------------------------------------------------------------------------- */
402: strcpy ( tabbuf, "LNM$" );              /*user need not pass this in tabnam*/
403: if ( tabnam != (char *)NULL )           /* see if user passed us a table */
404:      strcat ( tabbuf, tabnam );         /* concat tabnam passed by user */
405: else strcat ( tabbuf, "GROUP");         /* or default to group table */
406: tab_desc.dsc$w_length = strlen(tabbuf); /* set tabnam length in descriptor */
407: log_desc.dsc$w_length = strlen(lognam); /* set lognam length in descriptor */
408: /* --------------------------------------------------------------------------
409: Issue $dellnm, and return. 
410: -------------------------------------------------------------------------- */
411: vms_stat = SYS$DELLNM                   /* issue $dellnm */
412:         (
413:         &tab_desc,                      /* list of table names to search */
414:         &log_desc,                      /* logical name to be translated */
415:         0                               /* access mode */
416:         );
417: return( vms_stat );
418: } /* --- end-of-function vmsdellnm() --- */
419: 
420: 
421: /* ==========================================================================
422:  * Function:    vmsdeltatime ( millisecs )
423:  * Purpose:     Convert millisecs to vms internal 64-bit quadword format
424:  * --------------------------------------------------------------------------
425:  * Arguments:   millisecs (I)   int containing number of millisecs to sleep.
426:  * --------------------------------------------------------------------------
427:  * Returns:     ( int * )       addr of 64-bit quadword containing delta time
428:  *                              or NULL ptr for any error.
429:  * --------------------------------------------------------------------------
430:  * Notes:     o VMS resolution is hundredths of a second.  Any millisecs
431:  *              between 1 and 9 is rounded up to 10 (less than 1 returns 0).
432:  *              Greater than 10 rounds up or down in the usual way.
433:  *            o The address returned points to a static internal buffer.
434:  *              Copy it to a local buffer if you need to save it.
435:  * ======================================================================= */
436: /* --- entry point --- */
437: int     *vmsdeltatime ( millisecs )
438: int     millisecs;
439: {
440: /* -------------------------------------------------------------------------
441: Allocations and Declarations
442: -------------------------------------------------------------------------- */
443: int     hundredths = (millisecs+5)/10;          /* hundredths of secs */
444: int     hours=0, mins=0, secs=0;                /* in case of _long_ sleeps*/
445: char    asctim[64];                             /* delta time in ascii */
446: struct  dsc$descriptor_s                        /* asctim descriptor */
447:         timbuf = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, &asctim[0] };
448: static  WORD daytim[4];                         /* quadword system time */
449: int     *pdaytim = daytim;                      /* addr returned to caller */
450: int     status;                                 /* vms return status */
451: /* -------------------------------------------------------------------------
452: Get hours,mins,secs in case millisecs >= 1000
453: -------------------------------------------------------------------------- */
454: if ( hundredths < 1 ) hundredths = 1;           /* wait at least 1/100 sec */
455: else
456:  if ( (secs = hundredths/100) > 0 )             /* sleep one second or more*/
457:   { hundredths = (hundredths%100);              /* 100ths left after secs */
458:     if ( (mins = secs/60) > 0 )                 /* sleep one minute or more*/
459:      { secs = (secs%60);                        /*secs remaining after mins*/
460:        if ( (hours = mins/60) > 0 )             /* sleep one hour or more */
461:         { mins = (mins%60);                     /* mins remaining after hrs*/
462:           if ( hours > 23 ) hours=23; }         /* gee -- enough is enough */
463:      } /* --- end-of-if(mins>0) --- */
464:   } /* --- end-of-if(secs>0) --- */
465: /* -------------------------------------------------------------------------
466: Format an ascii string with vms delta time
467: -------------------------------------------------------------------------- */
468: sprintf(asctim,"0 %02d:%02d:%02d.%02d",hours,mins,secs,hundredths);
469: if ( msglevel >= 99 )                           /* debugging output wanted */
470:   printf("vmsdeltatime() asctim = \"%s\"\n",asctim);
471: /* -------------------------------------------------------------------------
472: Convert ascii string to 64-bit quadword format, and return it to caller
473: -------------------------------------------------------------------------- */
474: /* --- convert ascii string containing delta time --- */
475: status = sys$bintim
476:               ( &timbuf,                        /* ascii time string desc */
477:                 daytim );                       /* 64-bit delta time */
478: if ( status != SS$_NORMAL )                     /* probably internal bug */
479:   { pdaytim = (int *)NULL;                      /* set ptr for error */
480:     if ( msglevel >= 1 )                        /* error messages wanted */
481:       printf("vmsdeltatime() $bintim error %s\n",vmsmsg(status)); }
482: /* --- back to caller with time buffer or error --- */
483: return ( pdaytim );                             /* buffer or NULL ptr */
484: } /* --- end-of-vmsdeltatime() --- */
485: 
486: 
487: /* ==========================================================================
488:  * Function:    vmsetefn ( efcn, efn )
489:  * Purpose:     Set event flag efn in cluster efcn.
490:  * --------------------------------------------------------------------------
491:  * Arguments:   efcn (I)        int containing either 2 or 3, to set
492:  *                              flag in cluster 2 or 3, respectively.
493:  *              efn (I)         int containing the number of the event flag
494:  *                              to be set, 0-31.
495:  * --------------------------------------------------------------------------
496:  * Returns:     ( int )         0 if efn was previously clear (SS$_WASCLR),
497:  *                              1 if efn was already set (SS$_WASSET), or
498:  *                              -1 for VMS error.
499:  * --------------------------------------------------------------------------
500:  * Notes:
501:  * ======================================================================= */
502: /* --- entry point --- */
503: int     vmsetefn ( efcn, efn )
504: int     efcn;
505: int     efn;
506: {
507: /* --- Allocations and Declarations --- */
508: int     vms_stat;                               /* $setef VMS return status*/
509: int     efn_stat = (-1);                        /* previous state of efn */
510: /* --- Set event flag and return to caller. --- */
511: if ( efcn < 0 || efcn > 3 )                     /* efn contains all info */
512:   efcn = efn/32;                                /* set cluster from efn */
513: vms_stat = SYS$SETEF                            /* set the flag */
514:         ( 32*efcn + efn%32 );                   /* 1st efn + flag to set */
515: if ( vms_stat == SS$_WASSET ) efn_stat=1;       /* return 1 if efn was set */
516: else if ( vms_stat == SS$_WASCLR ) efn_stat=0;  /* or 0 if efn was clear */
517: else if ( msglevel >= 1 )                       /* or report error */
518:   printf("vmsetefn() error: %s\n",vmsmsg(vms_stat));
519: return ( efn_stat );                            /* previous state to caller*/
520: } /* --- end-of-function vmsetefn() --- */
521: 
522: 
523: /* ==========================================================================
524:  * Function:    vmsforcex ( pid )
525:  * Purpose:     Force process pid to exit
526:  * --------------------------------------------------------------------------
527:  * Arguments:   pid (I)         int containing process id to force exit
528:  * --------------------------------------------------------------------------
529:  * Returns:     ( int )         SS$_NORMAL if successful,
530:  *                              VMS error status otherwise.
531:  * --------------------------------------------------------------------------
532:  * Notes:     o
533:  * ======================================================================= */
534: /* --- entry point --- */
535: int     vmsforcex ( pid )
536: int     pid;
537: {
538: /* --- Allocations and Declarations --- */
539: unsigned long fxpid = pid;                      /* pid whose exit is forced*/
540: unsigned long code = SS$_FORCEDEXIT;            /* exit code to process */
541: int     vms_stat;                               /* $forcex return status */
542: /* --- force specified pid to exit --- */
543: vms_stat = sys$forcex ( &fxpid, 0, code );      /*issue $forcex code to pid*/
544: return ( vms_stat );                            /* and return to caller */
545: } /* --- end-of-function vmsforcex() --- */
546: 
547: 
548: /* ==========================================================================
549:  * Function:    vmsgrpmbx()
550:  * Purpose:     Allows temporary mailboxes to be accessed
551:  *              across the entire group
552:  * --------------------------------------------------------------------------
553:  * Arguments:   none
554:  * --------------------------------------------------------------------------
555:  * Returns:     ( int )         SS$_NORMAL for success
556:  * --------------------------------------------------------------------------
557:  * Notes:     o Same as the dcl command
558:  *      $ define/table=lnm$process_directory lnm$temporary_mailbox lnm$group
559:  * ======================================================================= */
560: int     vmsgrpmbx ( )
561: {
562: /* -------------------------------------------------------------------------
563: Allocations and Declarations
564: -------------------------------------------------------------------------- */
565: $DESCRIPTOR (tabnam, "LNM$PROCESS_DIRECTORY");
566: $DESCRIPTOR (lognam, "LNM$TEMPORARY_MAILBOX");
567: char    *eqvnam = "LNM$GROUP\000";
568: ITMLST  eqvlst[] =
569:   {
570:     { strlen(eqvnam), LNM$_STRING, eqvnam, 0 },
571:     { 0,0,0,0 }                                 /* item list termination */
572:   };
573: /* -------------------------------------------------------------------------
574: Redefine LNM$TEMPORARY_MAILBOX to specify
575: the group logical name table (LNM$GROUP)
576: -------------------------------------------------------------------------- */
577: return (
578:         SYS$CRELNM
579:                 (
580:                 0,                      /* addr of attr longword bit mask */
581:                 &tabnam,                /* table in which to create logical*/
582:                 &lognam,                /* logical name to be created */
583:                 0,                      /* access mode */
584:                 &eqvlst                 /* item list */
585:                 )
586:         );
587: } /* --- end-of-function vmsgrpmbx() --- */
588: 
589: 
590: /* ==========================================================================
591:  * Function:    vmsleepms ( millisecs )
592:  * Purpose:     Sleeps for millisecs
593:  * --------------------------------------------------------------------------
594:  * Arguments:   millisecs (I)   int containing number of millisecs to sleep.
595:  * --------------------------------------------------------------------------
596:  * Returns:     ( int )         SS$_NORMAL if successful,
597:  *                              VMS error status otherwise.
598:  * --------------------------------------------------------------------------
599:  * Notes:     o Max interval is approx 2**31nanosecs = 214secs = 3.5mins.
600:  *              For greater interval, treat daytim[2] as 64-bit signed
601:  *              integer, and init it with _negative_ of interval expressed
602:  *              in 100nanosec units.  (2**31)-1 = 2,147,483,647.
603:  * ======================================================================= */
604: /* --- entry point --- */
605: int     vmsleepms ( millisecs )
606: int     millisecs;
607: {
608: /* -------------------------------------------------------------------------
609: Allocations and Declarations
610: -------------------------------------------------------------------------- */
611: LONGWORD daytim[2];                             /* quadword system time */
612: int     status = SS$_IVTIME;                    /* init return stat for err*/
613: /* -------------------------------------------------------------------------
614: Set time to sleep in vms 64-bit quadword delta time system format.
615: -------------------------------------------------------------------------- */
616: if ( millisecs < 1 ) goto end_of_job;           /* back immediately for 0 */
617: if ( millisecs > 214748 ) millisecs=214748;     /* avoid overflow */
618: daytim[0] = (-10000)*millisecs;                 /* t in 100s of nanosecs */
619: daytim[1] = (-1);                               /* set neg vals for delta t */
620: /* -------------------------------------------------------------------------
621: Schedule a wakeup at daytim, and then hibernate until it occurs.
622: -------------------------------------------------------------------------- */
623: /* --- first, schedule wakeup --- */
624: status = sys$schdwk
625:               ( 0,                              /*pidadr of process to wake*/
626:                 0,                              /*prcnam of process to wake*/
627:                 daytim,                         /* time to wake us up */
628:                 0 );                            /* wakeup repeat interval */
629: if ( status != SS$_NORMAL )                     /* $schdwk failed */
630:   { if ( msglevel >= 1 )                        /* error messages wanted */
631:       printf("vmsleepms() $schdwk error %s\n",vmsmsg(status));
632:     goto end_of_job; }                          /* return without sleeping */
633: /* --- hibernate until woken --- */
634: status = sys$hiber();                           /* nighty-nite */
635: /* --- back to caller after awakening --- */
636: end_of_job: return ( status );                  /* back after millisecs */
637: } /* --- end-of-vmsleepms() --- */
638: 
639: 
640: /* ==========================================================================
641:  * Function:    vmsmsg ( vms_stat )
642:  * Purpose:     Returns text of VMS message corresponding to SS$_status.
643:  * --------------------------------------------------------------------------
644:  * Arguments:   vms_stat (I)    int SS$_ status.
645:  * --------------------------------------------------------------------------
646:  * Returns:     (char *)        address of char string containing message.
647:  * --------------------------------------------------------------------------
648:  * Notes:
649:  * ======================================================================= */
650: /* --- entry point --- */
651: char    *vmsmsg (vms_stat)
652: int     vms_stat;
653: {
654: /* -------------------------------------------------------------------------
655: Allocations and Declarations
656: -------------------------------------------------------------------------- */
657: static  char msgbuf[256];                       /* VMS error message buffer */
658: short   msglen;                                 /* message length */
659: struct  dsc$descriptor_s                        /* message descriptor */
660:         msg_desc = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, &msgbuf[0] };
661: char    outadr[4];                              /* dummy getmsg array */
662: /* -------------------------------------------------------------------------
663: Issue $getmsg and print message
664: -------------------------------------------------------------------------- */
665: msg_desc.dsc$w_length = 255;                    /* Init msg length */
666: sys$getmsg(vms_stat, &msglen, &msg_desc, 0xF, outadr ); /* 0xF for full msg */
667: if (msglen > 255) msglen=255;                   /* max msg size */
668: msgbuf[msglen] = '\000';                        /* null-terminate message */
669: return ( msgbuf );                              /* and give it to caller */
670: } /* --- end-of-function vmsmsg() --- */
671: 
672: 
673: /* ==========================================================================
674:  * Function:    vmspawn ( cmdstr, efn, isnotify )
675:  * Purpose:     Calls lib$spawn to spawn a child process, and waits for it
676:  *              to complete if efn>0.
677:  * --------------------------------------------------------------------------
678:  * Arguments:   cmdstr (I)      addr of char string containing command string
679:  *                              to be executed by spawned process.
680:  *              efn (I)         int containing event flag to wait on for
681:  *                              completion of subprocess, or 0 to return
682:  *                              to caller immediately.
683:  *              isnotify (I)    int containing TRUE to notify caller upon
684:  *                              completion of spawned process.
685:  * --------------------------------------------------------------------------
686:  * Returns:     ( int )         completion status of subprocess if efn>0,
687:  *                              or status of lib$spawn if efn<=0.
688:  * --------------------------------------------------------------------------
689:  * Notes:
690:  * ======================================================================= */
691: /* --- entry point --- */
692: int     vmspawn ( cmdstr, efn, isnotify )
693: char    *cmdstr;
694: int     efn;
695: int     isnotify;
696: {
697: /* -------------------------------------------------------------------------
698: Allocations and Declarations
699: -------------------------------------------------------------------------- */
700: /* --- buffers pointed to by string descriptors --- */
701: static  char
702:         infile[64],                     /* input-file */
703:         outfile[64];                    /* output-file */
704: /* --- string descriptors and pointers to the descriptors themselves --- */
705: struct  dsc$descriptor_s                /* descriptors for above */
706:         cmd_desc = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, &cmdstr[0] },
707:         in_desc  = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, &infile[0] },
708:         out_desc = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, &outfile[0]};
709: /* --- various and sundry other variables --- */
710: int     status;                         /* return code from lib$spawn issue*/
711: long    flags = NOWAIT | NOTIFY;        /* lib$spawn options (see above) */
712: long    proc_id;                        /* process id of spawned subprocess*/
713: long    comp_stat;                      /* completion status */
714: /* -------------------------------------------------------------------------
715: Get command string and issue lib$spawn
716: -------------------------------------------------------------------------- */
717: /* --- command string is first arg --- */
718: cmd_desc.dsc$w_length = strlen(cmdstr); /* length of cmdstr in descriptor */
719: /* --- set up flags --- */
720: flags = (isnotify)? NOWAIT | NOTIFY :   /*don't wait, let us know when done*/
721:                         NOWAIT ;        /* don't wait */
722: /* --- issue lib$spawn --- */
723: status = lib$spawn
724:         ( /* --- argument --- */        /* --- description --- */
725:                 &cmd_desc,              /* command to be executed */
726:                 0,                      /* equivalence name for sys$input */
727:                 0,                      /* equivalence name for sys$output */
728:                 &flags,                 /* bits designate lib$spawn options*/
729:                 0,                      /* explicit subprocess name */
730:                 &proc_id,               /* assigned process id */
731:                 &comp_stat,             /* completion status of subprocess */
732:                 &efn,                   /* completion event flag# to be set*/
733:                 0,                      /* addr of completion ast routine */
734:                 0,                      /* ast argument */
735:                 0,                      /* prompt string used by subprocess*/
736:                 0 );                    /* file spec for cli run by subproc*/
737: /* --- check return status --- */
738: if ( status != SS$_NORMAL )
739:   { if ( msglevel > 1 )
740:       printf ( "vmspawn()... can't spawn %s, err=%s\n",
741:       cmdstr, vmsmsg(status) );
742:     goto end_of_job; }
743: /* --- wait for event flag if we got one --- */
744: if ( efn > 0 )                          /* got an efn to wait for */
745:   { /* --- wait for efn and show completion status --- */
746:   sys$waitfr ( efn );                   /* return after flag gets set */
747:   status = comp_stat;                   /* give subprocess status to caller*/
748:   if ( msglevel >= 3 )                  /* display subprocess completion */
749:     printf ( "vmspawn()... completion status: %s\n", vmsmsg(status) );
750:   } /* --- end-of-if(efn>0) --- */
751: /* --- back to caller at end of job --- */
752: end_of_job: return ( status );
753: } /* --- end-of-function vmspawn() --- */
754: 
755: 
756: /* ==========================================================================
757:  * Function:    vmsrdefn ( efn )
758:  * Purpose:     test specified event flag (in whatever cluster it exists)
759:  * -------------------------------------------------------------------
760:  * Arguments:   efn (I)                 int containing flag to test
761:  * -------------------------------------------------------------------
762:  * Returns:     1 if efn is set or 0 if clear,
763:  *              or -1 for vms error.
764:  * -------------------------------------------------------------------
765:  * Notes:
766:  * ======================================================================= */
767: /* --- entry point --- */
768: int     vmsrdefn ( efn )
769: int     efn;
770: {
771: /* --- allocations and declarations --- */
772: unsigned int    efn_mask;                       /* event flag state mask */
773: int             vms_stat;                       /* $readef status */
774: int             efn_stat = (-1);                /* state of efn */
775: /* --- read all event flags in cluster and check the requested efn --- */
776: vms_stat = SYS$READEF(efn,&efn_mask);   /* state of all 32 flags in cluster*/
777: if ( vms_stat == SS$_WASSET ) efn_stat=1;       /* return 1 if efn was set */
778: else if ( vms_stat == SS$_WASCLR ) efn_stat=0;  /* or 0 if efn was clear */
779: else if ( msglevel >= 1 )                       /* or report error */
780:   printf("vmsrdefn() error: %s\n",vmsmsg(vms_stat));
781: #if 0
782: if ( vms_stat == SS$_NORMAL )                   /* read them successfully */
783:   { efn %= 32;                          /* set to efn number within cluster*/
784:     efn_stat = (efn_mask & (1<< efn))? 1:0; } /* and see if efn is set */
785: #endif
786: return ( efn_stat );                    /* event flag status back to caller*/
787: } /* --- end-of-function vmsrdefn() --- */
788: 
789: 
790: /* ==========================================================================
791:  * Function:    vmsrdmbx ( chan, message, msglen, iswait )
792:  * Purpose:     Read message from mailbox (and wait for completion).
793:  * --------------------------------------------------------------------------
794:  * Arguments:   chan (I)        int containing channel assigned to mailbox.
795:  *              message (O)     addr of buffer for message
796:  *              msglen (I/O)    addr of int containing max size of buffer on
797:  *                              input, and returning #bytes actually read.
798:  *                              See notes below.
799:  *              iswait (I)      int containing 0 to return immediately,
800:  *                              or 1 to wait for completion of qio.
801:  * --------------------------------------------------------------------------
802:  * Returns:     ( int )         SS$_NORMAL if successful,
803:  *                              VMS error status otherwise.
804:  * --------------------------------------------------------------------------
805:  * Notes:     o Msglen contains the transfer count only if iswait is
806:  *              specified.  Otherwise, msglen returns a (WORD *) ptr to
807:  *              the iosb, and the caller can examine iosb[1] when the
808:  *              qio completes.
809:  * ======================================================================= */
810: /* --- entry point --- */
811: int     vmsrdmbx ( chan, message, msglen, iswait )
812: int     chan;
813: char    *message;
814: int     *msglen;
815: int     iswait;
816: {
817: /* --- allocations and declarations --- */
818: LONGWORD mbxchan = (LONGWORD)chan;              /* argument for $qio */
819: static  WORD iosb[4];                           /* i/o status block */
820: int     status;                                 /* vms return status */
821: int     (*sys$func)() =                         /* choose $qio or $qiow */
822:                 (iswait)? sys$qiow:sys$qio;
823: /* --- issue $qio and return to caller after completion --- */
824: iosb[1] = 0;                                    /* reset size of message */
825: status = sys$func
826:                 (
827:                 0,                              /* efn - event flag */
828:                 mbxchan,                        /* chan - assigned to mbx */
829:                 IO$_READVBLK,                   /* func - func for device */
830:                 iosb,                           /* iosb - status block */
831:                 0,                              /* astadr - ast address */
832:                 0,                              /* astprm - ast parameter */
833:                 message,                        /* p1 = addr of message */
834:                 *msglen,                        /* p2 = max message size */
835:                 0,0,0,0                         /* p3-p6 unused */
836:                 );
837: if ( status == SS$_NORMAL )                     /* issued successfully */
838:   {
839:   if ( iswait )                                 /* caller wants to wait */
840:       *msglen = (int)(iosb[1]);                 /* and return message size */
841:   else                                          /* immediate return wanted */
842:       *((WORD **)msglen) = iosb;                /* so return iosb to caller*/
843:   }
844: else
845:   if ( msglevel >= 1 )                          /* error messages wanted */
846:     printf("vmsrdmbx() $qio error %s\n",vmsmsg(status));
847: return ( status );                              /* back with status */
848: } /* --- end-of-function vmsrdmbx() --- */
849: 
850: 
851: /* ==========================================================================
852:  * Function:    vmstime ( year,month,day, hour,min,sec,hundredths, wkday )
853:  * Purpose:     Current date/time obtained from sys$numtim().
854:  * --------------------------------------------------------------------------
855:  * Arguments:   year (O)        addr of int returning four-digit year.
856:  *              month (O)       addr of int returning month of year (1-12).
857:  *              day (O)         addr of int returning day of month (1-31).
858:  *              hour (O)        addr of int returning hour of day (0-23).
859:  *              min (O)         addr of int returning minute of hour (0-59).
860:  *              sec (O)         addr of int returning second of min (0-59).
861:  *              hundredths (O)  addr of int returning 100ths of secs (0-99).
862:  *              wkday (O)       addr of int returning 1=Mon thru 7=Sun.
863:  * --------------------------------------------------------------------------
864:  * Returns:     ( int )         SS$_NORMAL if time obtained successfully,
865:  *                              VMS error status otherwise.
866:  * --------------------------------------------------------------------------
867:  * Notes:       If any address is passed as NULL, the corresponding time
868:  *              component is not returned.
869:  * ======================================================================= */
870: /* --- entry point --- */
871: int     vmstime ( year,month,day, hour,min,sec,hundredths, wkday )
872: int     *year, *month, *day;
873: int     *hour, *min, *sec, *hundredths;
874: int     *wkday;
875: {
876: /* --- Allocations and Declarations --- */
877: WORD    timbuf[7];                              /* buffer for $numtim */
878: LONGWORD daynumber;                             /* for lib$day_of_week */
879: int     status;                                 /* $numtim return status */
880: /* --- obtain current day-of-week --- */
881: status = lib$day_of_week
882:               ( 0,                              /*user-time (0=current day)*/
883:                 &daynumber );                   /* day-number */
884: if ( status != SS$_NORMAL )                     /* probably SS$_ACCVIO */
885:   daynumber = (-1);                             /* set invalid daynumber */
886: /* --- obtain current time --- */
887: status = sys$numtim
888:               ( timbuf,                         /* buffer for time */
889:                 0 );                            /* [timadr] for conversion */
890: if ( status != SS$_NORMAL )                     /* probably SS$_ACCVIO */
891:   memset(timbuf,0,14);                          /* set all componenets to 0*/
892: /* --- return components to caller --- */
893: if ( year  != (int *)NULL )  *year  = timbuf[0]; /* set year if addr given */
894: if ( month != (int *)NULL )  *month = timbuf[1]; /* set month */
895: if ( day   != (int *)NULL )  *day   = timbuf[2]; /* etc */
896: if ( hour  != (int *)NULL )  *hour  = timbuf[3];
897: if ( min   != (int *)NULL )  *min   = timbuf[4];
898: if ( sec   != (int *)NULL )  *sec   = timbuf[5];
899: if ( hundredths != (int *)NULL ) *hundredths = timbuf[6];
900: if ( wkday != (int *)NULL )  *wkday = daynumber;
901: return ( status );                              /* back to caller */
902: } /* --- end-of-function vmstime() --- */
903: 
904: 
905: /* ==========================================================================
906:  * Function:    vmstrnlnm ( lognam, logval )
907:  * Purpose:     Translates a VMS logical name.
908:  * --------------------------------------------------------------------------
909:  * Arguments:   lognam (I)      addr of char string containing logical name
910:  *                              to be translated.
911:  *              logval (O)      addr of char string containing translated
912:  *                              value upon return.
913:  * --------------------------------------------------------------------------
914:  * Returns:     SS$_NORMAL      for successful completion
915:  * --------------------------------------------------------------------------
916:  * Notes:
917:  * ======================================================================= */
918: /* --- entry point --- */
919: int     vmstrnlnm( lognam, logval )
920: char    *lognam;
921: char    *logval;
922: {
923: /* --------------------------------------------------------------------------
924: Allocations and Declarations
925: -------------------------------------------------------------------------- */
926: $DESCRIPTOR (tabnam, "LNM$FILE_DEV");   /* list of tables to search */
927: char    logbuf[128], rslbuf[128];       /* logname and translation string */
928: short   rsllen;                         /* length of translated string */
929: struct  dsc$descriptor_s                /* local descrip for logical name */
930:         log_desc = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, &logbuf[0] };
931: int     itrn=0, maxtrn=0;               /* iteratively translate */
932: int     vms_stat;                       /* $trnlnm return status */
933: ITMLST  trnlst[] =
934:   {
935:     { 127, LNM$_STRING, &rslbuf, &rsllen },
936:     { 0,0,0,0 }
937:   };
938: /* --------------------------------------------------------------------------
939: Issue $trnlnm's, and Return translated value.
940: -------------------------------------------------------------------------- */
941: strcpy ( rslbuf, lognam );              /* init for 1st iteration */
942: while ( (itrn < maxtrn) || (maxtrn == 0) ) /* allow for max# iterations */
943:   {
944:   itrn++;                               /* bump iteration counter */
945:   strcpy ( logbuf, rslbuf );            /* copy prev Xlate to descriptor */
946:   log_desc.dsc$w_length = strlen(logbuf); /* and set the string length */
947:   vms_stat = SYS$TRNLNM                 /* issue $trnlnm */
948:     (
949:     0,                                  /* attributes controlling search */
950:     &tabnam,                            /* list of table names to search */
951:     &log_desc,                          /* logical name to be translated */
952:     0,                                  /* access mode */
953:     &trnlst[0]                          /* item list */
954:     );
955:   switch ( vms_stat )
956:     {
957:     case SS$_NORMAL:                    /* got a good Xlate */
958:       if ( rsllen > 127 ) rsllen=127;   /* check max length */
959:       rslbuf[rsllen] = '\000';          /* null-terminate */
960:       break;
961:     case SS$_NOLOGNAM:                  /* no more Xlates */
962:       strcpy( logval, logbuf );         /* copy last Xlate */
963:       if ( itrn > 1 ) vms_stat = SS$_NORMAL; /* xlated at least once */
964:       return (vms_stat);                /* ok or nolognam return */
965:     default:
966:       rsllen = 0;                       /* set for null string */
967:       goto end_of_job;                  /* and return err stat */
968:     } /* --- end-of-switch(vms_stat) --- */
969:   } /* --- end-of-while(itrn) --- */
970: /* --------------------------------------------------------------------------
971: Return translated value after last iteration.
972: -------------------------------------------------------------------------- */
973: end_of_job:
974:   if ( rsllen > 127 ) rsllen=127;       /* double-check check max length */
975:   memcpy(logval, rslbuf, rsllen);       /* copy last Xlation to caller's arg */
976:   logval[rsllen] = '\0';                /* and null-terminate */
977:   return( vms_stat );                   /* back to caller with status */
978: } /* --- end-of-function vmstrnlnm() --- */
979: 
980: 
981: /* ==========================================================================
982:  * Function:    wflor ( mask, flag )
983:  * Purpose:     Wait until any one of a specified set of event flags is set.
984:  * --------------------------------------------------------------------------
985:  * Arguments:   mask (I)        addr of int array containing the numbers
986:  *                              of the event flags on which to wait, 0-127
987:  *                              and terminated by any number out of range.
988:  *              flag (O)        addr of int returning the event flag number
989:  *                              that woke the process up, or -1 for error.
990:  * --------------------------------------------------------------------------
991:  * Returns:     ( int )         SS$_NORMAL for successful completion,
992:  *                              VMS error status otherwise.
993:  * --------------------------------------------------------------------------
994:  * Notes:     o The efn that woke the process up is cleared before returning.
995:  *            o All the flags specified in mask must reside in the same
996:  *              cluster, e.g., they must all be within the range 0-31
997:  *              or all within 32-63, etc.
998:  * ======================================================================= */
999: /* --- entry point --- */
1000: int     vmswflor ( mask, flag )
1001: int     *mask;
1002: int     *flag;
1003: {
1004: /* -------------------------------------------------------------------------
1005: Allocations and Declarations
1006: -------------------------------------------------------------------------- */
1007: int     efn = *mask;                            /* any efn in cluster */
1008: int     *maskptr = mask;                        /* local copy of mask arg */
1009: unsigned int bitmask = 0;                       /* bits set as per mask arg*/
1010: int     vms_stat;                               /* VMS return status */
1011: /* -------------------------------------------------------------------------
1012: Init args and issue $wflor
1013: -------------------------------------------------------------------------- */
1014: /* --- init args --- */
1015: *flag = (-1);                                   /* init for error return */
1016: while ( (*maskptr >= 0) && (*maskptr <= 127) )  /* set bits while efn legal*/
1017:   { setbit(bitmask,((*maskptr)%32));            /* set the bit */
1018:     maskptr++; }                                /* ready for next */
1019: /* --- issue $wflor --- */
1020: vms_stat = SYS$WFLOR
1021:   ( efn,                                        /* some flag in cluster */
1022:     bitmask );                                  /* flags on which to wait */
1023: if ( vms_stat != SS$_NORMAL ) goto end_of_job;  /*return immediately on err*/
1024: /* -------------------------------------------------------------------------
1025: Read and Clear efn that woke us.
1026: -------------------------------------------------------------------------- */
1027: /* --- Read the states of the flags in the cluster --- */
1028: vms_stat = SYS$READEF
1029:   ( efn,                                        /* flag in cluster */
1030:     &bitmask );                                 /*state of flags in cluster*/
1031: if ( vms_stat != SS$_WASSET
1032: &&   vms_stat != SS$_WASCLR ) goto end_of_job;  /* quit if $readef fails */
1033: /* --- Clear all the flags (in mask) until a set one is found --- */
1034: maskptr = mask;                                 /* init for another loop */
1035: while ( (*maskptr >= 0) && (*maskptr <= 127) )  /* clear efn's until WASSET */
1036:   {
1037:   vms_stat = SYS$CLREF( *maskptr );             /* clear the next flag */
1038:   switch ( vms_stat )                           /* was cleared flag set? */
1039:     {
1040:     case SS$_WASCLR:                            /* wasn't set, so try again*/
1041:       maskptr++;                                /*bump the ptr to next flag*/
1042:       break;
1043:     case SS$_WASSET:                            /*here's the flag that woke*/
1044:       *flag = *maskptr;                         /*let user know who woke us*/
1045:       vms_stat = SS$_NORMAL;                    /* set ok status */
1046:     default:                                    /* uh-oh (bad status) */
1047:       goto end_of_job;                          /* return ok or bad status */
1048:     } /* --- end-of-switch(vms_stat) --- */
1049:   } /* --- end-of-while(*maskptr) --- */
1050: vms_stat = SS$_WASCLR;                          /* strange - no one woke us*/
1051: /* --- back to caller --- */
1052: end_of_job:
1053:   if ( vms_stat != SS$_NORMAL )                 /* some problem */
1054:     if ( msglevel >= 1 )                        /* and we want it reported */
1055:       printf("vmswflor() error: %s\n",vmsmsg(vms_stat));
1056:   return ( vms_stat );                          /* back with status */
1057: } /* --- end-of-function vmswflor() --- */
1058: 
1059: 
1060: /* ==========================================================================
1061:  * Function:    vmswrtmbx ( chan, message, msglen, iswait )
1062:  * Purpose:     Write message to mailbox (and wait for completion).
1063:  * --------------------------------------------------------------------------
1064:  * Arguments:   chan (I)        int containing channel assigned to mailbox.
1065:  *              message (I)     addr of message
1066:  *              msglen (I)      int containing #bytes in message
1067:  *              iswait (I)      int containing 0 to return immediately,
1068:  *                              or 1 to wait for completion of qio.
1069:  * --------------------------------------------------------------------------
1070:  * Returns:     ( int )         SS$_NORMAL if successful,
1071:  *                              VMS error status otherwise.
1072:  * --------------------------------------------------------------------------
1073:  * Notes:
1074:  * ======================================================================= */
1075: /* --- entry point --- */
1076: int     vmswrtmbx ( chan, message, msglen, iswait )
1077: int     chan;
1078: char    *message;
1079: int     msglen;
1080: int     iswait;
1081: {
1082: /* --- allocations and declarations --- */
1083: LONGWORD mbxchan = (LONGWORD)chan;              /* argument for $qio */
1084: int     status;                                 /* vms return status */
1085: int     (*sys$func)() =                         /* choose $qio or $qiow */
1086:                 (iswait)? sys$qiow:sys$qio;
1087: /* --- issue $qio and return to caller after completion --- */
1088: status = sys$func
1089:                 (
1090:                 0,                              /* efn - event flag */
1091:                 mbxchan,                        /* chan - assigned to mbx */
1092:                 IO$_WRITEVBLK,                  /* func - func for device */
1093:                 0,                              /* iosb - status block */
1094:                 0,                              /* astadr - ast address */
1095:                 0,                              /* astprm - ast parameter */
1096:                 message,                        /* p1 = addr of message */
1097:                 msglen,                         /* p2 = #bytes in message */
1098:                 0,0,0,0                         /* p3-p6 unused */
1099:                 );
1100: if ( status != SS$_NORMAL )                     /* issued successfully */
1101:   if ( msglevel >= 1 )                          /* error messages wanted */
1102:     printf("vmswrtmbx() $qio error %s\n",vmsmsg(status));
1103: return ( status );                              /* back with status */
1104: } /* --- end-of-function vmswrtmbx() --- */
1105: 
1106: 
1107: #ifdef TESTDRIVE
1108: /* ==========================================================================
1109:  * Function:    vmslib test driver
1110:  * Purpose:     exercise above functions
1111:  * --------------------------------------------------------------------------
1112:  * Command-Line Arguments:
1113:  * --------------------------------------------------------------------------
1114:  * Returns:     ( void )
1115:  * --------------------------------------------------------------------------
1116:  * Notes:
1117:  * ======================================================================= */
1118: /* --- entry point --- */
1119: int     main ( argc, argv )
1120: int     argc;
1121: char    *argv[];
1122: {
1123: /* -------------------------------------------------------------------------
1124: Allocations and Declarations
1125: -------------------------------------------------------------------------- */
1126: int     year,month,day, hour,min,sec,hundredths, wkday; /* vmstime() args */
1127: char    *prompt(), *reply=NULL, **replies=NULL; /* prompt and get reply */
1128: int     status = SS$_NORMAL;                    /* many tests want status */
1129: /* -------------------------------------------------------------------------
1130: exercise vmstime()
1131: -------------------------------------------------------------------------- */
1132: if ( 1 )                                        /* toggle this test */
1133:   {
1134:   vmstime(&year,&month,&day,&hour,&min,&sec,&hundredths,&wkday); /*get time*/
1135:   printf("vmstime()... yr=%d,mon=%d,day=%d, hr=%d,min=%d,sec=%d, 100ths=%d\n",
1136:   year,month,day, hour,min,sec, hundredths);    /* and display it */
1137:   printf("\t\t wkday=%d\n",wkday);              /* 2nd line needed */
1138:   }
1139: /* -------------------------------------------------------------------------
1140: exercise vmsbeep()
1141: -------------------------------------------------------------------------- */
1142: if ( 1 )                                        /* toggle this test */
1143:  while ( 1 )
1144:   {
1145:   int   nbeeps = 0;                             /* #times to beep terminal */
1146:   reply = prompt("vmbeeps()... Enter #beeps to emit",NULL);
1147:   if ( *reply != '\000' ) nbeeps = atoi(reply); /* interpret reply as int */
1148:   if ( nbeeps < 1 ) break;                      /* CR or zero to quit loop */
1149:   vmsbeep(nbeeps);                              /* say beep-beep */
1150:   }
1151: /* -------------------------------------------------------------------------
1152: exercise vmsleepms()
1153: -------------------------------------------------------------------------- */
1154: if ( 1 )                                        /* toggle this test */
1155:  while ( 1 )
1156:   {
1157:   int   millisecs = 0;                          /* #millisecs to sleep */
1158:   reply = prompt("vmsleepms()... Enter #millisecs to sleep",NULL);
1159:   if ( *reply != '\000' ) millisecs = atoi(reply); /*interpret reply as int*/
1160:   if ( millisecs < 1 ) break;                   /* CR or zero to quit loop */
1161:   vmstime(&year,&month,&day,&hour,&min,&sec,&hundredths,&wkday);/*show time*/
1162:   printf("\t time before sleep is %d:%d:%d.%02d\n",hour,min,sec,hundredths);
1163:   vmsleepms(millisecs);                         /* sleep for requested time*/
1164:   vmstime(&year,&month,&day,&hour,&min,&sec,&hundredths,&wkday);/*show time*/
1165:   printf("\t time after wakeup is %d:%d:%d.%02d\n",hour,min,sec,hundredths);
1166:   }
1167: /* -------------------------------------------------------------------------
1168: exercise vmspawn()
1169: -------------------------------------------------------------------------- */
1170: if ( 1 )                                        /* toggle this test */
1171:  while ( 1 )
1172:   {
1173:   int   efn=0, isnotify=0;                      /* event and notify flag */
1174:   replies =                                     /* get all three args */
1175:     (char **)prompt("vmspawn()... Enter command[,efn[,notify]]",",");
1176:   if ( *replies[0] == '\000' ) break;           /* CR to quit loop */
1177:   if ( replies[1] != (char *)NULL )             /* got an efn from user */
1178:     { efn=atoi(replies[1]);                     /* interpret 2nd fld as efn*/
1179:       if ( replies[2] != (char *)NULL )         /* got notify flag, too */
1180:         isnotify=atoi(replies[2]); }            /* interpret 3rd fld */
1181:   vmspawn(replies[0],efn,isnotify);             /* spawn command in 1st fld*/
1182:   }
1183: /* -------------------------------------------------------------------------
1184: exercise vmsforcex()
1185: -------------------------------------------------------------------------- */
1186: if ( 1 )                                        /* toggle this test */
1187:  while ( 1 )
1188:   {
1189:   int   pid=0;                                  /* process id */
1190:   reply =                                       /* get pid of process */
1191:     prompt("vmsforcex()... Enter pid of process to force exit on",NULL);
1192:   if ( *reply != '\000' )                       /* interpret reply as hex */
1193:     sscanf(reply,"%x",&pid);
1194:   if ( pid < 1 ) break;                         /* CR or zero to quit loop */
1195:   status = vmsforcex(pid);                      /* force process to exit */
1196:   printf("  vmsforcex(%X) returned %s\n",pid,vmsmsg(status));
1197:   }
1198: /* -------------------------------------------------------------------------
1199: exercise vmscrmpsc()
1200: -------------------------------------------------------------------------- */
1201: if ( 1 )                                        /* toggle this test */
1202:  while ( 1 )
1203:   {
1204:   char  gsdnam[64]="crmpsc";                    /* name/handle of section */
1205:   int   pagcnt=1;                               /* page count for section */
1206:   char  *inaddr=NULL;                           /* ptr to section */
1207:   /* --- we first need to create or map section --- */
1208:   replies =                                     /* get section name,size */
1209:     (char **)prompt("vmscrmpsc()... Enter section name[,#pages]",",");
1210:   if ( *replies[0] == '\000' ) break;           /* CR to quit */
1211:   strcpy(gsdnam,replies[0]);                    /* local copy of name */
1212:   if ( replies[1] != (char *)NULL )             /* got page size from user */
1213:     pagcnt=atoi(replies[1]);                    /* interpret 2nd fld */
1214:   status = vmscrmpsc(gsdnam,pagcnt,&inaddr);    /* create or map section */
1215:   printf("%s\n",vmsmsg(status));                /* show if created/mapped */
1216:   if ( inaddr == (char *)NULL ) break;          /* $crmpsc failed */
1217:   /* --- now let's read/write to it --- */
1218:   while ( 1 )
1219:     {
1220:     int offset = 0;                             /* offset into global sect */
1221:     replies =                                   /*write/read inaddr[offset]*/
1222:       (char **)prompt("  Enter offset[,contents]",",");
1223:     if ( *replies[0] == '\000' ) break;         /* CR to quit loop */
1224:     offset = atoi(replies[0]);                  /* interpret offset */
1225:     if ( replies[1] == (char *)NULL )           /* no contents, so read */
1226:       printf("    \"%.64s\"\n",inaddr+offset);  /* display (64 char max) */
1227:     else
1228:       strcpy(inaddr+offset,replies[1]);         /* or copy field to section*/
1229:     } /* --- end-of-while(1) --- */
1230:   break;                                        /* just do outer loop once */
1231:   } /* --- end-of-while(1) --- */
1232: /* -------------------------------------------------------------------------
1233: exercise vmscrembx()
1234: -------------------------------------------------------------------------- */
1235: if ( 1 )                                        /* toggle this test */
1236:  while ( 1 )
1237:   {
1238:   char  mbxnam[64]="mailbox";                   /* name/handle of mailbox */
1239:   int   chan;                                   /* channel assigned to it */
1240:   WORD *iosb = NULL;                            /* rdmbx may return &iosb */
1241:   /* --- we first need to create or assign mailbox --- */
1242:   reply =                                       /* get mailbox name */
1243:     prompt("vmscrembx()... Enter mailbox name",NULL);
1244:   if ( *reply == '\000' ) break;                /* CR to quit */
1245:   status = vmsgrpmbx();                         /* temp mailboxes for ipc */
1246:   strcpy(mbxnam,reply);                         /* set mailbox name */
1247:   status = vmscrembx(mbxnam,&chan);             /* create or assign mailbox*/
1248:   if ( status != SS$_NORMAL )                   /* $crembx failed */
1249:     { printf("%s\n",vmsmsg(status));            /* display error msg */
1250:       break; }                                  /* and quit */
1251:   /* --- now let's read/write to it --- */
1252:   while ( 1 )
1253:     {
1254:     char message[256];                          /* message buffer */
1255:     int msglen = 255;                           /* (max) message length */
1256:     int iswait = 1;                             /* wait for reply */
1257:     replies =                                   /* write message or read */
1258:       (char **)prompt("  Enter {n=nowait,w}[,message]",",");
1259:     if ( *replies[0] == '\000' ) break;         /* CR to quit loop */
1260:     if ( toupper(*replies[0]) == 'N' )          /* 1st char is 'N' */
1261:       iswait = 0;                               /* so turn off wait */
1262:     if ( replies[1] != (char *)NULL )           /* got message from user */
1263:       {
1264:       msglen = 1 + strlen(replies[1]);          /* "1+" writes NULL to mbx */
1265:       status = vmswrtmbx(chan,replies[1],msglen,iswait); /* write message */
1266:       }
1267:     else                                        /* no message from user */
1268:       {
1269:       if ( iosb != NULL ) iswait = 0;           /* read already posted */
1270:       else                                      /* no read pending */
1271:         { status = vmsrdmbx(chan,message,&msglen,iswait); /*so read mailbox*/
1272:           if ( !iswait )                        /* returned without wait */
1273:             iosb = (WORD *)msglen; }            /* msglen returned &iosb */
1274:       if ( iosb != NULL )                       /* from prev post or above */
1275:         { msglen = (int)(iosb[1]);              /* iosb[1] is msglen */
1276:           if ( msglen > 0 ) iosb = NULL;        /* read no longer posted */
1277:             else *message = '\000'; }           /*   else still waiting */
1278:       printf("    %s=%d, message=\"%.64s\"\n",  /* display message */
1279:       (iswait?"#read":"iosb[1]"),msglen,message);
1280:       }
1281:     } /* --- end-of-while(1) --- */
1282:   break;                                        /* just do outer loop once */
1283:   } /* --- end-of-while(1) --- */
1284: /* -------------------------------------------------------------------------
1285: exercise vmsascefc(), etc (i.e., event flag functions)
1286: -------------------------------------------------------------------------- */
1287: if ( 1 )                                        /* toggle this test */
1288:   {
1289:   /* --- associate common event flag clusters --- */
1290:   while ( 1 )
1291:     {
1292:     char name[64] = "cluster";                  /* cluster name */
1293:     int efcn = 2;                               /* cluster # (2 or 3) */
1294:     replies =                                   /* write message or read */
1295:       (char **)prompt("vmsascefc()... Enter cluster #,name",",");
1296:     if ( *replies[0] == '\000' ) break;         /* CR to quit loop */
1297:     efcn = atoi(replies[0]);                    /* cluster # */
1298:     if ( efcn<2 || efcn>3 )                     /* out-of-range */
1299:       { printf("  Cluster # must be 2 or 3 (not %d)\n",efcn);
1300:         continue; }                             /* try again */
1301:     if ( replies[1] != (char *)NULL )           /* got name from user */
1302:       strcpy(name,replies[1]);                  /* replace default */
1303:     status = vmsascefc(efcn,name);              /* associate cluster */
1304:     if ( status != SS$_NORMAL )                 /* oops */
1305:       printf("  vmsascefc() failed: %s\n",vmsmsg(status));
1306:     } /* --- end-of-while(1) --- */
1307:   /* --- set, read, clear, wait for event flags --- */
1308:   while ( 1 )
1309:     {
1310:     int iefn,nefns=0,efns[64];                  /* event flags from user */
1311:     int isset, efn;                             /* an efn from efns[] */
1312:     char opcode;                                /* 'S'et,'R'd,'C'lr,'W'ait */
1313:     replies =                                   /* write message or read */
1314:       (char **)prompt("  Enter {'S'et,Rd,Clr,Wait},efn1[,efn2[,...]]",",");
1315:     if ( *replies[0] == '\000' ) break;         /* CR to quit loop */
1316:     opcode = toupper(*replies[0]);              /* first char is opcode */
1317:     while ( replies[nefns+1] != (char *)NULL )  /* got another efn */
1318:       { efns[nefns] = atoi(replies[nefns+1]);   /* so interpret this efn */
1319:         nefns++; }                              /* and bump efn count */
1320:     efns[nefns] = (-1);                         /* set trailer efn */
1321:     if ( opcode == 'W' )                        /* caller wants to wait */
1322:       { status = vmswflor(efns,&efn);           /* wait till any efn set */
1323:         printf("  woken up by efn#%d\n",efn); } /* display set efn */
1324:     else                                        /* for opcode != W */
1325:       for ( iefn=0; iefn < nefns; iefn++ )      /* do 1 efn at a time */
1326:         {
1327:         status = SS$_NORMAL;                    /* reset error */
1328:         efn = efns[iefn];                       /* current efn */
1329:         if ( opcode == 'S' ) status = vmsetefn(efn/32,efn%32); /* set efn*/
1330:         if ( opcode == 'C' ) status = vmsclrefn(efn/32,efn%32); /* clear efn*/
1331:         isset = vmsrdefn(efn);                  /* always check state */
1332:         printf("  efn#%d is %s\n",              /* and display it */
1333:         efn,(isset==1?"Set":(isset==0?"Clear":"Error")));
1334:         if(0)if ( status != SS$_NORMAL )        /* oops */
1335:           printf("  \"%c\" failed: %s\n",opcode,vmsmsg(status));
1336:         } /* --- end-of-for(iefn) --- */
1337:     } /* --- end-of-while(1) --- */
1338:   } /* --- end-of-if(1) --- */
1339: /* -------------------------------------------------------------------------
1340: exercise vmscrelnm(), etc
1341: -------------------------------------------------------------------------- */
1342: if ( 1 )                                        /* toggle this test */
1343:   while ( 1 )
1344:     {
1345:     /* --- create, translate or delete logical names --- */
1346:     char logval[256];                           /* logical name xlation */
1347:     char opcode=' ';                            /* 'C'reate,Delete,Xlate */
1348:     status = SS$_NORMAL;                        /* reset status */
1349:     replies =                                   /* write message or read */
1350:      (char **)prompt("vmstrnlnm()... Enter {'C're,Del,Xlat},lognam[,logval]",
1351:      ",");
1352:     if ( *replies[0] == '\000' ) break;         /* CR to quit loop */
1353:     opcode = toupper(*replies[0]);              /* 1st char of 1st reply */
1354:     if ( replies[1] == (char *)NULL ) continue; /* no lognam arg */
1355:     if ( opcode == 'C' )                        /* create logical name */
1356:      if ( replies[2] != (char *)NULL )          /* make sure we got logval */
1357:       status = vmscrelnm(replies[1],replies[2],NULL);
1358:     if ( opcode == 'D' )                        /* delete logical name */
1359:       status = vmsdellnm(replies[1],NULL);
1360:     if ( status != SS$_NORMAL )                 /* got error return */
1361:       printf("  vms%slnm(%s) error: %s\n",
1362:       ((opcode=='C')?"cre":"del"),replies[1],vmsmsg(status));
1363:     status = vmstrnlnm(replies[1],logval);      /* always try to translate */
1364:     if ( status == SS$_NORMAL )                 /* xlated okay */
1365:       printf("  vmstrnlnm(%s) = %s\n",replies[1],logval);
1366:     else printf("  vmstrnlnm(%s) error: %s\n",replies[1],vmsmsg(status));
1367:     } /* --- end-of-while(1) --- */
1368: /* -------------------------------------------------------------------------
1369: end-of-exercises
1370: -------------------------------------------------------------------------- */
1371: } /* --- end-of-function main() --- */
1372: 
1373: /* ==========================================================================
1374:  * Function:    prompt ( promptstr, delimstr )
1375:  * Purpose:     display prompt and get reply (or replies separated by delim)
1376:  * --------------------------------------------------------------------------
1377:  * Arguments:   promptstr (I)           addr of char string containing
1378:  *                                      prompt to be displayed.
1379:  *              delimstr (I)            addr of char string whose first char
1380:  *                                      contains the delim separating reply
1381:  *                                      fields.
1382:  * --------------------------------------------------------------------------
1383:  * Returns:     ( char * or char **)    (char *) of reply if delimstr=NULL, 
1384:  *                                      (char **) of reply fields otherwise
1385:  * --------------------------------------------------------------------------
1386:  * Notes:
1387:  * ======================================================================= */
1388: /* --- entry point --- */
1389: char    *prompt ( promptstr, delimstr )
1390: char    *promptstr;
1391: char    *delimstr;
1392: {
1393: /* --- Allocations and Declarations --- */
1394: static  char replystr[256], *replies[32];       /*user reply & ptrs into it*/
1395: char    *replyptr = replystr;                   /* ptr to current field */
1396: int     nreplies = 1;                           /* #fields in reply */
1397: char    delim = '\000';                         /* delim separating fields */
1398: char    *strptr, *strchr();                     /* search for delim */
1399: /* --- display prompt if provided --- */
1400: if ( promptstr != (char *)NULL )                /*caller passed prompt addr*/
1401:   if ( *promptstr != '\000' )                   /* with non-null string */
1402:     printf("%s --> ",promptstr);                /* display prompt with --> */
1403: /* --- get reply and remove trailing \n (if present) --- */
1404: gets(replystr);                                 /* wait for CR-termination */
1405: if ( (strptr = strchr(replystr,'\n'))           /* and look for CR in reply*/
1406: !=   (char *)NULL )                             /* got one from system */
1407:   *strptr = '\000';                             /* so remove it */
1408: /* --- parse reply into multiple delim-separated fields --- */
1409: if ( delimstr != (char *)NULL )                 /* caller passed delim addr*/
1410:   delim = *delimstr;                            /* we only use 1 char delim*/
1411: if ( delim != '\000' )                          /* check that it's non-null*/
1412:   {
1413:   replies[0] = replyptr = replystr;             /* 1st reply field at start*/
1414:   while ( (strptr = strchr(replyptr,delim))     /* look for a delim */
1415:   != (char *)NULL )                             /* found it */
1416:     { *strptr++ = '\000';                       /*terminate preceding field*/
1417:       replies[nreplies++] = replyptr = strptr; } /*store ptr for this field*/
1418:   replies[nreplies] = (char *)NULL;             /*NULL ptr after last field*/
1419:   replyptr = (char *)replies;                   /* return addr of ptr array*/
1420:   } /* --- end-of-if(delim!=0) --- */
1421: /* --- return single reply or multiple reply fields to caller --- */
1422: return ( replyptr );                            /* may be char* or char** */
1423: } /* --- end-of-function prompt() --- */
1424: #endif
1425: /* ========================= END-OF-FILE VMSLIB.C ======================== */

Copyright © 1986-2010, John Forkosh Associates, Inc.   All rights reserved.
email: john@forkosh.com