home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #31 / NN_1992_31.iso / spool / comp / os / vms / 20056 < prev    next >
Encoding:
Text File  |  1992-12-30  |  12.6 KB  |  405 lines

  1. Path: sparky!uunet!pipex!bnr.co.uk!uknet!mcsun!sun4nl!relay.philips.nl!cnplss5!cnplss5!hd
  2. From: hd@cnplss5.cft.philips.nl (Henk Davids)
  3. Newsgroups: comp.os.vms
  4. Subject: Re: Alternative callable editors in MAIL? [source+question]
  5. Message-ID: <1992Dec30.044645.11200@cnplss5.cnps.philips.nl>
  6. Date: 30 Dec 92 04:46:45 GMT
  7. References: <9212282149.AA16692@uu3.psi.com>
  8. Sender: news@cnplss5.cnps.philips.nl (USENET News System)
  9. Organization: Philips Communications & Processing Services, Eindhoven
  10. Lines: 392
  11. Nntp-Posting-Host: cnplss5
  12.  
  13.  
  14. Following up on the creation of custom editor modules for MAIL,
  15. below you will find some code designed to attach to a subprocess
  16. that has been created earlier, presumably running EVE or GNU Emacs.
  17. You will almost certainly have to change this. Besides that, the
  18. editor that we will attach to will have to do something sensible
  19. with the job logical names that are set by this routine. I will
  20. leave that as an exercise for the reader.
  21.  
  22. So much for the warnings.
  23.  
  24. Now a question: the comment in the C module says that MAIL is an installed
  25. module. In fact, it is not. Neither are the shareable images that MAIL will
  26. call. How then does MAIL get its privileges (SYSPRIV) to write into other
  27. peoples' mail files?
  28.  
  29.                 Henk
  30.  
  31. Below the makefile, the .OPT files and the C source.
  32. --start of makefile--
  33. .ifdef DEBUG
  34. CFLAGS=/debug/noopt/define=(TESTING
  35. LINKFLAGS=/debug/exe=$@
  36. .else
  37. CFLAGS=/optim=noinline/define=(DUMMY
  38. LINKFLAGS=/shareable=$@
  39. .endif
  40.  
  41. GNUOBJ=gnushr.obj
  42. GNUOPT=gnushr.opt
  43. EVEOBJ=eveshr.obj
  44. EVEOPT=eveshr.opt
  45.  
  46. all : gnushr.exe eveshr.exe
  47.       ! Done.
  48.  
  49. gnushr.exe : $(GNUOBJ) $(GNUOPT)
  50.        link $(LINKFLAGS) $(GNUOBJ),$(GNUOPT)/opt
  51.  
  52. eveshr.exe : $(EVEOBJ) $(EVEOPT)
  53.        link $(LINKFLAGS) $(EVEOBJ),$(EVEOPT)/opt
  54.  
  55. gnushr.obj : editshr.c
  56.        cc $(CFLAGS),GNU)/object=$@ editshr.c
  57.  
  58. eveshr.obj : editshr.c
  59.        cc $(CFLAGS),EVE)/object=$@ editshr.c
  60. --end of makefile--
  61. --start of eveshr.opt
  62. universal=EVE$EDIT
  63. --end of eveshr.opt
  64. --start of gnushr.opt
  65. universal=GNU$EDIT
  66. --end of gnushr.opt
  67.  
  68. --start of editshr.c--
  69. /*
  70.  EDITSHR: a shareable image that may be used by VMS MAIL as an editor.
  71.  Both the interface to a suspended EVE and GNUEmacs can be handled
  72.  by this source. See the accompanying makefile for the generation
  73.  procedure.
  74.  Define either EVE or GNU on the compiler invocation. To create a test
  75.  version, define TESTING too (see main() at end of this file).
  76.  
  77.  After creating the GNUSHR and EVESHR shareable images, install them
  78.  in SYS$SHARE. Since MAIL is an installed image, VMS expects these images
  79.  to be installed as well.
  80.  If you do not want to install the shareable image but want to use it
  81.  anyway, define MAIL as SYS$SYSTEM:MAIL.EXE;0. This will let you use
  82.  the non-installed version of MAIL, in which case VMS will allow you
  83.  to use private -non-installed- versions of GNUSHR or EVESHR.
  84.  
  85.  Operation:
  86.  1. tell MAIL to use the shareable image as editor call, by entering
  87.        SET EDITOR GNU
  88.      or
  89.        SET EDITOR EVE
  90.     This only has to be given once. MAIL will remember this setting.
  91.     Make sure you do not have a logical MAIL$EDIT defined when running
  92.     MAIL - this will override any setting you have given here.
  93.  2. When MAIL decides it's time to call the editor, it will activate
  94.     the GNUSHR/EVESHR image with appropriate parameters.
  95.  3. GNU$EDIT/EVE$EDIT then performs the following actions:
  96.     a. compose the processname of the editor. For Eve, this is "EVE_"
  97.        followed by the translation of the logical "TT:". For GNU Emacs,
  98.        this is "Emacs_" followed by the translation of the logical "TT:"
  99.        without a trailing colon. In any case, the procedure you use to
  100.        spawn the editor should set the process name in accordance with
  101.        this.
  102.     b. find the PID of that process. If the editor cannot be found,
  103.        callable TPU will be used. Note that TPU will start with the
  104.        section-name taken from the logical TPU$SECTION. If you did
  105.        not supply this logical name, the default systemtable definition
  106.        will be used. Currently (VMS 5.5) this is the standard EVE.
  107.     c. define a few job logical names:
  108.        <editor>_FILE_NAME         the input file to be read
  109.        <editor>_OUTPUT_FILE_NAME  where the output should go
  110.        <editor>_<editor_pid>      the PID of the process running MAIL
  111.     d. attach to the editor.
  112.     e. on return from the editor, cleanup and return to MAIL.
  113.  
  114.  Note: the fact that MAIL uses the simplified interface to a callable
  115.  editor is just sheer luck - it's not documented. This means of course
  116.  that future versions of MAIL may not work with this code.
  117. */
  118.  
  119. #include <ssdef.h>
  120. #include <descrip.h>
  121. #include <lib$routines.h>
  122.  
  123. /* Forward procedure definitions */
  124. static unsigned long call_tpu(struct dsc$descriptor *inputfile,
  125.                   struct dsc$descriptor *outputfile);
  126. static void longtohex(char *ptr, unsigned long value);
  127. static void strcpy(char *to, char *from);
  128. static void strncpy(char *to, char *from, int length);
  129. static unsigned long find_process(struct dsc$descriptor_s *name,
  130.                   unsigned long *pid_ptr);
  131. static unsigned long translate_logical_name(struct dsc$descriptor_s *logical_name,
  132.                         struct dsc$descriptor_s *string);
  133. static unsigned long define_logical_name(struct dsc$descriptor_s *logical_name,
  134.                      struct dsc$descriptor_s *string);
  135. static unsigned long delete_logical_name(struct dsc$descriptor_s* logical_name);
  136.  
  137. /* Selection of constants that differ between GNUEmacs and EVE */
  138. #ifdef EVE
  139. #define EDITOR_FILE_NAME "EVE_FILE_NAME"
  140. #define EDITOR_OUTPUT_FILE_NAME "EVE_OUTPUT_FILE_NAME"
  141. #define NAME_PREFIX "EVE"
  142. #define PID_PREFIX "EVE_"
  143. #define EDITOR_PID_LOGNAM "EVE_XXXXXXXX"
  144. #define ENTRYNAME EVE$EDIT
  145. #define NO_COLON 0
  146. #else    /* GNU */
  147. #define EDITOR_FILE_NAME "EMACS_FILE_NAME"
  148. #define EDITOR_OUTPUT_FILE_NAME "EMACS_OUTPUT_FILE_NAME"
  149. #define NAME_PREFIX "Emacs"
  150. #define PID_PREFIX "EMACS_"
  151. #define EDITOR_PID_LOGNAM "EMACS_XXXXXXXX"
  152. #define ENTRYNAME GNU$EDIT
  153. #define NO_COLON 1
  154. #endif
  155.  
  156. /* Common constants */
  157. /* maximum length of a process name */
  158. #define MAXPROCESSNAM 32
  159. /* maximum length of the translation of a logical name */
  160. #define MAXTRANSLATION 1024
  161.  
  162. /* Macro to test the result of a status value */
  163. #define OK(i) ((i) & 1)
  164.  
  165. /*
  166.   This is the procedure that will be called by MAIL.
  167.   At the time of the call, MAIL will have exported
  168.   any message that is needed from the MAIL-file to the
  169.   file system.
  170.   ENTRYNAME can be GNU$EDIT or EVE$EDIT, as specified above.
  171.   Return value is a VMS status longword (always SS$_NORMAL).
  172.   Errors preventing proper operation will be signalled.
  173. */
  174.  
  175. unsigned long ENTRYNAME(struct dsc$descriptor *inputfile,
  176.             struct dsc$descriptor *outputfile)
  177. {
  178.     $DESCRIPTOR(inputfile_lognam, EDITOR_FILE_NAME);
  179.     $DESCRIPTOR(outputfile_lognam, EDITOR_OUTPUT_FILE_NAME);
  180.     $DESCRIPTOR(tt_lognam_dsc, "TT");
  181.     char tt_translation[MAXTRANSLATION+1];
  182.     $DESCRIPTOR(tt_translation_dsc, tt_translation);
  183.     char editor_name[MAXPROCESSNAM+1];
  184.     $DESCRIPTOR(editor_name_dsc, editor_name);
  185.     char editor_pid_lognam[] = EDITOR_PID_LOGNAM;
  186.     $DESCRIPTOR(editor_pid_dsc, editor_pid_lognam);
  187.     char editor_pid_def_lognam[] = "XXXXXXXX";
  188.     $DESCRIPTOR(editor_pid_def_dsc, editor_pid_def_lognam);
  189.     unsigned long editor_pid;
  190.     unsigned long my_pid;
  191.     unsigned long status, ignore;
  192.     int i;
  193.  
  194.     /* generate the process name of the editor */
  195.     status = translate_logical_name(&tt_lognam_dsc, &tt_translation_dsc);
  196.     if (!OK(status))
  197.     lib$signal(status);
  198.     /* processname = prefix + f$logical("TT") */
  199.     strcpy(editor_name, NAME_PREFIX);
  200.     i = sizeof(NAME_PREFIX) - 1;
  201.     if (tt_translation_dsc.dsc$w_length > 0) {
  202.     if (tt_translation[0] != '_') {
  203.         editor_name[i++] = '_';
  204.     }
  205.     strncpy(&editor_name[i], tt_translation,
  206.         tt_translation_dsc.dsc$w_length);
  207.     i += tt_translation_dsc.dsc$w_length;
  208.     }
  209.     if (i > 0 && NO_COLON && editor_name[i-1] == ':')
  210.     i--;
  211.     editor_name_dsc.dsc$w_length = i;
  212.     
  213.     /* find the PID of the editor process */
  214.     status = find_process(&editor_name_dsc, &editor_pid);
  215.     if (!OK(status)) {
  216.     /* could not find kept editor, print warning message */
  217.     /* activate callable TPU */
  218.     status = call_tpu(inputfile, outputfile);
  219.     if (!OK(status))
  220.         lib$signal(status);
  221.     return(SS$_NORMAL);
  222.     /*NOTREACHED*/
  223.     }
  224.  
  225.     if (inputfile && inputfile->dsc$w_length) {
  226.     status = define_logical_name(&inputfile_lognam, inputfile);
  227.     if (!OK(status))
  228.         lib$signal(status);
  229.     }
  230.     if (outputfile && outputfile->dsc$w_length) {
  231.     status = define_logical_name(&outputfile_lognam, outputfile);
  232.     if (!OK(status))
  233.         lib$signal(status);
  234.     }
  235.     /* define "<editor>_pid"="my_pid" to get back here after suspend */
  236.     ignore = find_process(0, &my_pid);
  237.     longtohex(&editor_pid_lognam[sizeof(PID_PREFIX)-1], editor_pid);
  238.     longtohex(editor_pid_def_lognam, my_pid);
  239.     status = define_logical_name(&editor_pid_dsc, &editor_pid_def_dsc);
  240.     if (!OK(status))
  241.     lib$signal(status);
  242.  
  243.     status = lib$attach(&editor_pid);
  244.     if (!OK(status)) {
  245.     ignore = delete_logical_name(&inputfile_lognam);
  246.     ignore = delete_logical_name(&outputfile_lognam);
  247.     ignore = delete_logical_name(&editor_pid_dsc);
  248.     lib$signal(status);
  249.     }
  250.     status = delete_logical_name(&inputfile_lognam);
  251.     status = delete_logical_name(&outputfile_lognam);
  252.     status = delete_logical_name(&editor_pid_dsc);
  253.  
  254.     return(SS$_NORMAL);
  255. }
  256.  
  257. /* call_tpu: find and start the callable TPU. This is only done
  258.  * if a kept editor could not be found.
  259. */
  260. static unsigned long call_tpu(struct dsc$descriptor *inputfile,
  261.                   struct dsc$descriptor *outputfile)
  262. {
  263.     $DESCRIPTOR(tpu_file_name_dsc, "TPUSHR");
  264.     $DESCRIPTOR(tpu_symbol_name_dsc, "TPU$EDIT");
  265.     unsigned long (*symbol_value)();
  266.     unsigned long status;
  267.     
  268.     status = lib$find_image_symbol(&tpu_file_name_dsc,
  269.                    &tpu_symbol_name_dsc,
  270.                    &symbol_value);
  271.     if (OK(status)) {
  272.     status = (*symbol_value)(inputfile, outputfile);
  273.     }
  274.     return(status);
  275. }
  276.                   
  277. /* Private utility functions to avoid having to link against
  278.  * the VAXCRTL library
  279.  */
  280. static void strcpy(char *to, char *from)
  281. {
  282.     do {
  283.     *to++ = *from;
  284.     } while (*from++);
  285. }    
  286.  
  287. static void strncpy(char *to, char *from, int length)
  288. {
  289.     do {
  290.     *to++ = *from;
  291.     } while (*from++ && --length > 0);
  292. }    
  293.  
  294. static void longtohex(char *ptr, unsigned long value)
  295. {
  296.     char hextab[] = "0123456789ABCDEF";
  297.     int i;
  298.  
  299.     for (i=28; i>=0; i-=4) {
  300.     *ptr++ = hextab[value>>i & 0xf];
  301.     }
  302. }
  303.  
  304. #include <jpidef.h>
  305. /*
  306.  * Given a process name, find the PID of that process
  307.  * If the process name is not given (i.e. NULL is passed),
  308.  * the PID of the current process is returned.
  309.  */
  310. static unsigned long find_process(struct dsc$descriptor_s *name,
  311.                   unsigned long *pid_ptr)
  312. {
  313.     unsigned short code = JPI$_PID;
  314.     unsigned long status;
  315.  
  316.     status = lib$getjpi(&code, 0, name, pid_ptr, 0, 0);
  317.     return(status);
  318. }
  319.  
  320. /*
  321.  * Job logical name handling.
  322.  */
  323.  
  324. #include lnmdef
  325.  
  326. #define TABLE_NAME "LNM$JOB"
  327.  
  328. typedef union {
  329.     unsigned long terminator;
  330.     struct {
  331.     short length;
  332.     short code;
  333.     void *buffer;
  334.     long ret_length;
  335.     }item;
  336. } ITEM;
  337.  
  338. /*
  339.  * Translate a logical name
  340.  */
  341. static unsigned long translate_logical_name(struct dsc$descriptor_s *logical_name,
  342.                         struct dsc$descriptor_s *string)
  343. {
  344.   unsigned long status;
  345.   short length;
  346.  
  347.   status = lib$sys_trnlog(logical_name, &length, string);
  348.   if (OK(status)) {
  349.       if (status == SS$_NOTRAN) {
  350.       string->dsc$w_length = 0;
  351.       } else {
  352.       string->dsc$w_length = length;
  353.       }
  354.   }
  355.   return(status);
  356. }
  357.  
  358. /*
  359.  * Define a supervisor mode logical name in TABLE_NAME
  360.  * Return status is the VMS return code from lib$set_logical.
  361.  * 
  362.  * Note: using lowercase for the logical name itself will succeed, but
  363.  *     you will not be able to use that name for anything useful.
  364.  */
  365. static unsigned long define_logical_name(struct dsc$descriptor_s *logical_name,
  366.                      struct dsc$descriptor_s *string)
  367. {
  368.     ITEM item_list[2];
  369.     struct dsc$descriptor_s table_dsc =
  370.     {sizeof(TABLE_NAME)-1, DSC$K_DTYPE_T, DSC$K_CLASS_S, TABLE_NAME};
  371.  
  372.     item_list[0].item.buffer = string->dsc$a_pointer;
  373.     item_list[0].item.length = string->dsc$w_length;
  374.     item_list[0].item.code = LNM$_STRING;
  375.     item_list[0].item.ret_length = 0;
  376.     
  377.     item_list[1].terminator = 0;
  378.  
  379.     /* Use 0 i.s.o. &table_dsc for a process logical name */
  380.     return lib$set_logical(logical_name, 0, &table_dsc, 0, item_list);
  381. }
  382.  
  383. /*
  384.  * Delete a supervisor mode logical name from TABLE_NAME
  385.  */
  386. static unsigned long delete_logical_name(struct dsc$descriptor_s *lnm_dsc)
  387. {
  388.     struct dsc$descriptor_s table_dsc =
  389.       {sizeof(TABLE_NAME)-1, DSC$K_DTYPE_T, DSC$K_CLASS_S, TABLE_NAME};
  390.  
  391.     return lib$delete_logical(lnm_dsc, &table_dsc);
  392. }
  393.  
  394. #ifdef TESTING
  395. main()
  396. {
  397.     $DESCRIPTOR(inputfile_dsc,"INPUT");
  398.     $DESCRIPTOR(outputfile_dsc,"OUTPUT");
  399.     unsigned long status;
  400.  
  401.     status = ENTRYNAME(&inputfile_dsc, &outputfile_dsc);
  402. }
  403. #endif
  404. --end of editshr.c--
  405.