home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume26 / maint / part05 / misc.c
C/C++ Source or Header  |  1992-05-13  |  62KB  |  2,433 lines

  1. /******************************************************************************
  2. *******************************************************************************
  3.  
  4.    Site:    Western Michigan University Academic Computer Center
  5.  
  6.    System:    Directory/File System Maintenance
  7.   
  8.    Program:    maint
  9.  
  10.    Version=01    Level=00    01/24/92    Leonard J. Peirce
  11.  
  12.    Purpose:    Miscellaneous routines for MAINT.
  13.  
  14.    Arguments:    See individual routines.
  15.  
  16.    External variables:  curr_year
  17.             spec_win
  18.             stat_win
  19.             main_win
  20.             args
  21.  
  22.    External functions:
  23.  
  24.     Defined:  add_filetype, banystr, cat, check_marks, cont_after_stop,
  25.           follow_link, get_bnum, get_dir, get_dir_mem, get_filemarks,
  26.           get_num_file, make_ent, make_screen, mystrcpy, mystrmcpy,
  27.           padcpy, prot_str_to_val, prot_val_to_str, rename, set_args,
  28.           set_date, set_nodes, set_screen, set_width, spawn,
  29.           squeeze_str, strindex, strtcpy
  30.  
  31.     Called:   date_qsort, make_slot, name_qsort, put_pool, put_slot,
  32.           size_qsort, sort_files
  33.  
  34.    Files accessed:    See individual routines.
  35.  
  36.    Return codes:    See individual routines.
  37.  
  38.    Compiling instructions:    See Makefile.
  39.  
  40.    Linking instructions:    See Makefile.
  41.  
  42.    Other information:    (C) Copyright 1992, Leonard J. Peirce
  43.  
  44. ********************************************************************************
  45. *******************************************************************************/
  46.  
  47. /******************************************************************************/
  48. /*                                                                            */
  49. /*                        # I N C L U D E   F I L E S                         */
  50. /*                                                                            */
  51. /******************************************************************************/
  52.  
  53. #ifdef ultrix
  54. #include <cursesX.h>
  55. #else
  56. #include <curses.h>
  57. #endif
  58. #include <sys/param.h>
  59. #include <malloc.h>
  60. #include <time.h>
  61. #include <string.h>
  62. #if !defined(SYSV) || defined(sun)
  63. #include <sys/wait.h>
  64. #endif
  65. #include <errno.h>
  66. #include <ctype.h>
  67. #include <varargs.h>
  68. #include "maint.h"
  69. #include <sys/stat.h>
  70.  
  71. /******************************************************************************/
  72. /*                                                                            */
  73. /*                             # D E F I N E S                                */
  74. /*                                                                            */
  75. /******************************************************************************/
  76.  
  77. /******************************************************************************/
  78. /*                                                                            */
  79. /*          S T R U C T U R E S ,   U N I O N S ,   T Y P E D E F S           */
  80. /*                                                                            */
  81. /******************************************************************************/
  82.  
  83. /******************************************************************************/
  84. /*                                                                            */
  85. /*   E X T E R N A L   D E F I N I T I O N S   &   D E C L A R A T I O N S    */
  86. /*                                                                            */
  87. /******************************************************************************/
  88.  
  89. extern     int      curr_year;
  90.  
  91. extern     ENT_DEF  *baseptr;
  92.  
  93. extern     WINDOW      *spec_win,
  94.           *main_win,
  95.           *stat_win;
  96.  
  97. extern     ARG_DEF  args;
  98.  
  99. extern     char      *getenv();
  100.  
  101. extern     int      execve(),
  102.           vfork(),
  103.           put_slot(),
  104.           make_slot();
  105.  
  106. extern     u_short  cont_flag;
  107.  
  108. extern     void      put_pool(),
  109.           date_qsort(),
  110.           size_qsort(),
  111.           name_qsort(),
  112.           sort_files();
  113.  
  114.      char      *mystrcpy(),
  115.           *mystrmcpy(),
  116.           *prot_val_to_str(),
  117.           *padcpy(),
  118.           *set_date(),
  119.           *cat();
  120.  
  121. #if !defined(SYSV) || defined(sun)
  122.      long      get_bnum();
  123. #endif
  124.  
  125.      int      check_marks(),
  126.           strtcpy(),
  127.           follow_link(),
  128.           make_ent(),
  129.  
  130. #if defined(SYSV) && !defined(sun)
  131.           rename(),
  132. #endif
  133.  
  134.           strindex();
  135.  
  136.      u_short  add_filetype();
  137.  
  138.      short      banystr(),
  139.           get_num_file(),
  140.           prot_str_to_val();
  141.  
  142.      u_char      filetype_char();
  143.  
  144.      void      set_screen(),
  145.           set_width(),
  146.           set_args(),
  147.           set_nodes(),
  148.           get_dir_mem(),
  149.           get_dir(),
  150.           message(),
  151.           squeeze_str(),
  152.           make_screen(),
  153.           cont_after_stop(),
  154.           get_filemarks();
  155.  
  156. /******************************************************************************/
  157. /*                                                                            */
  158. /*     S T A T I C   D E F I N I T I O N S   &   D E C L A R A T I O N S      */
  159. /*                                                                            */
  160. /******************************************************************************/
  161.  
  162. static     char      *get_name();
  163.  
  164. static     u_short  check_nlen();
  165.  
  166. static     u_char      set_type();
  167.  
  168. /*******************************************************************************
  169. ********************************************************************************
  170.  
  171.   Function:    set_screen
  172.  
  173.   Purpose:    Compute values for parameters that relate to the screen,
  174.         including number of columns, number of files, and the number
  175.         of screens needed for the directory.
  176.  
  177.   Global variables:
  178.  
  179.     Name            Examine/Modify/Use/Read/Write
  180.     ----            -----------------------------
  181.     COLS                    X
  182.  
  183.   Return Codes:
  184.  
  185.     Code            Reason
  186.     ----            ------
  187.     none
  188.  
  189. ********************************************************************************
  190. *******************************************************************************/
  191.  
  192. void set_screen(num_screen,scr_file,num_file,slot_width,node_row_max,num_col)
  193.                     /*******   FORMAL  PARAMETERS   *******/
  194.      short      *num_screen,        /* number of screens in directory     */
  195.           *scr_file,        /* number of file slots per screen    */
  196.            num_file,        /* number of files in directory          */
  197.           slot_width;        /* width of file slot              */
  198.      u_short  node_row_max;        /* max. # of rows in node array          */
  199.      short      *num_col;        /* number of columns for full screen  */
  200.  
  201. {    /*** set_screen ***/
  202.  
  203.  
  204.    /* compute the number of files per row of the screen */
  205.  
  206.    *num_col = (short) COLS/(slot_width + SLOT_GAP + 1);
  207.  
  208.    if(*num_col == 0)
  209.       *num_col = 1;            /* must have at least one column      */
  210.  
  211.    /* now compute how many file slots will fit on a screen */
  212.  
  213.    *scr_file = *num_col * (short) node_row_max;
  214.  
  215.    /* compute how many screens will be needed for this directory */
  216.  
  217.    *num_screen = num_file/(*scr_file);
  218.  
  219.    if((num_file % (*scr_file)) != 0)
  220.       *num_screen += 1;
  221.  
  222.    return;
  223.              
  224. }    /*** set_screen ***/
  225.  
  226. /*******************************************************************************
  227. ********************************************************************************
  228.  
  229.   Function:    set_nodes
  230.  
  231.   Purpose:    Initialize the screen slot node pointers for the current
  232.         directory.
  233.  
  234.   Global variables:
  235.  
  236.     Name            Examine/Modify/Use/Read/Write
  237.     ----            -----------------------------
  238.     none
  239.  
  240.   Return Codes:
  241.  
  242.     Code            Reason
  243.     ----            ------
  244.     none
  245.  
  246. ********************************************************************************
  247. *******************************************************************************/
  248.  
  249. void set_nodes(nodes,node_row_max,scr_file,num_screen,curr_screen,num_file,
  250.            slot_width,num_col)
  251.                     /*******   FORMAL  PARAMETERS   *******/
  252. register NODE_DEF nodes[][MAX_NODE_COL+1]; /* screen node matrix          */
  253.      u_short  node_row_max;        /* max. # of rows in node array          */
  254.      short      *scr_file,        /* number of files on current screen  */
  255.            num_screen,        /* number of screens for directory    */
  256.           curr_screen,        /* current screen              */
  257.           num_file,        /* number of files in directory          */
  258.           slot_width,        /* number of characters for file slot */
  259.           num_col;        /* number of columns per screen          */
  260.  
  261. {    /*** set_nodes ***/
  262.                     /********   LOCAL  VARIABLES   ********/
  263. register NODE_DEF *tptr;        /* temporary node pointer          */
  264. register int      i,            /* loop and array index              */
  265.                j;            /* ditto....                  */
  266. static     short      left_val,        /* left pointer for node          */
  267.           up_val,        /* up pointer for node              */
  268.           column_val,        /* current column value              */
  269.           num_row,        /* number of rows for this screen     */
  270.           full_row,        /* number of full rows for screen     */
  271.           full_col;        /* number of full columns          */
  272.  
  273.  
  274.    if(curr_screen == num_screen)    /* if this is the last page          */
  275.    {
  276.       /* recompute the number of columns; it might be different because
  277.        * this is the last page of the directory
  278.        */
  279.  
  280.       /* compute how many files will be on this screen of the directory */
  281.  
  282.       *scr_file = num_file - (num_col * node_row_max * (curr_screen - 1));
  283.  
  284.       /* now compute how many columns are needed for the last screen */
  285.  
  286.       num_col = *scr_file / node_row_max;
  287.  
  288.       if((*scr_file % node_row_max) != 0)
  289.      num_col++;
  290.    }
  291.    else
  292.    {
  293.       /* compute how many files will be on this screen of the directory */
  294.  
  295.       *scr_file = num_col * (short) node_row_max;
  296.    }
  297.  
  298.    if(*scr_file < node_row_max)        /* determine number of rows          */
  299.       num_row = *scr_file;
  300.    else
  301.       num_row = node_row_max;
  302.  
  303.    left_val = num_col - 1;        /* set left and right pointers          */
  304.    j = 0;                /* start with the first column          */
  305.    column_val = 0;            /* cursor on screen starts @ (0,0)    */
  306.    full_col = *scr_file / node_row_max; /* calculate number of full columns   */
  307.  
  308.    if(full_col == 0)            /* must have at least one full column */
  309.       full_col = 1;
  310.  
  311.    full_row = *scr_file - (full_col * num_row);
  312.  
  313.    if(full_row == 0)
  314.       full_row = *scr_file / full_col;
  315.  
  316.    /* first initialize the node matrix just like it would be a full screen;
  317.     * then we will "trim" the edges to make sure that things point to the right
  318.     * places in case the cursor would to need to wrap around the screen
  319.     */
  320.  
  321.    up_val = num_row - 1;
  322.    i = 0;
  323.  
  324.    while(i < num_row)
  325.    {
  326.       j = 0;
  327.       left_val = num_col - 1;        /* left j value                  */
  328.       column_val = 0;
  329.  
  330.       while(j < num_col)
  331.       {
  332.      tptr = &(nodes[i][j]);        /* get a pointer to the current node  */
  333.      tptr->right_col = (j + 1) % num_col;
  334.      tptr->left_col = left_val;
  335.      tptr->up_col = j;
  336.      tptr->down_col = j;
  337.  
  338.      tptr->right_row = i;
  339.      tptr->left_row = i;
  340.      tptr->up_row = up_val;
  341.      tptr->down_row = (i + 1) % num_row;
  342.  
  343.      tptr->row = i;
  344.      tptr->column = column_val;
  345.      column_val = column_val + slot_width + SLOT_GAP + 1;
  346.      left_val = (left_val + 1) % num_col;
  347.      j++;
  348.       }
  349.  
  350.       up_val = (up_val + 1) % num_row;
  351.       i++;
  352.    }
  353.  
  354.    /* now trim the edges of the matrix just in case this is the last screen
  355.     * of the directory
  356.     */
  357.  
  358.    /* first go along the top of the screen */
  359.  
  360.    i = 0;
  361.  
  362.    for(j = 0; j < num_col; j++)
  363.    {
  364.       tptr = &(nodes[i][j]);        /* get a pointer to the node          */
  365.  
  366.       if(!j)                /* are we in the top left node?          */
  367.       {
  368.      /* top left node; the values for going up from this node should
  369.       * point to bottom node in the last column on the screen
  370.       */
  371.  
  372.      tptr->up_row = full_row - 1;
  373.      tptr->up_col = num_col - 1;
  374.       }
  375.       else
  376.       {
  377.      tptr->up_col = j - 1;
  378.      tptr->up_row = num_row - 1;
  379.       }
  380.    }
  381.  
  382.    /* now go along the left of the screen */
  383.  
  384.    j = 0;
  385.  
  386.    for(i = 0; i < num_row; i++)
  387.    {
  388.       tptr = &(nodes[i][j]);
  389.  
  390.       if(!i)
  391.       {
  392.      /* we are in the top left of the screen; going left from here
  393.       * should go to the bottom, right-most node
  394.       */
  395.  
  396.      tptr->left_row = full_row - 1;
  397.      tptr->left_col = num_col - 1;
  398.       }
  399.       else
  400.       {
  401.      if(i < full_row + 1)
  402.         tptr->left_col = num_col - 1;
  403.      else
  404.         tptr->left_col = full_col - 1;
  405.  
  406.      tptr->left_row = (i - 1) % num_row;
  407.       }
  408.    }
  409.  
  410.    /* trim the bottom full columns */
  411.  
  412.    i = num_row - 1;
  413.  
  414.    for(j = 0; j < full_col; j++)
  415.    {
  416.       tptr = &(nodes[i][j]);        /* get a pointer to the node          */
  417.       tptr->down_col = j + 1;
  418.    }
  419.  
  420.    /* now go along the right side of the last full column */
  421.  
  422.    j = full_col - 1;
  423.  
  424.    for(i = full_row; i < num_row; i++)
  425.    {
  426.       tptr = &(nodes[i][j]);
  427.       tptr->right_row = (i + 1) % num_row;
  428.       tptr->right_col = 0;
  429.    }
  430.  
  431.    /* trim along the last column, whether it be full or not */
  432.  
  433.    j = num_col - 1;
  434.  
  435.    for(i = 0; i < full_row; i++)
  436.    {
  437.       tptr = &(nodes[i][j]);
  438.       tptr->right_row = (i + 1) % num_row;
  439.       tptr->right_col = 0;
  440.    }
  441.  
  442.    /* set the last node on the screen; this is a special case */
  443.  
  444.    tptr = &(nodes[full_row-1][num_col-1]);
  445.    tptr->down_row = 0;
  446.    tptr->down_col = 0;
  447.  
  448.    return;
  449.  
  450. }    /*** set_nodes ***/
  451.  
  452. /*******************************************************************************
  453. ********************************************************************************
  454.  
  455.   Function:    make_ent
  456.  
  457.   Purpose:    Gather all the information about an individual file, including
  458.         the protection string and filename that will be displayed on
  459.         the screen.  This information is stored in the directory entry.
  460.  
  461.   Global variables:
  462.  
  463.     Name            Examine/Modify/Use/Read/Write
  464.     ----            -----------------------------
  465.     none
  466.  
  467.   Return Codes:
  468.  
  469.     Code            Reason
  470.     ----            ------
  471.     SUCCESS
  472.     FAILURE
  473.  
  474. ********************************************************************************
  475. *******************************************************************************/
  476.  
  477. int make_ent(ent,filename,num_block)
  478.                     /*******   FORMAL  PARAMETERS   *******/
  479. register ENT_DEF  *ent;            /* pointer to file entry          */
  480. register char      *filename;        /* file to be looked up              */
  481.      long      *num_block;        /* number of blocks in directory      */
  482.  
  483. {    /*** make_ent ***/
  484.                     /********   LOCAL  VARIABLES   ********/
  485. static     int      status;        /* return code status holder          */
  486. static     struct      stat    statbuf;    /* file stat structure              */
  487.  
  488.  
  489. #if !defined(SYSV) || defined(sun)
  490.    status = lstat(filename,&statbuf);
  491. #else
  492.    status = stat(filename,&statbuf);
  493. #endif
  494.  
  495.    if(status != 0)
  496.       return(FAILURE);
  497.  
  498.    ent->type = set_type(statbuf.st_mode);
  499.    ent->prot = statbuf.st_mode;
  500.    ent->time = statbuf.st_mtime;
  501.    ent->size = statbuf.st_size;
  502.    ent->command = NULL;
  503.    ent->text = NULL;
  504.    ent->gid = statbuf.st_gid;
  505.    ent->uid = statbuf.st_uid;
  506.    ent->name_len = check_nlen(filename);
  507.  
  508.    /* set the filename that will be displayed on the screen */
  509.  
  510.    strcpy(ent->scr_name,get_name(filename,&(ent->disp_len),ent->prot,
  511.       ent->type));
  512.  
  513. #if defined(SYSV) && !defined(sun)
  514.    *num_block += kbytes(statbuf.st_size);
  515. #else
  516.    *num_block += statbuf.st_blocks;
  517. #endif
  518.  
  519.    return(SUCCESS);
  520.  
  521. }    /*** make_ent ***/
  522.  
  523. /*******************************************************************************
  524. ********************************************************************************
  525.  
  526.   Function:    make_screen
  527.  
  528.   Purpose:    Create the individual screen entries for the current screen
  529.         of the directory and write them to the virtual display.
  530.  
  531.         This routine will also clear out the slots on the screen where
  532.         the files should not appear.  This would happen only on the
  533.         last page of a directory.
  534.  
  535.   Global variables:
  536.  
  537.     Name            Examine/Modify/Use/Read/Write
  538.     ----            -----------------------------
  539.     none
  540.  
  541.   Return Codes:
  542.  
  543.     Code            Reason
  544.     ----            ------
  545.     none
  546.  
  547. ********************************************************************************
  548. *******************************************************************************/
  549.  
  550. void make_screen(window,nodes,dirptr,args,curr_screen,node_row_max,
  551.          node_col_max,scr_file,num_slot,slot_width,text_flag)
  552.                     /*******   FORMAL  PARAMETERS   *******/
  553.      WINDOW      *window;        /* window to write to              */
  554.      NODE_DEF nodes[][MAX_NODE_COL+1]; /* screen node matrix          */
  555.      ENT_DEF  *dirptr;        /* pointer to directory information   */
  556. register ARG_DEF  *args;        /* command-line arguments          */
  557.      short      curr_screen;        /* current screen number          */
  558.      u_short  node_row_max,        /* max. # of rows in node array          */
  559.           node_col_max;        /* max. # of columns in node array    */
  560. register short      scr_file;        /* number of files for current screen */
  561.      short      num_slot,        /* number of slots per screen          */
  562.           slot_width,        /* width of a filename screen slot    */
  563.           text_flag;        /* whether we display text descrips   */
  564.  
  565. {    /*** make_screen ***/
  566.                     /********   LOCAL  VARIABLES   ********/
  567. register ENT_DEF  *ent;            /* pointer to current directory entry */
  568. register short      file_count = 0;    /* number of files processed          */
  569. static     int      rend_set,        /* rendition setting for slots          */
  570.           scr_row,        /* what row on screen to write to     */
  571.           scr_col;        /* what column on screen to write to  */
  572. static     short      i,            /* loop and array index              */
  573.           j;            /*  "    "    "     "              */
  574.      char      buf[BUFSIZ+1];    /* formatting buffer              */
  575.  
  576.  
  577.    /* get pointer to the first directory entry for the current screen */
  578.  
  579.    ent = dirptr + (u_long) ((curr_screen - 1) * num_slot);
  580.    j = 0;
  581.  
  582.    while((j < node_col_max) && (file_count < scr_file))
  583.    {
  584.       i = 0;
  585.       scr_col = nodes[i][j].column + 1;    /* get column value for now          */
  586.       scr_row = 0;
  587.  
  588.       while((i < node_row_max) && (file_count < scr_file))
  589.       {
  590.      /* create the screen slot for the file; this included determining
  591.       * if we need to put something special up in case the file has
  592.       * some command(s) associated with it
  593.       */
  594.  
  595.      rend_set = make_slot(buf,ent,args,slot_width,text_flag);
  596.  
  597.      /* now write the file information to the screen in the right spot */
  598.  
  599.      put_slot(window,scr_row,scr_col,buf,rend_set);
  600.      i++;                /* move to next column              */
  601.      file_count++;            /* count this file as processed          */
  602.      scr_row++;            /* move to next row on screen          */
  603.      ent++;                /* go to next directory entry          */
  604.       }
  605.  
  606.       j++;                /* go down the screen node matrix     */
  607.    }
  608.  
  609.    if(num_slot > scr_file)        /* do we need to clear out some of    */
  610.    {                    /* the slots on the screen?          */
  611.       /* clear out the slots */
  612.  
  613.       while(i++ < node_row_max)
  614.       {
  615.      wmove(window,scr_row++,scr_col);
  616.      wclrtoeol(window);
  617.       }
  618.  
  619.       if(j < node_col_max)
  620.       {
  621.      /* we have more than one column to clear out */
  622.  
  623.      scr_col += slot_width + 1;
  624.      scr_row = 0;
  625.  
  626.      while(scr_row < node_row_max)
  627.      {
  628.         wmove(window,scr_row++,scr_col);
  629.         wclrtoeol(window);
  630.      }
  631.       }
  632.    }
  633.  
  634.    return;
  635.  
  636. }    /*** make_screen ***/
  637.  
  638. /*******************************************************************************
  639. ********************************************************************************
  640.  
  641.   Function:    check_marks
  642.  
  643.   Purpose:    Check to see if there are any marks in the current directory.
  644.  
  645.   Global variables:
  646.  
  647.     Name             Examine/Modify/Use/Read/Write
  648.     ----            -----------------------------
  649.     none
  650.  
  651.   Return Codes:
  652.  
  653.     Code            Reason
  654.     ----            ------
  655.     TRUE            marks exist in current directory
  656.     FALSE            no marks in current directory
  657.  
  658. ********************************************************************************
  659. *******************************************************************************/
  660.  
  661. int check_marks(ent,num_files)
  662.                     /*******   FORMAL  PARAMETERS   *******/
  663. register ENT_DEF  *ent;            /* pointer to current file entry      */
  664. register short      num_files;        /* number of files in directory          */
  665.  
  666. {    /*** check_marks ***/
  667.  
  668.    while(num_files--)            /* check all entries if necessary     */
  669.    {
  670.       if(ent->command)            /* command for this file?          */
  671.      return(TRUE);            /* yes, no need to check any more     */
  672.  
  673.       ent++;                /* nope, go to next entry          */
  674.    }
  675.  
  676.    return(FALSE);
  677.  
  678. }    /*** check_marks ***/
  679.  
  680. /*******************************************************************************
  681. ********************************************************************************
  682.  
  683.   Function:      get_dir_mem
  684.  
  685.   Purpose:    Compute the amount of memory needed for the current directory
  686.         and allocate it.  Also set the global pointer to the base of
  687.         the memory so that it may be used for sorting if so desired.
  688.  
  689.   Global variables:
  690.  
  691.     Name            Examine/Modify/Use/Read/Write
  692.     ----            -----------------------------
  693.     baseptr                  X    X
  694.  
  695.   Return Codes:
  696.  
  697.     Code            Reason
  698.     ----            ------
  699.     none
  700.  
  701. ********************************************************************************
  702. *******************************************************************************/
  703.  
  704. void get_dir_mem(dirptr,dirsize,num_file)
  705.                     /*******   FORMAL  PARAMETERS   *******/
  706.      ENT_DEF  **dirptr;        /* where to store pointer to memory   */
  707.      u_int      *dirsize;        /* amount of memory allocated          */
  708.      short      num_file;        /* number of files in directory          */
  709.  
  710. {    /*** get_dir_mem ***/
  711.                     /********   LOCAL  VARIABLES   ********/
  712.      u_int      memsize;        /* amount of memory to allocated      */
  713.  
  714.  
  715.    /* allocate enough memory to hold the information about each of the
  716.     * files in the current directory; we get the amount of memory by multi-
  717.     * plying the number of files (plus 1, in case we want to sort them) 
  718.     * in the directory by the length the structure definition that holds
  719.     * the information about a file
  720.     */
  721.  
  722.    /* compute how much memory to allocate */
  723.  
  724.    memsize = (u_int) ((num_file + 1) * sizeof(ENT_DEF));
  725.    *dirsize = memsize;
  726.  
  727.    baseptr = (ENT_DEF *) malloc(memsize);
  728.  
  729.    if(baseptr == NULL)
  730.    {
  731.       exit(CANT_ALLOCATE);
  732.    }
  733.    else
  734.       *dirptr = baseptr;
  735.  
  736.                     /* memory allocated for the directory */
  737.    return;
  738.  
  739. }    /*** get_dir_mem ***/
  740.  
  741. /*******************************************************************************
  742. ********************************************************************************
  743.  
  744.   Function:    get_dir
  745.  
  746.   Purpose:    Get the number of files in the current directory, allocate the
  747.         necessary memory to store the information about the directory,
  748.         and obtain the information about the individual files.
  749.  
  750.   Global variables:
  751.  
  752.     Name            Examine/Modify/Use/Read/Write
  753.     ----            -----------------------------
  754.     none
  755.  
  756.   Return Codes:
  757.  
  758.     Code            Reason
  759.     ----            ------
  760.     none
  761.  
  762. ********************************************************************************
  763. *******************************************************************************/
  764.  
  765. void get_dir(dirptr,args,num_block,curr_pool,num_file,pool_length)
  766.                     /*******   FORMAL  PARAMETERS   *******/
  767. register ENT_DEF  *dirptr;        /* pointer to allocated memory          */
  768. register ARG_DEF  *args;        /* run-time argument flags          */
  769.      long      *num_block;        /* number of blocks in directory      */
  770.      POOL_DEF **curr_pool;        /* pointer to current memory pool     */
  771.      short      *num_file;        /* number of files in directory          */
  772.      size_t      pool_length;        /* length to allocate for new pools   */
  773.  
  774. {    /*** get_dir ***/
  775.                     /********   LOCAL  VARIABLES   ********/
  776. #if !defined(SYSV)
  777. register struct      direct *dir_ent;    /* pointer to directory file entry    */
  778. #else
  779. register struct      dirent *dir_ent;    /* Suns use this as well as SysV      */
  780. #endif
  781.      size_t      name_length;        /* length of filename              */
  782.      DIR      *dptr;        /* pointer to directory file          */
  783.  
  784.  
  785.    dptr = opendir(".");            /* open directory so we can read it   */
  786.  
  787.    if(dptr == NULL)
  788.       return;
  789.  
  790.    /* process all of the directory entries that we can get */
  791.  
  792.    while((dir_ent = readdir(dptr)) != NULL) 
  793.    {
  794.       /*try to make the directory entry for this file */
  795.  
  796.       if(args->dot_files == TRUE || dir_ent->d_name[0] != '.')
  797.       {
  798.      if(make_ent(dirptr,dir_ent->d_name,num_block) == SUCCESS)
  799.      {
  800.         /* everything ok so far; store the full filename in a memory pool */
  801.  
  802.         name_length = strlen(dir_ent->d_name);
  803.         put_pool(&(dirptr->filename),curr_pool,dir_ent->d_name,name_length,
  804.              pool_length);
  805.             dirptr++;
  806.      }
  807.      else
  808.         *num_file -= 1;        /* bummer; subtract one from num_file */
  809.       }
  810.    }
  811.  
  812.    closedir(dptr);
  813.  
  814.    /* create a dummy entry at the end in case we want to sort */
  815.  
  816.    if(sizeof(int) == 4)
  817.    {
  818.       dirptr->size = 0xEFFFFFFF;
  819.       dirptr->time = 0xEFFFFFFF;
  820.    }
  821.    else
  822.    {
  823.       dirptr->size = 0xEFFF;
  824.       dirptr->time = 0xEFFF;
  825.    }
  826.  
  827.    put_pool(&(dirptr->filename),curr_pool,"~~~~~~~~~~",10,pool_length);
  828.  
  829.    if(args->sort)
  830.       sort_files(*num_file - 1,args->sort);
  831.  
  832. /*   *num_block = (long) kbytes(dbtob(*num_block)); */
  833.    return;
  834.  
  835. }    /*** get_dir ***/
  836.  
  837. /*******************************************************************************
  838. ********************************************************************************
  839.  
  840.   Function:    get_num_file
  841.  
  842.   Purpose:    Get the number of files in the current directory.
  843.  
  844.   Global variables:
  845.  
  846.     Name              Examine/Modify/Use/Read/Write
  847.     ----            -----------------------------
  848.     none
  849.  
  850.   Return Codes:
  851.  
  852.     Code            Reason
  853.     ----            ------
  854.     count            number of files in directory
  855.       -1            failure
  856.  
  857. ********************************************************************************
  858. *******************************************************************************/
  859.  
  860. short get_num_file(args)
  861.                     /*******   FORMAL  PARAMETERS   *******/
  862. register ARG_DEF  *args;        /* run-time arguments              */
  863.  
  864. {    /*** get_num_file ***/
  865.                     /********   LOCAL  VARIABLES   ********/
  866. register DIR      *dptr;        /* pointer to directory file entry    */
  867. register short      count;        /* number of files in directory          */
  868. #if !defined(SYSV)
  869. register struct      direct *dir_ent;    /* pointer to directory file entry    */
  870. #else
  871. register struct      dirent *dir_ent;    /* Suns use this as well as SysV      */
  872. #endif
  873.  
  874.  
  875.    dptr = opendir(".");            /* open the current directory          */
  876.  
  877.    if(dptr == NULL)
  878.       return(-1);
  879.  
  880.    count = 0;
  881.  
  882.    if(args->dot_files == TRUE)
  883.    {
  884.       while(readdir(dptr) != NULL)
  885.      ++count;
  886.    }
  887.    else
  888.    {
  889.       while((dir_ent = readdir(dptr)) != NULL)
  890.       {
  891.      if(dir_ent->d_name[0] != '.')
  892.         ++count;
  893.       }
  894.    }
  895.  
  896.    closedir(dptr);
  897.    return(count);            /* return number of files          */
  898.  
  899. }    /*** get_num_file ***/
  900.  
  901. /*******************************************************************************
  902. ********************************************************************************
  903.  
  904.   Function:    mystrcpy
  905.  
  906.   Purpose:    Version of strcpy that copies a string and returns a pointer
  907.         to the null character in the destination string.
  908.  
  909.   Global variables:
  910.  
  911.     Name            Examine/Modify/Use/Read/Write
  912.     ----            -----------------------------
  913.     none
  914.  
  915.   Return Codes:
  916.  
  917.     Code            Reason
  918.     ----            ------
  919.     dest - 1        pointer to null character terminating the
  920.                 destionation string
  921.  
  922. ********************************************************************************
  923. *******************************************************************************/
  924.  
  925. char *mystrcpy(dest,source)
  926.                     /*******   FORMAL  PARAMETERS   *******/
  927.      char      *dest,        /* destination string              */
  928.           *source;        /* source string              */
  929.  
  930. {    /*** mystrcpy ***/
  931.  
  932.    while(*dest++ = *source++)        /* copy the source string to the dest */
  933.       ;
  934.  
  935.    return(dest - 1);            /* return pointer to null character   */
  936.  
  937. }    /*** mystrcpy ***/
  938.  
  939. /*******************************************************************************
  940. ********************************************************************************
  941.  
  942.   Function:    mystrmcpy
  943.  
  944.   Purpose:    Version of strncpy that copies exactly n characters and
  945.         returns a pointer to the null character in the destination
  946.         string.
  947.  
  948.   Global variables:
  949.  
  950.     Name            Examine/Modify/Use/Read/Write
  951.     ----            -----------------------------
  952.     none
  953.  
  954.   Return Codes:
  955.  
  956.     Code            Reason
  957.     ----            ------
  958.     dest - 1        pointer to null character terminating the
  959.                 destionation string
  960.  
  961. ********************************************************************************
  962. *******************************************************************************/
  963.  
  964. char *mystrmcpy(dest,source,length)
  965.                     /*******   FORMAL  PARAMETERS   *******/
  966.      char      *dest,        /* destination string              */
  967.           *source;        /* source string              */
  968.      int      length;        /* max. length to copy              */
  969.  
  970. {    /*** mystrmcpy ***/
  971.  
  972.    while(*source != '\0' && length-- >= 0)
  973.       *dest++ = *source++;
  974.  
  975.    *(dest - 1) = '\0';            /* make sure it's a string          */
  976.    return(dest - 1);            /* return pointer to null character   */
  977.  
  978. }    /*** mystrmcpy ***/
  979.  
  980. /*******************************************************************************
  981. ********************************************************************************
  982.  
  983.   Function:    prot_val_to_str
  984.  
  985.   Purpose:    Create the string representing the file protection for a
  986.         specific file from the integer value for the protection.
  987.  
  988.   Global variables:
  989.  
  990.     Name            Examine/Modify/Use/Read/Write
  991.     ----            -----------------------------
  992.     none
  993.  
  994.   Return Codes:
  995.  
  996.     Code            Reason
  997.     ----             ------
  998.     buf            protection string
  999.  
  1000. ********************************************************************************
  1001. *******************************************************************************/
  1002.  
  1003. char *prot_val_to_str(prot)
  1004.                     /*******   FORMAL  PARAMETERS   *******/
  1005. register u_short  prot;            /* protection word value          */
  1006.  
  1007. {    /*** prot_val_to_str ***/
  1008.                     /********   LOCAL  VARIABLES   ********/
  1009. register char      *str;            /* pointer to buffer              */
  1010. register short      i,            /* loop and array index              */
  1011.           j,
  1012.           k;
  1013. static     char      buf[PROT_MAX+1];    /* where to put the protection string */
  1014.  
  1015.  
  1016.    /* first determine what type of file it is */
  1017.  
  1018.    str = buf;
  1019.  
  1020.    switch(prot & S_IFMT)
  1021.    {
  1022.       case(S_IFREG):
  1023.      *str = '-';            /* regular file                  */
  1024.      break;
  1025.       case(S_IFDIR):
  1026.      *str = 'd';            /* directory                  */
  1027.      break;
  1028.       case(S_IFCHR):
  1029.      *str = 'c';            /* character special file          */
  1030.      break;
  1031.       case(S_IFIFO):
  1032.      *str = 'p';            /* named pipe                  */
  1033.      break;
  1034.       case(S_IFBLK):
  1035.      *str = 'b';            /* block special file              */
  1036.      break;
  1037. #if !defined(SYSV) || defined(sun)
  1038.       case(S_IFLNK):
  1039.      *str = 'l';            /* symbolic link              */
  1040.      break;
  1041. #endif
  1042.       default:
  1043.      *str = '-';
  1044.    }
  1045.  
  1046.    /* create the permission string */
  1047.  
  1048.    k = 1;                /* skip over filetype in string          */
  1049.    j = 0;
  1050.  
  1051.    for(i = 0; i < 3; i++)
  1052.    {
  1053.       if(prot & (S_IREAD >> j))        /* check for read permission          */
  1054.      *(str + k) = 'r';
  1055.       else
  1056.      *(str + k) = '-';
  1057.  
  1058.       if(prot & (S_IWRITE >> j))    /* check for write permission          */
  1059.      *(str + k + 1) = 'w';
  1060.       else
  1061.      *(str + k + 1) = '-';
  1062.  
  1063.       if(prot & (S_IEXEC >> j))        /* check for execute permission          */
  1064.      *(str + k + 2) = 'x';
  1065.       else
  1066.      *(str + k + 2) = '-';
  1067.  
  1068.       k += 3;
  1069.       j += 3;
  1070.    }
  1071.  
  1072.    /* check the setuid bit */
  1073.  
  1074.    if(prot & S_ISUID)
  1075.    {
  1076.       /* setuid is set; now see if it is executable */
  1077.  
  1078.       if(*(str + 3) == 'x')
  1079.      *(str + 3) = 's';
  1080.       else
  1081.      *(str + 3) = 'S';
  1082.    }
  1083.  
  1084.    if(prot & S_ISGID)
  1085.    {
  1086.       /* setgid is set; now see if it is executable */
  1087.  
  1088.       if(*(str + 6) == 'x')
  1089.      *(str + 6) = 's';
  1090.       else
  1091.      *(str + 6) = 'S';
  1092.    }
  1093.  
  1094.    if(prot & S_ISVTX)
  1095.    {
  1096.       /* sticky bit is set */
  1097.  
  1098.       *(str + 9) = 't';
  1099.    }
  1100.  
  1101.    *(str + PROT_MAX) = '\0';        /* make it a string              */
  1102.    return(buf);
  1103.  
  1104. }    /*** prot_val_to_str ***/
  1105.  
  1106. /*******************************************************************************
  1107. ********************************************************************************
  1108.  
  1109.   Function:    prot_str_to_val
  1110.  
  1111.   Purpose:    Given a protection string and the original integer value
  1112.         for a file's protection, edit the string and if it is valid,
  1113.         calculate the new protection integer value.
  1114.  
  1115.   Global variables:
  1116.  
  1117.     Name            Examine/Modify/Use/Read/Write
  1118.     ----            -----------------------------
  1119.     none
  1120.  
  1121.   Return Codes:
  1122.  
  1123.     Code            Reason
  1124.     ----            ------
  1125.     SUCCESS
  1126.     FAILURE            invalid protection specification
  1127.  
  1128. ********************************************************************************
  1129. *******************************************************************************/
  1130.  
  1131. short prot_str_to_val(str,new_val)
  1132.                     /*******   FORMAL  PARAMETERS   *******/
  1133. register char      *str;            /* protection string              */
  1134.      u_short  *new_val;        /* calculated protection value          */
  1135.  
  1136. {    /*** prot_str_to_val ***/
  1137.  
  1138.                     /********   LOCAL  VARIABLES   ********/
  1139.      u_short  mode,            /* protection mode value          */
  1140.           val,            /* temporary value              */
  1141.           j,            /* loop and array index              */
  1142.           scale;        /* scaling factor for current field   */
  1143.  
  1144.    mode = 0;
  1145.    val = 0;                /* digit value                  */
  1146.    j = 0;                /* start with first group          */
  1147.    scale = 0100;
  1148.  
  1149.    while(j < (PROT_MAX - 1))
  1150.    {
  1151.       switch(*(str + j))
  1152.       {
  1153.      case('r'):
  1154.         val += 4;
  1155.         break;
  1156.      case('-'):
  1157.         break;
  1158.      default:
  1159.         return(FAILURE);
  1160.       }
  1161.  
  1162.       switch(*(str + j + 1))
  1163.       {
  1164.      case('w'):
  1165.         val += 2;
  1166.         break;
  1167.      case('-'):
  1168.         break;
  1169.      default:
  1170.         return(FAILURE);
  1171.       }
  1172.  
  1173.       /* add the mode for the current octal digit to the overall mode value */
  1174.  
  1175.       mode = mode + (scale * val);
  1176.       scale /= 010;            /* scale down for next digit          */
  1177.       val = 0;                /* reset temporary digit value          */
  1178.       j += 3;
  1179.    }
  1180.  
  1181.    /* now handle the x/s/S field of the first TWO digits in the mode string;
  1182.     * we'll do the sticky bit last
  1183.     */
  1184.  
  1185.    switch(*(str + 2))
  1186.    {
  1187.       case('-'):
  1188.      break;
  1189.       case('x'):
  1190.      mode += 0100;
  1191.      break;
  1192.       case('s'):
  1193.      mode += 04100;
  1194.      break;
  1195.       case('S'):
  1196.      mode += 04000;
  1197.      break;
  1198.       default:
  1199.      return(FAILURE);
  1200.    }
  1201.  
  1202.    switch(*(str + 5))
  1203.    {
  1204.       case('-'):
  1205.      break;
  1206.       case('x'):
  1207.      mode += 010;
  1208.      break;
  1209.       case('s'):
  1210.      mode += 02010;
  1211.      break;
  1212.       case('S'):
  1213.      mode += 02000;
  1214.      break;
  1215.       default:
  1216.      return(FAILURE);
  1217.    }
  1218.  
  1219.    /* check for the last field */
  1220.  
  1221.    switch(*(str + 8))
  1222.    {
  1223.       case('-'):
  1224.      break;
  1225.       case('x'):
  1226.      mode++;
  1227.      break;
  1228.       case('t'):
  1229.      mode += 01000;            /* sticky bit; only works for root    */
  1230.      break;
  1231.       default:
  1232.      return(FAILURE);
  1233.    }
  1234.  
  1235.    if(*(str + 9))
  1236.       return(FAILURE);            /* string too long              */
  1237.  
  1238.    *new_val = mode;            /* ok here; set the return value      */
  1239.    return(SUCCESS);
  1240.  
  1241. }    /*** prot_str_to_val ***/
  1242.  
  1243. /*******************************************************************************
  1244. ********************************************************************************
  1245.  
  1246.   Function:    set_args
  1247.  
  1248.   Purpose:    Set the original values for ent_factor and slot_width along
  1249.         with initializing some of the other flags that provide infor-
  1250.         mation about what run-time arguments were specified.
  1251.  
  1252.   Global variables:
  1253.  
  1254.     Name            Examine/Modify/Use/Read/Write
  1255.     ----            -----------------------------
  1256.     COLS
  1257.  
  1258.   Return Codes:
  1259.  
  1260.     Code            Reason
  1261.     ----            ------
  1262.     none
  1263.  
  1264. ********************************************************************************
  1265. *******************************************************************************/
  1266.  
  1267. void set_args(args,slot_width,ent_factor)
  1268.                     /*******   FORMAL  PARAMETERS   *******/
  1269. register ARG_DEF  *args;        /* run-time argument flags          */
  1270.      short      *slot_width;        /* starting slot width              */
  1271.      size_t      *ent_factor;        /* ent. size memory allocation factor */
  1272.  
  1273. {    /*** set_args ***/
  1274.  
  1275.    /* initialize the width to include the length of the filename that
  1276.     * will be displayed and the spot to hold the cursor; also update
  1277.     * the entry size factor for later
  1278.     */
  1279.  
  1280.    *slot_width = DISP_MAX;
  1281.    *ent_factor = FUDGE_FACTOR;
  1282.  
  1283.    /* we have to see what info should be included to get the
  1284.     * slot width and the entry factor
  1285.     */
  1286.  
  1287.    if(args->date)
  1288.       *slot_width = *slot_width + DATE_MAX + FIELD_GAP;
  1289.  
  1290.    if(args->size)
  1291.       *slot_width = *slot_width + SIZE_MAX + FIELD_GAP;
  1292.  
  1293.    if(args->prot)
  1294.       *slot_width = *slot_width + PROT_MAX + FIELD_GAP;
  1295.  
  1296.    if(args->owner)
  1297.       *slot_width = *slot_width + OWNER_MAX + FIELD_GAP;
  1298.  
  1299.    if(args->group)
  1300.       *slot_width = *slot_width + GROUP_MAX + FIELD_GAP;
  1301.  
  1302.    if(args->text)
  1303.    {
  1304.       /* the user wants text descriptors */
  1305.  
  1306.       *ent_factor = *ent_factor + TEXT_MAX + 1;
  1307.       *slot_width = *slot_width + TEXT_MAX + FIELD_GAP;
  1308.  
  1309.       /* now see if there is enough room to include the text descriptors on
  1310.        * the screen
  1311.        */
  1312.  
  1313.       if(*slot_width > (COLS - 1))
  1314.       {
  1315.      args->text = SLOT_OVF;        /* they overflow the file slots          */
  1316.      *slot_width = *slot_width - (TEXT_MAX + FIELD_GAP);
  1317.       }
  1318.    }
  1319.  
  1320.    if(*slot_width == DISP_MAX)
  1321.       args->def = 1;            /* just default info on screen          */
  1322.    else
  1323.       args->def = 0;            /* clear to be thorough.....          */
  1324.  
  1325.    return;
  1326.  
  1327. }    /*** set_args ***/
  1328.  
  1329. /*******************************************************************************
  1330. ********************************************************************************
  1331.  
  1332.   Function:    set_width
  1333.  
  1334.   Purpose:    Set the slot width for the current directory based on whether
  1335.         or not text descriptors will be included on the screen
  1336.  
  1337.   Global variables:
  1338.  
  1339.     Name            Examine/Modify/Use/Read/Write
  1340.     ----            -----------------------------
  1341.     none
  1342.  
  1343.   Return Codes:
  1344.  
  1345.     Code            Reason
  1346.     ----            ------
  1347.     none
  1348.  
  1349. ********************************************************************************
  1350. *******************************************************************************/
  1351.  
  1352. void set_width(slot_width,text_flag)
  1353.                     /*******   FORMAL  PARAMETERS   *******/
  1354.      short      *slot_width,        /* current slot width              */
  1355.           text_flag;        /* text descrips included for dir?    */
  1356.  
  1357. {    /*** set_width ***/
  1358.  
  1359.  
  1360.    /* should we at least TRY to get text descriptors on the screen? */
  1361.  
  1362.    if(text_flag == DISPLAY_TEXT)
  1363.    {
  1364.       /* yes, they need to be displayed; increase the slot_width
  1365.        * to accommodate them
  1366.        */
  1367.  
  1368.       *slot_width = *slot_width + TEXT_MAX + 1;
  1369.    }
  1370.  
  1371.    return;
  1372.  
  1373. }    /*** set_width ***/
  1374.  
  1375. /*******************************************************************************
  1376. ********************************************************************************
  1377.  
  1378.   Function:    banystr
  1379.  
  1380.   Purpose:    Determine if a finite-length character string contains
  1381.         any characters from a second null-terminated character
  1382.         string.
  1383.  
  1384.   Global variables:
  1385.  
  1386.     Name            Examine/Modify/Use/Read/Write
  1387.     ----            -----------------------------
  1388.     none
  1389.  
  1390.   Return Codes:
  1391.  
  1392.     Code            Reason
  1393.     ----            ------
  1394.      >=0            match was found; return code is the offset
  1395.                 into str1 where the character is found
  1396.       -1            no common characters in the two strings
  1397.  
  1398. ********************************************************************************
  1399. *******************************************************************************/
  1400.  
  1401. short banystr(str1,str2,length)
  1402.                       /*******   FORMAL  PARAMETERS   *******/
  1403. register char      *str1,        /* string to search              */
  1404.           *str2;        /* what to look for              */
  1405.      short      length;        /* when to stop searching          */
  1406.  
  1407. {    /*** banystr ***/
  1408.                     /********   LOCAL  VARIABLES   ********/
  1409. register int      offset1,        /* offset into string str1          */
  1410.           offset2;        /* offset into string str2          */
  1411.  
  1412.  
  1413.    if(str1 == NULL || str2 == NULL || length <= 0)
  1414.       return(-1);
  1415.  
  1416.    if((*str1 == '\0') || (*str2 == '\0'))
  1417.       return(-1);
  1418.  
  1419.    offset1 = 0;
  1420.  
  1421.    while(*(str1+offset1) != '\0' && length--)
  1422.    {
  1423.       offset2 = 0;
  1424.       while(*(str2+offset2) != '\0')
  1425.       {
  1426.      if(*(str1+offset1) == *(str2+offset2))
  1427.      {
  1428.         return(offset1);        /* match found; return offset          */
  1429.      }
  1430.      ++offset2;
  1431.       }
  1432.       ++offset1;
  1433.    }
  1434.  
  1435.    return(-1);                /* no match; return -1              */
  1436.  
  1437. }    /*** banystr ***/
  1438.  
  1439. /*******************************************************************************
  1440. ********************************************************************************
  1441.  
  1442.   Function:    set_type
  1443.  
  1444.   Purpose:    Determine the type of a file and return it.
  1445.  
  1446.   Global variables:
  1447.  
  1448.     Name            Examine/Modify/Use/Read/Write
  1449.     ----            -----------------------------
  1450.     none
  1451.  
  1452.   Return Codes:
  1453.  
  1454.     Code            Reason
  1455.     ----            ------
  1456.     REGULAR            regular file
  1457.     DIRECTORY        directory
  1458.     CHARACTER        character-type special file
  1459.     BLOCK            block special file
  1460.     FIFO            FIFO (named pipe)
  1461.     SOCKET            socket file
  1462.     LINK            symbolic link
  1463.  
  1464. ********************************************************************************
  1465. *******************************************************************************/
  1466.  
  1467. static u_char set_type(mode)
  1468.                     /*******   FORMAL  PARAMETERS   *******/
  1469.      u_short  mode;            /* protection mode to examine          */
  1470.  
  1471. {    /*** set_type ***/
  1472.  
  1473.    switch(mode & S_IFMT)
  1474.    {
  1475. #if !defined(SYSV) || defined(sun)
  1476.       case(S_IFLNK):
  1477.      return(LINK);
  1478. #endif
  1479.       case(S_IFREG):
  1480.      return(REGULAR);
  1481.       case(S_IFDIR):
  1482.      return(DIRECTORY);
  1483.       case(S_IFCHR):
  1484.      return(CHARACTER);
  1485.       case(S_IFBLK):
  1486.      return(BLOCK);
  1487. #if !defined(SYSV) || defined(sun)
  1488.       case(S_IFSOCK):
  1489.      return(SOCKET);
  1490. #endif
  1491.       case(S_IFIFO):
  1492.      return(FIFO);
  1493.       default:
  1494.      break;
  1495.     }
  1496.  
  1497.    return(REGULAR);            /* default is regular type          */
  1498.  
  1499. }    /*** set_type ***/
  1500.  
  1501. /*******************************************************************************
  1502. ********************************************************************************
  1503.  
  1504.   Function:    set_date
  1505.  
  1506.   Purpose:    Create a date string for a file.
  1507.  
  1508.   Global variables:
  1509.  
  1510.     Name            Examine/Modify/Use/Read/Write
  1511.     ----            -----------------------------
  1512.     curr_year           X
  1513.  
  1514.   Return Codes:
  1515.  
  1516.     Code            Reason
  1517.     ----            ------
  1518.     date_buf        buffer where date string is stored
  1519.  
  1520. ********************************************************************************
  1521. *******************************************************************************/
  1522.  
  1523. char *set_date(time_val)
  1524.                     /*******   FORMAL  PARAMETERS   *******/
  1525.      time_t      time_val;        /* binary time value              */
  1526.  
  1527. {    /*** set_date ***/
  1528.                     /********   LOCAL  VARIABLES   ********/
  1529. struct     tm      *time_str;        /* time structure              */
  1530. static     char      date_buf[DATE_MAX+1];
  1531. static     char      *month[] =
  1532. {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
  1533.  
  1534.    time_str = localtime(&time_val);
  1535.  
  1536.    if(time_str->tm_year == curr_year)
  1537.       sprintf(date_buf,"%3s %2d %2d:%1d%1d",month[time_str->tm_mon],
  1538.           time_str->tm_mday,time_str->tm_hour,time_str->tm_min/10,
  1539.           time_str->tm_min%10);
  1540.    else
  1541.       sprintf(date_buf,"%3s %2d  %4d",month[time_str->tm_mon],
  1542.           time_str->tm_mday,time_str->tm_year + 1900);
  1543.  
  1544.    return(date_buf);
  1545.  
  1546. }    /*** set_date ***/
  1547.  
  1548. /*******************************************************************************
  1549. ********************************************************************************
  1550.  
  1551.   Function:    padcpy
  1552.  
  1553.   Purpose:    Copy a counted string, padding with spaces.
  1554.  
  1555.   Global variables:
  1556.  
  1557.     Name            Examine/Modify/Use/Read/Write
  1558.     ----            -----------------------------
  1559.     none
  1560.  
  1561.   Return Codes:
  1562.  
  1563.     Code            Reason
  1564.     ----            ------
  1565.     date_buf        buffer where date string is stored
  1566.  
  1567. ********************************************************************************
  1568. *******************************************************************************/
  1569.  
  1570. char *padcpy(dest,source,length)
  1571.                     /********   LOCAL  VARIABLES   ********/
  1572.      char      *dest,        /* destination string              */
  1573.           *source;        /* source string              */
  1574.      int      length;        /* length that destination should be  */
  1575.  
  1576. {    /*** padcpy ***/
  1577.  
  1578.    if(source != NULL && *source != '\0')
  1579.    {
  1580.       while(*source && length--)    /* copy it                  */
  1581.      *dest++ = *source++;
  1582.    }
  1583.  
  1584.    while(length-- > 0)            /* pad it                  */
  1585.       *dest++ = ' ';
  1586.  
  1587.    *dest = '\0';            /* make it a string              */
  1588.    return(dest);
  1589.  
  1590. }    /*** padcpy ***/
  1591.  
  1592. /*******************************************************************************
  1593. ********************************************************************************
  1594.  
  1595.   Function:    add_filetype
  1596.  
  1597.   Purpose:    Set the filetype in an integer file mode.
  1598.  
  1599.   Global variables:
  1600.  
  1601.     Name            Examine/Modify/Use/Read/Write
  1602.     ----            -----------------------------
  1603.     none
  1604.  
  1605.   Return Codes:
  1606.  
  1607.     Code            Reason
  1608.     ----            ------
  1609.     prot            new protection value
  1610.  
  1611. ********************************************************************************
  1612. *******************************************************************************/
  1613.  
  1614. u_short add_filetype(type,prot)
  1615.                     /*******   FORMAL  PARAMETERS   *******/
  1616.      u_char      type;            /* type of file                  */
  1617.      u_short  prot;            /* protection mode to work with          */
  1618.  
  1619. {    /*** add_filetype ***/
  1620.  
  1621.  
  1622.    switch(type)
  1623.    {
  1624.       case(REGULAR):
  1625.      prot |= S_IFREG;
  1626.      break;
  1627.       case(DIRECTORY):
  1628.      prot |= S_IFDIR;
  1629.      break;
  1630.       case(CHARACTER):
  1631.      prot |= S_IFCHR;
  1632.      break;
  1633.       case(BLOCK):
  1634.      prot |= S_IFBLK;
  1635.      break;
  1636.       case(FIFO):
  1637.      prot |= S_IFIFO;
  1638.      break;
  1639. #if !defined(SYSV) || defined(sun)
  1640.       case(SOCKET):
  1641.      prot |= S_IFSOCK;
  1642.      break;
  1643.       case(LINK):
  1644.      prot |= S_IFLNK;
  1645.      break;
  1646. #endif
  1647.       default:
  1648.      prot |= S_IFREG;
  1649.      break;
  1650.    }
  1651.  
  1652.    return(prot);
  1653.  
  1654. }    /*** add_filetype ***/
  1655.  
  1656. /*******************************************************************************
  1657. ********************************************************************************
  1658.  
  1659.   Function:    spawn
  1660.  
  1661.   Purpose:    Fork off a process to let the user return to the shell.
  1662.  
  1663.   Global variables:
  1664.  
  1665.     Name            Examine/Modify/Use/Read/Write
  1666.     ----            -----------------------------
  1667.     none
  1668.  
  1669.   Return Codes:
  1670.  
  1671.     Code            Reason
  1672.     ----            ------
  1673.     SUCCESS
  1674.     FAILURE
  1675.  
  1676. ********************************************************************************
  1677. *******************************************************************************/
  1678.  
  1679. int spawn()
  1680.  
  1681. {    /*** spawn ***/
  1682.                     /********   LOCAL  VARIABLES   ********/
  1683.      char      *tptr,        /* temporary pointer              */
  1684.           *shell;        /* pointer to the user's shell          */
  1685.      int      child,        /* pid of child process              */
  1686.           i;            /* loop and return value          */
  1687. #if !defined(SYSV) || defined(sun)
  1688. union     wait      status;
  1689. #else
  1690.      int      status;
  1691. #endif
  1692.  
  1693.  
  1694.    shell = getenv("SHELL");        /* get what shell to use          */
  1695.  
  1696.    if(shell == NULL || *shell == '\0')
  1697.       shell = DEFAULT_SHELL;        /* user didn't have a SHELL variable  */
  1698.  
  1699.    tptr = strrchr(shell,'/');        /* find last level of shell name      */
  1700.  
  1701.    if(tptr == NULL)
  1702.       tptr = shell;
  1703.    else
  1704.       tptr++;
  1705.  
  1706.    if((child = vfork()) == 0)
  1707.    {
  1708.       /* we're in the child */
  1709.  
  1710.       endwin();                /* make sure tty is reset          */
  1711.       execlp(shell,tptr,NULL);        /* no return from this              */
  1712.       return(FAILURE);            /* failure if we get here          */
  1713.    }
  1714.    else if(child > 0)
  1715.    {
  1716.       /* we're in the parent; wait for the child to finish */
  1717.  
  1718.       while(((i = wait(&status)) != child) && i > 0)
  1719.      ;
  1720.    }
  1721.    else
  1722.       return(FAILURE);            /* can't fork                  */
  1723.  
  1724.    return(SUCCESS);
  1725.  
  1726. }    /*** spawn ***/
  1727.  
  1728. /*******************************************************************************
  1729. ********************************************************************************
  1730.  
  1731.   Function:    check_nlen
  1732.  
  1733.   Purpose:    Check if a filename (as displayed) would be longer than
  1734.         DISP_MAX.  This info is useful in make_slot() when we are
  1735.         deciding what has to be tagged.
  1736.  
  1737.   Global variables:
  1738.  
  1739.     Name            Examine/Modify/Use/Read/Write
  1740.     ----            -----------------------------
  1741.     none
  1742.  
  1743.   Return Codes:
  1744.  
  1745.     Code            Reason
  1746.     ----            ------
  1747.     count            displayed length of filename
  1748.  
  1749. ********************************************************************************
  1750. *******************************************************************************/
  1751.  
  1752. static u_short check_nlen(filename)
  1753.                     /*******   FORMAL  PARAMETERS   *******/
  1754. register char      *filename;        /* filename to be checked          */
  1755.  
  1756. {    /*** check_nlen ***/
  1757.                     /********   LOCAL  VARIABLES   ********/
  1758. register u_short  count;        /* length of displayed filename          */
  1759.  
  1760.  
  1761.    count = 0;
  1762.  
  1763.    while(*filename)
  1764.    {
  1765.       if(!iscntrl(*filename))
  1766.      count++;
  1767.       else
  1768.      count += 2;
  1769.  
  1770.       ++filename;
  1771.    }
  1772.  
  1773.    return(count);
  1774.  
  1775. }    /*** check_nlen ***/
  1776.  
  1777. /*******************************************************************************
  1778. ********************************************************************************
  1779.  
  1780.   Function:    strtcpy
  1781.  
  1782.   Purpose:    Copy one string to another, translating control characters to
  1783.         a two-character pair of ^ and the printable control character.
  1784.  
  1785.   Global variables:
  1786.  
  1787.     Name            Examine/Modify/Use/Read/Write
  1788.     ----            -----------------------------
  1789.     none
  1790.  
  1791.   Return Codes:
  1792.  
  1793.     Code            Reason
  1794.     ----            ------
  1795.     count            displayed length of filename
  1796.  
  1797. ********************************************************************************
  1798. *******************************************************************************/
  1799.  
  1800. int strtcpy(dest,source)
  1801.                     /*******   FORMAL  PARAMETERS   *******/
  1802. register char      *dest,        /* destination string              */
  1803.           *source;        /* source string              */
  1804.  
  1805. {    /*** strtcpy ***/
  1806.                     /********   LOCAL  VARIABLES   ********/
  1807. register int      length;        /* length of resulting string          */
  1808.  
  1809.  
  1810.    length = 0;
  1811.  
  1812.    while(*source)
  1813.    {
  1814.       if(iscntrl(*source))
  1815.       {
  1816.      *dest++ = '^';
  1817.      *dest++ = *source++ + '@';    /* make it printable              */
  1818.      length += 2;
  1819.       }
  1820.       else
  1821.       {
  1822.      *dest++ = *source++;
  1823.      ++length;
  1824.       }
  1825.    }
  1826.  
  1827.    *dest = '\0';            /* make it a string              */
  1828.    return(length);
  1829.  
  1830. }    /*** strtcpy ***/
  1831.  
  1832. /*******************************************************************************
  1833. ********************************************************************************
  1834.  
  1835.   Function:    get_filemarks
  1836.  
  1837.   Purpose:    Recreate the displayed names for all of the files in the
  1838.         current directory so that they include the filemarks.  This
  1839.         is normally only done after the filemarks are selected from
  1840.         the options menu.
  1841.  
  1842.   Global variables:
  1843.  
  1844.     Name            Examine/Modify/Use/Read/Write
  1845.     ----            -----------------------------
  1846.     none
  1847.  
  1848.   Return Codes:
  1849.  
  1850.     Code            Reason
  1851.     ----            ------
  1852.     none
  1853.  
  1854. ********************************************************************************
  1855. *******************************************************************************/
  1856.  
  1857. void get_filemarks(dirptr,num_file)
  1858.                     /*******   FORMAL  PARAMETERS   *******/
  1859. register ENT_DEF  *dirptr;        /* pointer to directory information   */
  1860. register short      num_file;        /* number of files in directory          */
  1861.  
  1862. {    /*** get_filemarks ***/
  1863.  
  1864.    while(num_file-- > 0)
  1865.    {
  1866.       strcpy(dirptr->scr_name,get_name(dirptr->filename,&dirptr->name_len));
  1867.       dirptr++;
  1868.    }
  1869.  
  1870.    return;
  1871.  
  1872. }    /*** get_filemarks ***/
  1873.  
  1874. /*******************************************************************************
  1875. ********************************************************************************
  1876.  
  1877.   Function:    get_name
  1878.  
  1879.   Purpose:    Create the filename that will be displayed in a slot, including
  1880.         translating non-printable characters.
  1881.  
  1882.   Global variables:
  1883.  
  1884.     Name            Examine/Modify/Use/Read/Write
  1885.     ----            -----------------------------
  1886.     args.filemarks           X
  1887.  
  1888.   Return Codes:
  1889.  
  1890.     Code            Reason
  1891.     ----            ------
  1892.     retptr            pointer to displayed filename string
  1893.  
  1894. ********************************************************************************
  1895. *******************************************************************************/
  1896.  
  1897. static char *get_name(filename,length,prot,type)
  1898.                     /*******   FORMAL  PARAMETERS   *******/
  1899.      char      *filename;        /* original filename              */
  1900.      u_short  *length,        /* length of filename minus padding   */
  1901.           prot;            /* integer protection value          */
  1902.      u_char      type;            /* file type                  */
  1903.  
  1904. {    /*** get_name ***/
  1905.                     /********   LOCAL  VARIABLES   ********/
  1906. register char      *tptr;        /* temporary character pointer          */
  1907. register u_short  i;            /* loop and array index              */
  1908. static     char      newname[DISP_MAX+1];    /* where to store translated name     */
  1909.  
  1910.  
  1911.    i = 0;
  1912.    tptr = newname;
  1913.  
  1914.    while((i < DNAME_MAX) && (*filename != '\0'))
  1915.    {
  1916.       if(*filename >= ' ')
  1917.       {
  1918.      *tptr = *filename;
  1919.      tptr++;
  1920.      filename++;
  1921.      ++i;
  1922.       }
  1923.       else
  1924.       {
  1925.      *tptr++ = '^';            /* non-printable; translate it          */
  1926.      ++i;
  1927.  
  1928.      if(i < DNAME_MAX)
  1929.      {
  1930.         *tptr = *filename + '@';
  1931.         ++i;
  1932.         tptr++;
  1933.      }
  1934.  
  1935.      filename++;
  1936.       }
  1937.    }
  1938.  
  1939.    /* pad the name with spaces */
  1940.  
  1941.    if(args.filemarks)
  1942.       *tptr++ = filetype_char(prot,type);
  1943.    else
  1944.       *tptr++ = ' ';
  1945.  
  1946.    *length = ++i;            /* count the filemark char          */
  1947.  
  1948.    while(i++ < DISP_MAX)
  1949.       *tptr++ = ' ';
  1950.  
  1951.    *tptr = '\0';            /* make sure it's a string          */
  1952.    return(newname);
  1953.  
  1954. }    /*** get_name ***/
  1955.  
  1956. /*******************************************************************************
  1957. ********************************************************************************
  1958.  
  1959.   Function:    filetype_char
  1960.  
  1961.   Purpose:    Determine what character should be appended to the filename
  1962.         for the -F option.
  1963.  
  1964.   Global variables:
  1965.  
  1966.     Name            Examine/Modify/Use/Read/Write
  1967.     ----            -----------------------------
  1968.     none
  1969.  
  1970.   Return Codes:
  1971.  
  1972.     Code            Reason
  1973.     ----            ------
  1974.     retval            filetype character
  1975.  
  1976. ********************************************************************************
  1977. *******************************************************************************/
  1978.  
  1979. u_char filetype_char(prot,type)
  1980.                     /*******   FORMAL  PARAMETERS   *******/
  1981.      u_short  prot;            /* file protection word              */
  1982.      u_char      type;            /* type of file                  */
  1983.  
  1984. {    /*** filetype_char ***/
  1985.                     /********   LOCAL  VARIABLES   ********/
  1986.      u_char      retval;        /* file type char (for -F)          */
  1987.  
  1988.  
  1989.    switch(type)
  1990.    {
  1991.       case(DIRECTORY):
  1992.  
  1993.      retval = '/';
  1994.      break;
  1995.  
  1996.       case(SOCKET):
  1997.  
  1998.      retval = '=';
  1999.      break;
  2000.  
  2001. #if !defined(SYSV) || defined(sun)
  2002.       case(LINK):
  2003.  
  2004.      retval = '@';
  2005.      break;
  2006. #endif
  2007.  
  2008.       case(REGULAR):
  2009.  
  2010.      /* determine if the file is executable */
  2011.  
  2012.      if(prot & (S_IEXEC | (S_IEXEC >> 3) | (S_IEXEC >> 6)))
  2013.         retval = '*';
  2014.      else
  2015.         retval = ' ';
  2016.  
  2017.      break;
  2018.  
  2019.       default:
  2020.  
  2021.      retval = ' ';
  2022.      break;
  2023.    }
  2024.  
  2025.    return(retval);
  2026.  
  2027. }    /*** filetype_char ****/
  2028.  
  2029. /*******************************************************************************
  2030. ********************************************************************************
  2031.  
  2032.   Function:    squeeze_str
  2033.  
  2034.   Purpose:    Squeeze the whitespace characters out of a string
  2035.  
  2036.   Global variables:
  2037.  
  2038.     Name            Examine/Modify/Use/Read/Write
  2039.     ----            -----------------------------
  2040.     none
  2041.  
  2042.   Return Codes:
  2043.  
  2044.     Code            Reason
  2045.     ----            ------
  2046.     none
  2047.  
  2048. ********************************************************************************
  2049. *******************************************************************************/
  2050.  
  2051. void squeeze_str(str)
  2052.                     /*******   FORMAL  PARAMETERS   *******/
  2053. register char      *str;            /* string to be squeezed          */
  2054.  
  2055. {    /*** squeeze_str ***/
  2056.                     /********   LOCAL  VARIABLES   ********/
  2057. register char      *ptr;            /* temporary pointer              */
  2058.  
  2059.  
  2060.    ptr = str;
  2061.  
  2062.    while(*ptr)
  2063.    {
  2064.       if(!isspace(*ptr))
  2065.      *str++ = *ptr++;
  2066.       else
  2067.      ptr++;
  2068.    }
  2069.  
  2070.    *str = '\0';                /* make sure it's a string          */
  2071.    return;
  2072.  
  2073. }    /*** squeeze_str ***/
  2074.  
  2075. /*******************************************************************************
  2076. ********************************************************************************
  2077.  
  2078.   Function:    follow_link
  2079.  
  2080.   Purpose:    Given a filename that is a symbolic link, try to find out what
  2081.         it points to.
  2082.  
  2083.   Global variables:
  2084.  
  2085.     Name            Examine/Modify/Use/Read/Write
  2086.     ----            -----------------------------
  2087.     none
  2088.  
  2089.   Return Codes:
  2090.  
  2091.     Code            Reason
  2092.     ----            ------
  2093.     REGULAR
  2094.     DIRECTORY
  2095.     CHARACTER
  2096.     BLOCK
  2097.     LINK
  2098.     SOCKET
  2099.  
  2100. ********************************************************************************
  2101. *******************************************************************************/
  2102.  
  2103. int follow_link(linkname)
  2104.                     /*******   FORMAL  PARAMETERS   *******/
  2105.      char      *linkname;        /* link to follow              */
  2106.  
  2107. {    /*** follow_link ***/
  2108.                     /********   LOCAL  VARIABLES   ********/
  2109. struct     stat      statbuf;        /* for stat'ing the file          */
  2110.  
  2111.  
  2112.    if(stat(linkname,&statbuf) == -1)
  2113.       return(FAILURE);
  2114.  
  2115.    switch(statbuf.st_mode & S_IFMT)
  2116.    {
  2117.       case(S_IFREG):
  2118.      return(REGULAR);
  2119.       case(S_IFDIR):
  2120.      return(DIRECTORY);
  2121.       case(S_IFCHR):
  2122.      return(CHARACTER);
  2123.       case(S_IFBLK):
  2124.      return(BLOCK);
  2125. #if !defined(SYSV) || defined(sun)
  2126.       case(S_IFLNK):
  2127.      return(LINK);
  2128.       case(S_IFSOCK):
  2129.      return(SOCKET);
  2130. #endif
  2131.       default:
  2132.      break;
  2133.    }
  2134.  
  2135.    return(REGULAR);
  2136.  
  2137. }    /*** follow_link ***/
  2138.  
  2139. /*******************************************************************************
  2140. ********************************************************************************
  2141.  
  2142.   Function:    get_bnum
  2143.  
  2144.   Purpose:    Get the number of blocks that a file occupies and return it.
  2145.  
  2146.   Global variables:
  2147.  
  2148.     Name            Examine/Modify/Use/Read/Write
  2149.     ----            -----------------------------
  2150.     none
  2151.  
  2152.   Return Codes:
  2153.  
  2154.     Code            Reason
  2155.     ----            ------
  2156.     kbytes(...)        number of blocks the file occupies
  2157.  
  2158. ********************************************************************************
  2159. *******************************************************************************/
  2160.  
  2161. long get_bnum(filename)
  2162.                     /*******   FORMAL  PARAMETERS   *******/
  2163.      char      *filename;        /* file to be examined              */
  2164.  
  2165. {    /*** get_bnum ***/
  2166.                     /********   LOCAL  VARIABLES   ********/
  2167. struct     stat      statbuf;        /* for doing a stat              */
  2168.  
  2169.  
  2170.    if(stat(filename,&statbuf) != 0)
  2171.       return(0L);
  2172.  
  2173. #if !defined(SYSV) || defined(sun)
  2174.    return((long) statbuf.st_blocks);
  2175. #else
  2176.    return((long) statbuf.st_size);
  2177. #endif
  2178.  
  2179. }    /*** get_bnum ***/
  2180.  
  2181. /*******************************************************************************
  2182. ********************************************************************************
  2183.  
  2184.   Function:    cont_after_stop
  2185.  
  2186.   Purpose:    Signal hander called when restarting after being suspended
  2187.  
  2188.   Global variables:
  2189.  
  2190.     Name            Examine/Modify/Use/Read/Write
  2191.     ----            -----------------------------
  2192.     main_win                X
  2193.     spec_win                X
  2194.     stat_win                X
  2195.  
  2196.   Return Codes:
  2197.  
  2198.     Code            Reason
  2199.     ----            ------
  2200.     none
  2201.  
  2202. ********************************************************************************
  2203. *******************************************************************************/
  2204.  
  2205. void cont_after_stop()
  2206.  
  2207. {    /*** cont_after_stop ***/
  2208.  
  2209.    /* redraw the screen after resuming */
  2210.  
  2211.    touchwin(spec_win);
  2212.    touchwin(main_win);
  2213.    touchwin(stat_win);
  2214.    wrefresh(spec_win);
  2215.    wrefresh(main_win);
  2216.    wrefresh(stat_win);
  2217.    return;
  2218.  
  2219. }    /*** cont_after_stop ***/
  2220.  
  2221. /*******************************************************************************
  2222. ********************************************************************************
  2223.  
  2224.   Function:    cat
  2225.  
  2226.   Purpose:    Concatenate strings into one string.
  2227.  
  2228.   Global variables:
  2229.  
  2230.     Name            Examine/Modify/Use/Read/Write
  2231.     ----            -----------------------------
  2232.     none
  2233.  
  2234.   Return Codes:
  2235.  
  2236.     Code            Reason
  2237.     ----            ------
  2238.     retval            pointer to destination string
  2239.     NULL            null string pointer; returned when
  2240.                 no arguments are passed
  2241.  
  2242.   Termination Codes:
  2243.  
  2244.     Code            Reason
  2245.     ----            ------
  2246.     none
  2247.  
  2248.   Description of Linkage:
  2249.  
  2250.     char    *rc,
  2251.         *cat();
  2252.  
  2253.     rc = cat(num_args,dest,source1,source2,...sourcen);
  2254.  
  2255.     where dest is a pointer to a character string allocated by
  2256.     the caller and is large enough to hold the resulting string
  2257.     and source1, source2,...sourcen are pointers to character
  2258.     strings to be concatenated.
  2259.  
  2260. ********************************************************************************
  2261. *******************************************************************************/
  2262.  
  2263. char *cat(va_alist)
  2264.                     /*******   FORMAL  PARAMETERS   *******/
  2265.      va_dcl                /* variable-length parameter list     */
  2266.  
  2267. {    /*** cat ***/
  2268.                     /********   LOCAL  VARIABLES   ********/
  2269. static     char      *dest,        /* pointer to destination string      */
  2270.           *source;        /* pointer to current source string   */
  2271. static     char      *retval;        /* to save pointer to destination     */
  2272. static     int      count;        /* number of arguments passed          */
  2273. static     va_list  incrmtr;        /* argument list incrementor          */
  2274.  
  2275.  
  2276.    va_start(incrmtr);            /* begin everything....              */
  2277.  
  2278.    count = va_arg(incrmtr,int);        /* get number of arguments          */
  2279.  
  2280.    if(count <= 1)            /* enough arguments?              */
  2281.       return(NULL);            /* nope, get out of here...          */
  2282.  
  2283.    dest = va_arg(incrmtr,char*);    /* get the destination pointer          */
  2284.    retval = dest;            /* save pointer to destination          */
  2285.  
  2286.    --count;                /* subtract for first argument          */
  2287.  
  2288.    while(count > 0)            /* process all of the source strings  */
  2289.    {
  2290.       source = va_arg(incrmtr,char*);    /* get the next argument          */
  2291.       while(*dest++ = *source++)    /* cat the source to the destination  */
  2292.      ;
  2293.  
  2294.       dest--;                /* back over the null character          */
  2295.       count--;
  2296.    }
  2297.  
  2298.    *dest = '\0';            /* terminate the destination          */
  2299.    va_end(incrmtr);            /* end varargs session              */
  2300.  
  2301.    return(retval);            /* return pointer to destination      */
  2302.  
  2303. }    /*** cat ***/
  2304.  
  2305. /*******************************************************************************
  2306. ********************************************************************************
  2307.  
  2308.   Function:    strindex
  2309.  
  2310.   Purpose:    Return the position of one string in another.
  2311.  
  2312.   Global variables:
  2313.  
  2314.     Name            Examine/Modify/Use/Read/Write
  2315.     ----            -----------------------------
  2316.     none
  2317.  
  2318.   Return Codes:
  2319.  
  2320.     Code            Reason
  2321.     ----            ------
  2322.      -1            key not found in str or key is a null
  2323.                 pointer or str is a null pointer
  2324.     offset            offset into str where key is located
  2325.  
  2326.   Termination Codes:
  2327.  
  2328.     Code            Reason
  2329.     ----            ------
  2330.     none
  2331.  
  2332.    Description of Linkage:
  2333.  
  2334.     int  strindex();
  2335.     rc = strindex(str,key);
  2336.  
  2337. ********************************************************************************
  2338. *******************************************************************************/
  2339.  
  2340. int strindex(str,key)
  2341.                     /*******   FORMAL  PARAMETERS   *******/
  2342. register char      *str,            /* string to be searched          */
  2343.           *key;            /* string to be searched for          */
  2344.  
  2345. {    /*** strindex ***/
  2346.                     /********   LOCAL  VARIABLES   ********/
  2347. register int      i,            /* primary pointer to str          */
  2348.           j,            /* secondary pointer to str for com-  */
  2349.                     /* parison                  */
  2350.           k;            /* pointer to key for comparison      */
  2351.  
  2352.  
  2353.    if(str == NULL || key == NULL || *str == '\0' || *key == '\0')
  2354.       return(-1);
  2355.  
  2356.    i = 0;
  2357.    while(*(str+i) != '\0')
  2358.    {
  2359.       j = i;
  2360.       k = 0;
  2361.  
  2362.       /* look for a match */
  2363.  
  2364.       while((*(str+j) == *(key+k)) && (*(str+j) != '\0') && (*(key+k) != '\0'))
  2365.       {
  2366.      ++j;
  2367.      ++k;
  2368.       }
  2369.  
  2370.       if(*(key+k) == '\0')
  2371.      return(i);            /* key was found              */
  2372.       else if(*(str+j) == '\0')
  2373.      return(-1);            /* key was not found              */
  2374.  
  2375.       ++i;                /* not sure yet; keep trying...          */
  2376.    }
  2377.  
  2378.    /* if we get to here, the key was not found */
  2379.  
  2380.    return(-1);
  2381.  
  2382. }    /*** strindex ***/
  2383.  
  2384. /*******************************************************************************
  2385. ********************************************************************************
  2386.  
  2387.   Function:    rename
  2388.  
  2389.   Purpose:    Fake a rename function for System V machines
  2390.  
  2391.   Global variables:
  2392.  
  2393.     Name            Examine/Modify/Use/Read/Write
  2394.     ----            -----------------------------
  2395.     none
  2396.  
  2397.   Return Codes:
  2398.  
  2399.     Code            Reason
  2400.     ----            ------
  2401.      -1            key not found in str or key is a null
  2402.                 pointer or str is a null pointer
  2403.     offset            offset into str where key is located
  2404.  
  2405.   Termination Codes:
  2406.  
  2407.     Code            Reason
  2408.     ----            ------
  2409.     none
  2410.  
  2411. ********************************************************************************
  2412. *******************************************************************************/
  2413.  
  2414. #if defined(SYSV) && !defined(sun)
  2415.  
  2416. int rename(source,dest)
  2417.                     /*******   FORMAL  PARAMETERS   *******/
  2418.      char      *source,        /* file to be renamed              */          *dest;        /* what to call it              */
  2419.  
  2420. {    /*** rename ***/
  2421.  
  2422.    if(link(source,dest))
  2423.       return(-1);
  2424.  
  2425.    if(unlink(source))
  2426.       return(-1);
  2427.  
  2428.    return(0);
  2429.  
  2430. }    /*** rename ***/
  2431.  
  2432. #endif
  2433.