home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 1 / ARM_CLUB_CD.iso / contents / apps / program / d / elvis / Source / c / cmd1 < prev    next >
Encoding:
Text File  |  1990-04-14  |  14.6 KB  |  810 lines

  1. /* cmd1.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    16820 SW Tallac Way
  6.  *    Beaverton, OR 97006
  7.  *    kirkenda@jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
  8.  */
  9.  
  10.  
  11. /* This file contains some of the EX commands - mostly ones that deal with
  12.  * files, options, etc. -- anything except text.
  13.  */
  14.  
  15. #include <ctype.h>
  16. #include "vi.h"
  17. #include "regexp.h"
  18.  
  19. #ifdef DEBUG
  20. /* print the selected lines with info on the blocks */
  21. void cmd_debug(frommark, tomark, cmd, bang, extra)
  22.     MARK    frommark;
  23.     MARK    tomark;
  24.     CMD    cmd;
  25.     int    bang;
  26.     char    *extra;
  27. {
  28.     register char    *scan;
  29.     register long    l;
  30.     register int    i;
  31.     int        len;
  32.  
  33.     /* scan lnum[] to determine which block its in */
  34.     l = markline(frommark);
  35.     for (i = 1; l > lnum[i]; i++)
  36.     {
  37.     }
  38.  
  39.     do
  40.     {
  41.         /* fetch text of the block containing that line */
  42.         scan = blkget(i)->c;
  43.  
  44.         /* calculate its length */
  45.         if (scan[BLKSIZE - 1])
  46.         {
  47.             len = BLKSIZE;
  48.         }
  49.         else
  50.         {
  51.             len = strlen(scan);
  52.         }
  53.  
  54.         /* print block stats */
  55.         wprintw(stdscr, "##### hdr[%d]=%d, lnum[%d-1]=%ld, lnum[%d]=%ld (%ld lines)\n",
  56.             i, hdr.n[i], i, lnum[i-1], i, lnum[i], lnum[i] - lnum[i - 1]);
  57.         wprintw(stdscr, "##### len=%d, buf=0x%lx, %sdirty\n",
  58.             len, scan, ((int *)scan)[MAXBLKS + 1] ? "" : "not ");
  59.         if (bang)
  60.         {
  61.             while (--len >= 0)
  62.             {
  63.                 addch(*scan);
  64.                 scan++;
  65.             }
  66.         }
  67.         exrefresh();
  68.  
  69.         /* next block */
  70.         i++;
  71.     } while (i < MAXBLKS && lnum[i] && lnum[i - 1] < markline(tomark));
  72. }
  73.  
  74.  
  75. /* This function checks a lot of conditions to make sure they aren't screwy */
  76. void cmd_validate(frommark, tomark, cmd, bang, extra)
  77.     MARK    frommark;
  78.     MARK    tomark;
  79.     CMD    cmd;
  80.     int    bang;
  81.     char    *extra;
  82. {
  83.     char    *scan;
  84.     ushort    i;
  85.     int    nlcnt;    /* used to count newlines */
  86.     int    len;    /* counts non-NUL characters */
  87.  
  88.     /* check lnum[0] */
  89.     if (lnum[0] != 0L)
  90.     {
  91.         wprintw(stdscr, "lnum[0] = %ld\n", lnum[0]);
  92.     }
  93.  
  94.     /* check each block */
  95.     for (i = 1; lnum[i] <= nlines; i++)
  96.     {
  97.         scan = blkget(i)->c;
  98.         if (scan[BLKSIZE - 1])
  99.         {
  100.             wprintw(stdscr, "block %d has no NUL at the end\n", i);
  101.         }
  102.         else
  103.         {
  104.             for (nlcnt = len = 0; *scan; scan++, len++)
  105.             {
  106.                 if (*scan == '\n')
  107.                 {
  108.                     nlcnt++;
  109.                 }
  110.             }
  111.             if (scan[-1] != '\n')
  112.             {
  113.                 wprintw(stdscr, "block %d doesn't end with '\\n' (length %d)\n", i, len);
  114.             }
  115.             if (bang || nlcnt != lnum[i] - lnum[i - 1])
  116.             {
  117.                 wprintw(stdscr, "block %d (line %ld?) has %d lines, but should have %ld\n",
  118.                     i, lnum[i - 1] + 1L, nlcnt, lnum[i] - lnum[i - 1]);
  119.             }
  120.         }
  121.         exrefresh();
  122.     }
  123.  
  124.     /* check lnum again */
  125.     if (lnum[i] != INFINITY)
  126.     {
  127.         wprintw(stdscr, "hdr.n[%d] = %d, but lnum[%d] = %ld\n",
  128.             i, hdr.n[i], i, lnum[i]);
  129.     }
  130.  
  131.     wprintw(stdscr, "# = \"%s\", %% = \"%s\"\n", prevorig, origname);
  132. }
  133. #endif
  134.  
  135.  
  136. void cmd_mark(frommark, tomark, cmd, bang, extra)
  137.     MARK    frommark;
  138.     MARK    tomark;
  139.     CMD    cmd;
  140.     int    bang;
  141.     char    *extra;
  142. {
  143.     /* validate the name of the mark */
  144.     if (!extra || *extra < 'a' || *extra > 'z' || extra[1])
  145.     {
  146.         msg("Invalid mark name");
  147.         return;
  148.     }
  149.  
  150.     mark[*extra - 'a'] = tomark;
  151. }
  152.  
  153. void cmd_write(frommark, tomark, cmd, bang, extra)
  154.     MARK    frommark;
  155.     MARK    tomark;
  156.     CMD    cmd;
  157.     int    bang;
  158.     char    *extra;
  159. {
  160.     int        fd;
  161.     register long    l;
  162.     register char    *scan;
  163.     register int    i;
  164.  
  165.     /* if all lines are to be written, use tmpsave() */
  166.     if (frommark == MARK_FIRST && tomark == MARK_LAST)
  167.     {
  168.         tmpsave(extra);
  169.         return;
  170.     }
  171.  
  172.     /* else do it line-by-line, like cmd_print() */
  173.     fd = open((*extra == '>' ? extra + 2 : extra), 1);
  174.     if (fd < 0)
  175.     {
  176.         fd = creat(extra, 0644);
  177.         if (fd < 0)
  178.         {
  179.             msg("Can't write to \"%s\"", extra);
  180.             return;
  181.         }
  182.     }
  183.     else if (*extra == '>')
  184.     {
  185.         lseek(fd, 0L, 2);
  186.     }
  187.     for (l = markline(frommark); l <= markline(tomark); l++)
  188.     {
  189.         /* get the next line */
  190.         scan = fetchline(l);
  191.         i = strlen(scan);
  192.         scan[i++] = '\n';
  193.  
  194.         /* print the line */
  195.         write(fd, scan, i);
  196.     }
  197.     close(fd);
  198. }    
  199.  
  200.  
  201. void cmd_shell(frommark, tomark, cmd, bang, extra)
  202.     MARK    frommark, tomark;
  203.     CMD    cmd;
  204.     int    bang;
  205.     char    *extra;
  206. {
  207.     static char    prevextra[80];
  208.  
  209.     /* special case: ":sh" means ":!sh" */
  210.     if (cmd == CMD_SHELL)
  211.     {
  212.         extra = o_shell;
  213.         frommark = tomark = 0L;
  214.     }
  215.  
  216.     /* if extra is "!", substute previous command */
  217.     if (*extra == '!')
  218.     {
  219.         if (!*prevextra)
  220.         {
  221.             addstr("No previous shell command to substitute for '!'\n");
  222.             return;
  223.         }
  224.         extra = prevextra;
  225.     }
  226.     else
  227.     {
  228.         strcpy(prevextra, extra);
  229.     }
  230.  
  231.     /* if no lines were specified, just run the command */
  232.     suspend_curses();
  233.     if (frommark == 0L)
  234.     {
  235.         system(extra);
  236.     }
  237.     else /* pipe lines from the file through the command */
  238.     {
  239.         filter(frommark, tomark, extra);
  240.     }
  241.  
  242.     /* resume curses quietly for MODE_EX, but noisily otherwise */
  243.     resume_curses(mode == MODE_EX);
  244. }
  245.  
  246.  
  247. void cmd_global(frommark, tomark, cmd, bang, extra)
  248.     MARK    frommark, tomark;
  249.     CMD    cmd;
  250.     int    bang;
  251.     char    *extra;    /* rest of the command line */
  252. {
  253.     char    *cmdptr;    /* the command from the command line */
  254.     char    cmdln[100];    /* copy of the command from the command line */
  255.     char    *line;        /* a line from the file */
  256.     long    l;        /* used as a counter to move through lines */
  257.     long    lqty;        /* quantity of lines to be scanned */
  258.     regexp    *re;        /* the compiled search expression */
  259.  
  260.     /* ":g! ..." is the same as ":v ..." */
  261.     if (bang)
  262.     {
  263.         cmd = CMD_VGLOBAL;
  264.     }
  265.  
  266.     /* make sure we got a search pattern */
  267.     if (*extra != '/' && *extra != '?')
  268.     {
  269.         msg("Usage: %c /regular expression/ command", cmd == CMD_GLOBAL ? 'g' : 'v');
  270.         return;
  271.     }
  272.  
  273.     /* parse & compile the search pattern */
  274.     cmdptr = parseptrn(extra);
  275.     if (!extra[1])
  276.     {
  277.         msg("Can't use empty regular expression with '%c' command", cmd == CMD_GLOBAL ? 'g' : 'v');
  278.         return;
  279.     }
  280.     re = regcomp(extra + 1);
  281.     if (!re)
  282.     {
  283.         /* regcomp found & described an error */
  284.         return;
  285.     }
  286.  
  287.     /* for each line in the range */
  288.     ChangeText
  289.     {
  290.         /* NOTE: we have to go through the lines in a forward order,
  291.          * otherwise "g/re/p" would look funny.  *BUT* for "g/re/d"
  292.          * to work, simply adding 1 to the line# on each loop won't
  293.          * work.  The solution: count lines relative to the end of
  294.          * the file.  Think about it.
  295.          */
  296.         for (l = nlines - markline(frommark), lqty = markline(tomark) - markline(frommark) + 1L;
  297.              lqty > 0 && nlines - l >= 0;
  298.              l--, lqty--)
  299.         {
  300.             /* fetch the line */
  301.             line = fetchline(nlines - l);
  302.  
  303.             /* if it contains the search pattern... */
  304.             if ((!regexec(re, line, 1)) == (cmd != CMD_GLOBAL))
  305.             {
  306.                 /* move the cursor to that line */
  307.                 cursor = MARK_AT_LINE(nlines - l);
  308.  
  309.                 /* do the ex command (without mucking up
  310.                  * the original copy of the command line)
  311.                  */
  312.                 strcpy(cmdln, cmdptr);
  313.                 doexcmd(cmdln);
  314.             }
  315.         }
  316.     }
  317.  
  318.     /* free the regexp */
  319.     free(re);
  320. }
  321.  
  322.  
  323. void cmd_file(frommark, tomark, cmd, bang, extra)
  324.     MARK    frommark, tomark;
  325.     CMD    cmd;
  326.     int    bang;
  327.     char    *extra;
  328. {
  329.     if (frommark == tomark)
  330.     {
  331.         msg( "\"%s\" %s%s %ld lines, this is line %ld  [%ld%%]",
  332.             *origname ? origname : "[NO FILE]",
  333.             tstflag(file, MODIFIED) ? "[MODIFIED]" : "",
  334.             tstflag(file, READONLY) ? "[READONLY]" : "",
  335.             nlines,
  336.             markline(frommark),
  337.             markline(frommark) * 100 / nlines);
  338.     }
  339.     else
  340.     {
  341.         msg( "\"%s\" %s%s %ld lines, range  %ld,%ld  contains %ld lines",
  342.             *origname ? origname : "[NO FILE]",
  343.             tstflag(file, MODIFIED) ? "[MODIFIED]" : "",
  344.             tstflag(file, READONLY) ? "[READONLY]" : "",
  345.             nlines,
  346.             markline(frommark), markline(tomark),
  347.             markline(tomark) - markline(frommark) + 1L);
  348.     }
  349. }
  350.  
  351.  
  352. void cmd_edit(frommark, tomark, cmd, bang, extra)
  353.     MARK    frommark, tomark;
  354.     CMD    cmd;
  355.     int    bang;
  356.     char    *extra;
  357. {
  358.     long    line = 1L;    /* might be set to prevline */
  359.  
  360.     if (!strcmp(extra, prevorig))
  361.     {
  362.         line = prevline;
  363.     }
  364.  
  365.     /* switch files */
  366.     if (tmpabort(bang))
  367.     {
  368.         tmpstart(extra);
  369.         if (line <= nlines && line >= 1L)
  370.         {
  371.             cursor = MARK_AT_LINE(line);
  372.         }
  373.     }
  374.     else
  375.     {
  376.         addstr("Use edit! to abort changes, or w to save changes\n");
  377.  
  378.         /* so we can say ":e!" with no filename next time... */
  379.         strcpy(prevorig, extra);
  380.         prevline = 1L;
  381.     }
  382. }
  383.  
  384.  
  385. void cmd_next(frommark, tomark, cmd, bang, extra)
  386.     MARK    frommark, tomark;
  387.     CMD    cmd;
  388.     int    bang;
  389.     char    *extra;
  390. {
  391.     int    i, j;
  392.     char    *scan;
  393.     char    *build;
  394.  
  395.     /* if extra stuff given, use ":args" to define a new args list */
  396.     if (extra && *extra)
  397.     {
  398.         cmd_args(frommark, tomark, cmd, bang, extra);
  399.     }
  400.  
  401.     /* move to the next arg */
  402.     if (cmd == CMD_NEXT)
  403.     {
  404.         i = argno + 1;
  405.     }
  406.     else
  407.     {
  408.         i = argno - 1;
  409.     }
  410.     if (i < 0 || i >= nargs)
  411.     {
  412.         msg("No more files to edit");
  413.         return;
  414.     }
  415.  
  416.     /* find & isolate the name of the file to edit */
  417.     for (j = i, scan = args; j > 0; j--)
  418.     {
  419.         while(!isspace(*scan))
  420.         {
  421.             scan++;
  422.         }
  423.         while(isspace(*scan))
  424.         {
  425.             scan++;
  426.         }
  427.     }
  428.     for (build = tmpblk.c; *scan && !isspace(*scan); )
  429.     {
  430.         *build++ = *scan++;
  431.     }
  432.     *build = '\0';
  433.  
  434.     /* switch to the next file */
  435.     if (tmpabort(bang))
  436.     {
  437.         tmpstart(tmpblk.c);
  438.         argno = i;
  439.     }
  440.     else
  441.     {
  442.         addstr("Use next! to abort changes, or w to save changes\n");
  443.     }
  444. }
  445.  
  446.  
  447. void cmd_xit(frommark, tomark, cmd, bang, extra)
  448.     MARK    frommark, tomark;
  449.     CMD    cmd;
  450.     int    bang;
  451.     char    *extra;
  452. {
  453.     if (tmpend(bang))
  454.     {
  455.         mode = MODE_QUIT;
  456.     }
  457.     else
  458.     {
  459.         msg("Could not save file -- use quit! to abort changes, or w filename");
  460.     }
  461. }
  462.  
  463.  
  464. void cmd_args(frommark, tomark, cmd, bang, extra)
  465.     MARK    frommark, tomark;
  466.     CMD    cmd;
  467.     int    bang;
  468.     char    *extra;
  469. {
  470.     char    *scan;
  471.     int    i;
  472.     int    spc;    /* boolean: was previous char a space? */
  473.  
  474.     /* if no extra names given, or just current name, then report the args
  475.      * we have now.
  476.      */
  477.     if (!extra || !*extra)
  478.     {
  479.         /* for each element of args... */
  480.         for (scan = args, spc = TRUE, i = 0; *scan; )
  481.         {
  482.             /* bracket before the current arg */
  483.             if (*scan != ' ' && *scan != '\t' && spc && i == argno)
  484.             {
  485.                 qaddch('[');
  486.             }
  487.  
  488.             qaddch(*scan);
  489.  
  490.             spc = (*scan == ' ' || *scan == '\t');
  491.  
  492.             scan++;
  493.  
  494.             /* bracket after current arg */
  495.             if ((!*scan || *scan == ' ' || *scan == '\t') && !spc)
  496.             {
  497.                 if (i == argno)
  498.                 {
  499.                     qaddch(']');
  500.                 }
  501.                 i++;
  502.             }
  503.         }
  504.     
  505.         /* write a trailing newline */
  506.         addch('\n');
  507.         exrefresh();
  508.     }
  509.     else /* new args list given */
  510.     {
  511.         strcpy(args, extra);
  512.         argno = -1; /* before the first, so :next wil go to first */
  513.  
  514.         /* count the names */
  515.         for (nargs = 0, scan = args; *scan; nargs++)
  516.         {
  517.             while (*scan && !isspace(*scan))
  518.             {
  519.                 scan++;
  520.             }
  521.             while (isspace(*scan))
  522.             {
  523.                 scan++;
  524.             }
  525.         }
  526.         msg("%d files to edit", nargs);
  527.         exrefresh();
  528.     }
  529. }
  530.  
  531.  
  532. void cmd_cd(frommark, tomark, cmd, bang, extra)
  533.     MARK    frommark, tomark;
  534.     CMD    cmd;
  535.     int    bang;
  536.     char    *extra;
  537. {
  538.     char    *getenv();
  539.  
  540.     /* default directory name is $HOME */
  541.     if (!*extra)
  542.     {
  543.         extra = getenv("HOME");
  544.         if (!extra)
  545.         {
  546.             msg("environment variable $HOME not set");
  547.             return;
  548.         }
  549.     }
  550.  
  551.     /* go to the directory */
  552.     if (chdir(extra) < 0)
  553.     {
  554.         perror(extra);
  555.     }
  556. }
  557.  
  558.  
  559. void cmd_map(frommark, tomark, cmd, bang, extra)
  560.     MARK    frommark, tomark;
  561.     CMD    cmd;
  562.     int    bang;
  563.     char    *extra;
  564. {
  565.     char    *mapto;
  566.  
  567.     /* "map" with no extra will dump the map table contents */
  568.     if (!*extra)
  569.     {
  570.         dumpkey();
  571.     }
  572.     else
  573.     {
  574.         /* "extra" is key to map, followed my what it maps to */
  575.         for (mapto = extra; *mapto && *mapto != ' ' && *mapto!= '\t'; mapto++)
  576.         {
  577.         }
  578.         while (*mapto == ' ' || *mapto == '\t')
  579.         {
  580.             *mapto++ = '\0';
  581.         }
  582.  
  583.         mapkey(extra, mapto, bang ? WHEN_VICMD|WHEN_VIINP|WHEN_EX : WHEN_VICMD);
  584.     }
  585. }
  586.  
  587.  
  588. void cmd_set(frommark, tomark, cmd, bang, extra)
  589.     MARK    frommark, tomark;
  590.     CMD    cmd;
  591.     int    bang;
  592.     char    *extra;
  593. {
  594.     if (!*extra)
  595.     {
  596.         dumpopts(FALSE);/* "FALSE" means "don't dump all" - only set */
  597.     }
  598.     else if (!strcmp(extra, "all"))
  599.     {
  600.         dumpopts(TRUE);    /* "TRUE" means "dump all" - even unset vars */
  601.     }
  602.     else
  603.     {
  604.         setopts(extra);
  605.     }
  606. }
  607.  
  608.  
  609. void cmd_tag(frommark, tomark, cmd, bang, extra)
  610.     MARK    frommark, tomark;
  611.     CMD    cmd;
  612.     int    bang;
  613.     char    *extra;
  614. {
  615.     char    *scan;    /* used to scan through the tmpblk.c */
  616.     char    *cmp;    /* char of tag name we're comparing, or NULL */
  617.     char    *end;    /* marks the end of chars in tmpblk.c */
  618.     int    fd;    /* file descriptor used to read the file */
  619.     char    wasmagic; /* preserves the original state of o_magic */
  620.  
  621.     /* open the tags file */
  622.     fd = open(TAGS, O_RDONLY);
  623.     if (fd < 0)
  624.     {
  625.         msg("No tags file");
  626.         return;
  627.     }
  628.  
  629.     /* Hmmm... this would have been a lot easier with <stdio.h> */
  630.  
  631.     /* find the line with our tag in it */
  632.     for(scan = end = tmpblk.c, cmp = extra; ; scan++)
  633.     {
  634.         /* read a block, if necessary */
  635.         if (scan >= end)
  636.         {
  637.             end = tmpblk.c + read(fd, tmpblk.c, BLKSIZE);
  638.             scan = tmpblk.c;
  639.             if (scan >= end)
  640.             {
  641.                 msg("tag \"%s\" not found", extra);
  642.                 close(fd);
  643.                 return;
  644.             }
  645.         }
  646.  
  647.         /* if we're comparing, compare... */
  648.         if (cmp)
  649.         {
  650.             /* matched??? wow! */
  651.             if (!*cmp && *scan == '\t')
  652.             {
  653.                 break;
  654.             }
  655.             if (*cmp++ != *scan)
  656.             {
  657.                 /* failed! skip to newline */
  658.                 cmp = (char *)0;
  659.             }
  660.         }
  661.  
  662.         /* if we're skipping to newline, do it fast! */
  663.         if (!cmp)
  664.         {
  665.             while (scan < end && *scan != '\n')
  666.             {
  667.                 scan++;
  668.             }
  669.             if (scan < end)
  670.             {
  671.                 cmp = extra;
  672.             }
  673.         }
  674.     }
  675.  
  676.     /* found it! get the rest of the line into memory */
  677.     for (cmp = tmpblk.c, scan++; scan < end && *scan != '\n'; )
  678.     {
  679.         *cmp++ = *scan++;
  680.     }
  681.     if (scan == end)
  682.     {
  683.         read(fd, cmp, BLKSIZE - (cmp - tmpblk.c));
  684.     }
  685.  
  686.     /* we can close the tags file now */
  687.     close(fd);
  688.  
  689.     /* extract the filename from the line, and edit the file */
  690.     for (cmp = tmpblk.c; *cmp != '\t'; cmp++)
  691.     {
  692.     }
  693.     *cmp++ = '\0';
  694.     if (strcmp(origname, tmpblk.c) != 0)
  695.     {
  696.         if (!tmpabort(bang))
  697.         {
  698.             addstr("Use tag! to abort changes, or w to save changes\n");
  699.             return;
  700.         }
  701.         tmpstart(tmpblk.c);
  702.     }
  703.  
  704.     /* move to the desired line (or to line 1 if that fails) */
  705.     wasmagic = *o_magic;
  706.     *o_magic = FALSE;
  707.     linespec(cmp, &cursor);
  708.     if (cursor == MARK_UNSET)
  709.     {
  710.         cursor = MARK_FIRST;
  711.     }
  712.     *o_magic = wasmagic;
  713. }
  714.  
  715.  
  716. void cmd_visual(frommark, tomark, cmd, bang, extra)
  717.     MARK    frommark, tomark;
  718.     CMD    cmd;
  719.     int    bang;
  720.     char    *extra;
  721. {
  722.     mode = MODE_VI;
  723. }
  724.  
  725. void cmd_quit(frommark, tomark, cmd, bang, extra)
  726.     MARK    frommark, tomark;
  727.     CMD    cmd;
  728.     int    bang;
  729.     char    *extra;
  730. {
  731.     if (tmpabort(bang))
  732.     {
  733.         mode = MODE_QUIT;
  734.     }
  735.     else
  736.     {
  737.         addstr("Use q! to abort changes, or wq to save changes\n");
  738.     }
  739. }
  740.  
  741.  
  742. void cmd_rewind(frommark, tomark, cmd, bang, extra)
  743.     MARK    frommark, tomark;
  744.     CMD    cmd;
  745.     int    bang;
  746.     char    *extra;
  747. {
  748.     /* switch to the first file */
  749.     if (tmpabort(bang))
  750.     {
  751.         argno = -1;
  752.         cmd_next(frommark, tomark, CMD_NEXT, bang, extra);
  753.     }
  754.     else
  755.     {
  756.         addstr("Use rewind! to abort changes, or w to save changes\n");
  757.     }
  758. }
  759.  
  760.  
  761.  
  762. /* describe this version of the program */
  763. void cmd_version(frommark, tomark, cmd, bang, extra)
  764.     MARK    frommark;
  765.     MARK    tomark;
  766.     CMD    cmd;
  767.     int    bang;
  768.     char    *extra;
  769. {
  770. #ifndef DATE
  771.     addstr(VERSION);
  772.     addch('\n');
  773. #else
  774.     wprintw(stdscr, "%s  (%s)\n", VERSION, DATE);
  775. #endif
  776. #ifdef COPYING
  777.     addch('\n');
  778.     addstr(COPYING);
  779.     addch('\n');
  780. #endif
  781. }
  782.  
  783.  
  784. /* make a .exrc file which describes the current configuration */
  785. void cmd_mkexrc(frommark, tomark, cmd, bang, extra)
  786.     MARK    frommark;
  787.     MARK    tomark;
  788.     CMD    cmd;
  789.     int    bang;
  790.     char    *extra;
  791. {
  792.     int    fd;
  793.  
  794.     /* create the .exrc file */
  795.     fd = creat(EXRC, 0666);
  796.     if (fd < 0)
  797.     {
  798.         addstr("Couldn't create .exrc file\n");
  799.         return;
  800.     }
  801.  
  802.     /* save stuff */
  803.     savekeys(fd);
  804.     saveopts(fd);
  805.  
  806.     /* close the file */
  807.     close(fd);
  808.     addstr("Created new .exrc file\n");
  809. }
  810.