home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume6 / reminders / rs.c < prev   
C/C++ Source or Header  |  1986-11-30  |  14KB  |  582 lines

  1. static char rcsid[] = "$Header: rs.c,v 3.3 86/07/03 14:24:34 don Exp $";
  2.  
  3. /* $Log:    rs.c,v $
  4.  * Revision 3.3  86/07/03  14:24:34  don
  5.  * 1.  MAX_LINE (# columns on a line) now defined by termcap entry for TERM.
  6.  * 2.  Misc. Optimizations.
  7.  * 3.  Reminders can now be "marked", by appending ^G to reminder, to have
  8.  *     reminder highlighted during display.  "Highlight" options can be defined
  9.  *     in the RSINIT environment variable.
  10.  *     U - Underscore,  B - Bold,  S - Asterisk. (Default is standout)
  11.  *     I - Ignore termcap entry.
  12.  * 
  13.  * Revision 3.2  85/08/26  14:55:42  don
  14.  * Adding Mike's enhancements.  Thanks Mike! :-)
  15.  * Revision 3.2 & 3.3 by Mike Spitzer @ (pur-ee!mjs)
  16.  * 
  17.  * Revision 3.2  85/08/05  13:10:52  mjs
  18.  * -added new print_line which doesn't barf on long words
  19.  * -added #define for place to break up lines(MAX_LINE)
  20.  * -print_line is always called now, test for strlen(line) < MAX_LINE
  21.  *  is now made there.
  22.  * 
  23.  *     MIke Spitzer
  24.  *     pur-ee!mjs
  25.  * 
  26.  * Revision 3.1  85/07/26  20:48:06  mjs
  27.  * "rs" now recognizes the $EDITOR variable.  "vi" will be used if 
  28.  * $EDITOR is undefined.
  29.  * 
  30.  * added "-e" flag... does the same thing as "-v"
  31.  * 
  32.  * -mjs
  33.  * 
  34.  * Revision 2.2  85/02/25  10:35:48  don
  35.  * 1.  Optimized kill and line wrap routines.
  36.  * 2.  Added defines for LPR & VI.
  37.  * 3.  Added more RSINIT options. (A & D)
  38.  * 4.  Deleted add_calendar routine, now uses add_reminders.
  39.  * 5.  Added comments.
  40.  * 
  41.  * Revision 2.1  85/01/28  17:03:56  don
  42.  * 1. Added new notes file - .rsnotes | command rs -n
  43.  * 2. Added new alternate file - user defined via setenv RSALT | command rs -A
  44.  * 3. Added environment variable RSINIT.
  45.  *    setenv RSINIT 'ad' | a = display after add | d = display after delete.
  46.  * 4. Lines may now be 256 char. long.
  47.  * 5. Long lines will automatically wrap like 'vi'.
  48.  * 6. Added search command. | rs -s 'search string'
  49.  * 7. Help deleted, replaced with 'usage' message.
  50.  * 8. Misc. optimizations.
  51.  * 
  52.  * Revision 1.3  85/01/15  09:17:57  don
  53.  * 1. Added $Log line for RCS.
  54.  * 2. Fixed help message.
  55.  * 3. Coded in range deletion.
  56.  *  */
  57.  
  58. /*    Program    written by:    Don Joslyn
  59.  *                Nova University Computer Center
  60.  *                3301 College Avenue
  61.  *                Fort Lauderdale, Florida 33314
  62.  *                (305) 475-7630 (novavax!don)
  63.  *
  64.  *    Notice:  No Copyright. 
  65.  *
  66. */
  67.  
  68. #include    <stdio.h>
  69. #include    <ctype.h>
  70. #ifdef    BSD
  71. #include    <strings.h>
  72. #else
  73. #include    <string.h>
  74. #define        rindex    strnchr
  75. #endif    BSD
  76.  
  77. #define        MAXLEN   256    /* Max. Length of a single line     */
  78. #define        MAXLINES 500    /* Max. number of lines (reminders) */
  79.  
  80. #define        CALENDAR "/calendar"    /* calendar file */
  81. #define        RSFILE     "/.reminders"    /* reminder file */
  82. #define        RSNOTES  "/.rsnotes"    /* notes    file */
  83.  
  84. #define        LPR    "/usr/ucb/lpr"    /* location of lpr */
  85. #define        EDITOR    "/usr/ucb/vi"     /* default editor  */
  86.  
  87. /*#define        BIGHELP    /* Define if you want verbose help message */
  88.  
  89. FILE    *fp,
  90.     *fptmp;
  91.  
  92. char    fname[128],        /* Filename tmp */
  93.     on[32],            /* string used to turn "mark" on  */
  94.     off[32],        /* string used to turn "mark" off */
  95.     buff[1024],        /* Holds termcap entry for TERM */
  96.     s[MAXLEN],        /* Tmp string and line storage */
  97.     sstr[80],        /* Search string */
  98.     cmd[256];        /* cmd for system call */
  99.  
  100. char    *a,
  101.     *editor,        /* Hold for EDITOR environment variable */
  102.     *entity = "Reminders",    /* Entity working on */
  103.     *env,            /* Hold for RSINIT environment variable */
  104.     *fun,            /* Used in arg processing */
  105.     *mark_on  = "so",    /* Default mark is Standout mode */
  106.     *mark_off = "se";    /* Standout end */
  107.     
  108.  
  109. char    *getenv(),
  110.     *malloc(),
  111.     *mktemp();
  112.  
  113. char    rstmp[]= "/tmp/rsXXXXXX";    /* name of temp. file during delete */
  114.  
  115. int    adisplay = 0,    /* display reminders after additions (default = no) */
  116.     ddisplay = 0,    /* display reminders after deletions (default = no) */
  117.     Adisplay = 0,    /* display notes/alt after additions (default = no) */
  118.     Ddisplay = 0,    /* display notes/alt after deletions (default = no) */
  119.     columns = 80,    /* Number of columns in a line. */
  120.     len      = 0,    /* Length of line */
  121.     mark     = 0,    /* Mark the line (High Priority) */
  122.     tcap     = 1,    /* Read Termcap stuff. */
  123.     tcapok   = 0,    /* TERM found in Termcap file. */
  124.     rem_work = 1,    /* working on reminder file by default */
  125.     search   = 0,    /* search option seen on command line */
  126.     status;        /* Hold status returned by sys calls and such */
  127.  
  128. main(argc, argv)
  129. int    argc;
  130. char    *argv[];
  131.  
  132. /* Get RSINIT environment variable to find options desired */
  133.  
  134. env = getenv("RSINIT");
  135.  
  136. while (*env) {
  137.     switch(*env++) {
  138.         case 'a' : adisplay++; break;
  139.         case 'd' : ddisplay++; break;
  140.         case 'A' : Adisplay++; break;
  141.         case 'D' : Ddisplay++; break;
  142.         case 'I' : tcap = 0;   break;
  143.         case 'U' :
  144.             mark_on  = "us";
  145.             mark_off = "ue";
  146.             break;
  147.         case 'B' :
  148.             mark_on  = "bo";
  149.             mark_off = "be";
  150.             break;
  151.         case 'S' :
  152.             mark_on  = "ss";
  153.             mark_off = "ss";
  154.             break;
  155.     }
  156. }
  157.  
  158.  
  159. /* Get users HOME directory and construct default name for reminder file */
  160.  
  161. sprintf(fname, "%s%s", getenv("HOME"), RSFILE);
  162.  
  163. /* Find out what the user wants to do */
  164.  
  165. while ( --argc > 0 && (*++argv)[0] == '-')
  166.     for (fun = argv[0]+1; *fun != '\0'; fun++)
  167.         switch(*fun) {
  168.         case 'A' :    /* Work on Alternate reminder file */
  169.             env = getenv("RSALT");
  170.             if (!env)
  171.                 env = "phone_numbers";
  172.  
  173.             sprintf(fname, "%s/.%s", getenv("HOME"), env);
  174.             entity = env;
  175.             if (islower(entity[0]))
  176.                 entity[0] = toupper(entity[0]);
  177.             rem_work = 0;
  178.             break;
  179.  
  180.         case 'a' :    /* Add reminder(s)/note(s)/alternate(s) */
  181.             add_reminder();
  182.             exit(0);
  183.  
  184.         case 'c' :    /* Add entries to calendar file */
  185.             sprintf(fname, "%s%s", getenv("HOME"), CALENDAR);
  186.             entity = "Calendar commands";
  187.             rem_work = 0;
  188.             add_reminder();
  189.             exit(0);
  190.  
  191.         case 'd' :    /* Delete reminder(s)/note(s)/alternate(s) */
  192.             delete_reminder(argc, argv);
  193.             exit(0);
  194.  
  195.         case 'k' :    /* Kill all reminders/notes/alternates */
  196.             if ( unlink(fname) == 0) {
  197.                 printf("%s killed.\n", entity);
  198.             }
  199.             exit(0);
  200.  
  201.         case 'n' :    /* Work on notes file */
  202.             sprintf(fname, "%s%s", getenv("HOME"), RSNOTES);
  203.             entity = "Notes";
  204.             rem_work = 0;
  205.             break;
  206.  
  207.         case 'p' :    /* print reminders/notes/alternates */
  208.             sprintf(cmd, "%s %s", LPR, fname);
  209.             status = system(cmd);
  210.  
  211.             if (status == 0) {
  212.                 printf("%s will be printed.\n", entity);
  213.                 exit(0);
  214.             }
  215.             else {
  216.                 printf("%s can't be printed, sorry\n", entity);
  217.                 exit(1);
  218.             }
  219.  
  220.         case 's' :    /* search for string in reminders/notes/alts */
  221.             argc--;
  222.             argv++;
  223.             sprintf(sstr, "%s", argv[0]);
  224.             search++;
  225.             break;
  226.         case 'e' : /* -e and -v are equivilent */
  227.         case 'v' : /* Edit reminders/notes/alternates with editor */
  228.             editor = getenv("EDITOR");
  229.             if (!editor)
  230.                 editor = EDITOR;
  231.             sprintf(cmd, "%s %s",editor,fname);
  232.             system(cmd);
  233.             exit(0);
  234.         default:    /* Give em some help */
  235. #ifndef    BIGHELP
  236.             printf("Usage: rs [ -Aaceknpv ] [ -s search_string ] [ -d # ] [ -d #-# ]\n");
  237.             printf("For additional information type:  man rs\n");
  238. #else
  239.             /* You can enable this stuff if you want! */
  240.             printf("Reminder Service commands:\n\n");
  241.             printf("-A\tWork on Alternate reminder file.\n");
  242.             printf("-a\tAdd reminder(s)/note(s)/Alt(s).\n");
  243.             printf("-c\tAdd line(s) to the calendar file.\n");
  244.             printf("-d\tDelete reminder(s)/note(s)/Alt(s).\n");
  245.             printf("-k\tKill all reminders/notes/Alternate.\n");
  246.             printf("-n\tWork on notes.\n");
  247.             printf("-p\tPrint reminders/notes/Alternates.\n");
  248.             printf("-s\tSearch for string.\n");
  249.             printf("-e\tEdit reminders/notes/Alt.\n\n");
  250.             printf("rs with no option will display reminders.\n");
  251.             printf("SEE ALSO rs(1)\n");
  252. #endif    BIGHELP
  253.             exit(0);
  254.         }
  255.  
  256. print_reminders();
  257.  
  258. }
  259.  
  260.  
  261. /* ADD REMINDERS */
  262. /* This routine uses cat to add lines to the reminder/note/alternate file */
  263. /* If you don't like it, add your own getline routine! */
  264.  
  265. add_reminder()
  266. {
  267.     printf("Enter %s then ^d to exit:\n", entity);
  268.  
  269.     sprintf(cmd, "%s %s","/bin/cat >>",fname);
  270.     system(cmd);
  271.     if ( (adisplay && rem_work) || (Adisplay && !rem_work) )
  272.         print_reminders();
  273. }
  274.  
  275.  
  276. /* DELETE REMINDERS/NOTES/ALTERNATES */
  277.  
  278. delete_reminder(argc, argv)
  279.     int    argc;
  280.     char    *argv[];
  281. {
  282.     int    begin,
  283.         end,
  284.         delete_line[MAXLINES];
  285.  
  286.     char    a[4], b[4];
  287.  
  288.     register int    i        = 0,
  289.             j        = 0,
  290.             deleted     = 0,
  291.             line_number = 0,
  292.             printed     = 0;
  293.  
  294.     argc--, argv++;
  295.     for (;argc > 0; argc--, argv++) {
  296.         if (alldigits(*argv)) {
  297.             delete_line[atoi(*argv)] = 1;
  298.         }
  299.         else {
  300.             i = rindex(*argv, '-');
  301.             sscanf(i+1, "%s", b );
  302.             j = ( strlen(*argv) - strlen(b) ) - 1;
  303.             strncpy(a, *argv, j);
  304.             a[j]='\0';
  305.             begin = atoi(a);
  306.             end   = atoi(b);
  307.  
  308.             if (begin < end) {
  309.                 for (j = begin ; j < end+1 ; j++)
  310.                     delete_line[j] = 1;
  311.             }
  312.             else {
  313.                 printf("Illegal range specified.\n");
  314.                 exit(1);
  315.             }
  316.         }
  317.     }
  318.  
  319.     mktemp(rstmp);
  320.     if ((fptmp = fopen(rstmp,"w")) == NULL) {
  321.         print_open_error_exit(rstmp);
  322.     }
  323.  
  324.     if ((fp = fopen(fname,"r")) == NULL) {
  325.         print_open_error_exit(fname);
  326.     }
  327.  
  328.     while (getline(s, MAXLEN) > 0) {
  329.         if (delete_line[++line_number] != 1) {
  330.             fprintf(fptmp,"%s",s);
  331.             printed++;
  332.         }
  333.         else {
  334.             deleted++;
  335.         }
  336.     }
  337.  
  338.     fclose(fp);
  339.     fclose(fptmp);
  340.  
  341.     status = unlink(fname);
  342.     if (status != 0) {
  343.         printf("Can't remove file - %s", fname);
  344.         exit(1);
  345.     }
  346.  
  347.     if (printed) {
  348.         if ((fp = fopen(fname,"w")) == NULL) {
  349.             print_open_error_exit(fname);
  350.         }
  351.  
  352.         if ((fptmp = fopen(rstmp,"r")) == NULL) {
  353.             print_open_error_exit(rstmp);
  354.         }
  355.  
  356.         while (fgets(s, MAXLEN, fptmp) != NULL) {
  357.             fputs(s, fp);
  358.         }
  359.     }
  360.  
  361.     fclose(fp);
  362.     fclose(fptmp);
  363.     status = unlink(rstmp);
  364.  
  365.     if (deleted)
  366.         printf("%d %s deleted.\n", deleted, entity );
  367.  
  368.     if ( (ddisplay && rem_work) || (Ddisplay && !rem_work) )
  369.         print_reminders();
  370. }
  371.  
  372.  
  373. /* PRINT REMINDERS/NOTES/ALTERNATES */
  374. /* This routine will print reminders/notes/alternates */
  375. /* print_line is called to do the printing with */
  376. /* auto wrap.  If a search argument was given, only lines that contain the */
  377. /* search string will be printed. */
  378.  
  379. print_reminders()
  380. {
  381.     register int line_number = 0;
  382.  
  383.     if ((fp = fopen(fname,"r")) == NULL) {
  384.         exit(0);
  385.     }
  386.  
  387.     if (tcap) {
  388.         if (tgetent(buff, getenv("TERM")) == 1) {
  389.             tcapok++;
  390.             columns = tgetnum("co");
  391.             if (columns <= 0)
  392.                 columns = 80;
  393.             columns -= 6;
  394.             a = on;
  395.             tgetstr(mark_on,  &a);
  396.             a = off;
  397.             tgetstr(mark_off, &a);
  398.             if (!strlen(on)) {
  399.                 if (tgetflag("bs"))
  400.                     strcpy(on, "\010*");
  401.                 else {
  402.                     a = on;
  403.                     tgetstr("bc", &a);
  404.                 }
  405.             }
  406.         }
  407.     }
  408.         
  409.     printf("\n%s:\n", entity);
  410.  
  411.     while ((len = getline(s, MAXLEN)) > 0) {
  412.         if (search) {
  413.             if (instr(s, sstr) != -1) {
  414.                 printf("%3d. ", ++line_number);
  415.                 if (tcapok)
  416.                     find_mark();
  417.                 if (mark)
  418.                     printf("%s", on);
  419.                 print_line(s, columns);
  420.                 if (mark) {
  421.                     printf("%s", off);
  422.                     mark = 0;
  423.                 }
  424.             }
  425.             else
  426.                 line_number++;
  427.         }
  428.         else {
  429.             printf("%3d. ", ++line_number);
  430.             if (tcapok)
  431.                 find_mark();
  432.             if (mark)
  433.                 printf("%s", on);
  434.             print_line(s, columns);
  435.             if (mark) {
  436.                 printf("%s", off);
  437.                 mark = 0;
  438.             }
  439.         }
  440.     }
  441.  
  442.     printf("\n");
  443.  
  444.     fclose(fp);
  445. }
  446.  
  447. getline(s, lim)
  448. char s[];
  449. int  lim;
  450. {
  451.     register int i = 0;
  452.     register int c;
  453.  
  454.     while (--lim > 0 && (c=getc(fp)) != EOF && c != '\n')
  455.         s[i++] = c;
  456.  
  457.     if (c == '\n')
  458.         s[i++] = c;
  459.  
  460.     s[i] = '\0';
  461.  
  462.     return(i);
  463. }
  464.  
  465. alldigits(s)
  466. register char *s;
  467. {
  468.     register c = *s++;
  469.  
  470.     do {
  471.     if (!isdigit(c))
  472.         return(0);
  473.     }
  474.     while (c = *s++);
  475.  
  476.     return(1);
  477. }
  478.  
  479. instr(s, t)
  480. char s[], t[];
  481. {
  482.     register int i, j, k;
  483.  
  484.     for (i = 0; s[i] != '\0' ; i++) {
  485.         for (j=i, k=0 ; t[k] != '\0' && s[j]==t[k] ; j++ , k++)
  486.             ;
  487.         if (t[k] == '\0')
  488.             return(i);
  489.     }
  490.     return(-1);
  491. }
  492.  
  493. print_open_error_exit(file_name)
  494. char    file_name[];
  495. {
  496.     printf("Can't open file - %s\n",file_name);
  497.     exit(1);
  498. }
  499.  
  500. /* This routine will wrap lines greater than 75 characters long.      */
  501. /* An attempt is made to break the line up after a word.  If a "word" */
  502. /* is greater than 75 characters, the word will be split.             */ 
  503. /*     pur-ee!mjs                              */
  504.  
  505. #define SPACE    ' '
  506. int print_line (line, maxlen)
  507. char    line[];            /* string to be printed */
  508. unsigned int    maxlen;        /* longest line permitted for output */
  509. {
  510.     register int    index,    /* used in for loops */
  511.                     breaking_pt,/* index in line[] at point to break line 
  512.                 */
  513.                     nospace = 0,/* set to TRUE if no space is found */
  514.                     last_br_pt = 0,/* last breaking point */
  515.                     line_len,    /* number of characters in line[] */
  516.                     done = 0;    /* set to TRUE if finished */
  517.  
  518.  /* if line[] isn't longer than the longest line permitted, we can just
  519.     print it, and return. */
  520.  
  521.     line_len = strlen (line);
  522.  
  523.     if (strlen (line) <= maxlen) {
  524.     printf ("%s", line);
  525.     return;
  526.     }
  527.  
  528.     do {
  529.     /* set breaking_pt at point in line[] where we should break the line.
  530.        Do this by start looking backwards from maxlen until a space is
  531.        found. */
  532.  
  533.     for (index = (maxlen + last_br_pt); line[index] != SPACE; --index) {
  534.         if (index == last_br_pt) {
  535.         nospace = 1;
  536.         break;
  537.         }
  538.         if (index >= line_len) {
  539.         index = line_len - 1;   /* 1 gets added to it below */
  540.         done = 1;
  541.         break;
  542.         }
  543.     }
  544.     breaking_pt = index + 1;
  545.  
  546.     /* if there is no space found, set breaking point to MAXLEN */
  547.  
  548.     if (nospace == 1) {
  549.         breaking_pt = maxlen + last_br_pt;
  550.         nospace = 0;    /* reset flag */
  551.     }
  552.     /* print line[] up to breaking point */
  553.  
  554.     for (index = last_br_pt; index < breaking_pt; ++index) 
  555.         putchar (line[index]);
  556.  
  557.  
  558.         if (last_br_pt == 0) /* this is our first time through */
  559.             maxlen -= 5; /* for indenting */
  560.         if (!done) {
  561.         if (mark)
  562.             printf("%s", off);
  563.  
  564.             printf("\n     "); /* indent */
  565.  
  566.         if (mark)
  567.             printf("%s", on);
  568.     }
  569.  
  570.     last_br_pt = breaking_pt;
  571.     } while (!done);
  572. }
  573. find_mark()
  574. {
  575.     if (s[len-2] == '\07') {
  576.         mark = 1;
  577.         s[len-2] = '\n';
  578.         s[len-1] = '\0';
  579.     }
  580. }
  581.