home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / EFFO / forum16.lzh / SOFTWARE / C / TREE / tree.c < prev   
Text File  |  1991-05-06  |  15KB  |  579 lines

  1. /* Revision history (latest entry on top)
  2.  * CM = Christian Mahr
  3.  * HK = Helmut Kohl
  4.  *
  5.  * bugs:
  6.  * no different behavior if pxd = 1
  7.  *
  8.  * rev.        date    note
  9.  *----------------------------------------
  10.  * 1.23  HK  24.12.90  add option -l for depth control
  11.  * 1.22  HK  02.12.90  extended help message / add terminal type Gepard
  12.  *                     automatic detection of GEPARD terminal
  13.  *                     add unsorted printing
  14.  * 1.21  CM  17.06.90  last version of Christian Mahr of EFFO-Disk
  15.  *                     new version with sorted directory and special
  16.  *                     graphics for VT100 and ATARI ST/IBM
  17.  */
  18.  
  19.  
  20. #define VERSION "v1.23 - 24.12.90 / CM,HK"
  21.  
  22. #define DEBUG 1
  23.  
  24. #include <stdio.h>
  25. #include <modes.h>
  26. #include <direct.h>
  27. #include <dir.h>
  28. #include <sgstat.h>
  29. extern int errno;
  30.  
  31. #define BUFSIZE 256
  32. #define MAXLINE 256
  33. #define TRUE  1
  34. #define FALSE 0
  35. #define ERROR (-1)
  36.  
  37. /* div terminal types */
  38. #define ANY_TERM 0
  39. #define VT100    1
  40. #define ST       2
  41. #define GEPARD   3
  42.  
  43. /* aliases for termcap terminal types */
  44. char *vt100_alias[] =
  45. {
  46.    "VT100",
  47.    "vt100",
  48.    "vt100-80",
  49.    "VT220",
  50.    "vt220",
  51.    "vt300",
  52.    "vt300-80",                  /* more ... */
  53.    NULL
  54. };
  55.  
  56. char *st_alias[] =
  57. {
  58.    "st",
  59.    "st50",
  60.    "stlow",
  61.    NULL
  62. };
  63.  
  64. extern char *malloc();
  65.  
  66. #define DIRSIZ  sizeof(struct direct)
  67. #define DEF_NAME_FIELD 12
  68.  
  69. /* special character functions */
  70. #define INTRO 0
  71. #define RIGHT 1
  72. #define DOWN  2
  73. #define DOWN_RIGHT 3
  74. #define RIGHT_DOWN 4
  75. #define LAST_RIGHT 5
  76.  
  77. /* special character tables */
  78. static char *VT100_seq[] =
  79. {
  80.    "\x1b)0",
  81.    "\x0Eq\x0F",
  82.    "\x0Ex\x0F",
  83.    "\x0Et\x0F",
  84.    "\x0Ew\x0F",
  85.    "\x0Em\x0F",
  86. };
  87.  
  88. static char *any_terminal[] =
  89. {
  90.    "","-","|","|","+","`"
  91. };
  92.  
  93. static char *ST_seq[] =
  94. {
  95.    "", "\xC4", "\xB3", "\xC3", "\xC2", "\xC0"
  96. };
  97.  
  98. static char *gepard_terminal[] =
  99. {
  100.    "","\xB8","╣","»","\xBA","¼"
  101. };
  102.  
  103. char  **special_char ;
  104. char    left[MAXLINE];              /* output line up to the actual position */
  105. int     debug, show_files, sort_files, terminal_type, name_field;
  106.                                     /* option variables */
  107.  
  108. static char *cmds[] =
  109. {
  110.    "tree, ",VERSION,
  111.    "\nSyntax: tree [<directory>] [<opts>]\n",
  112.    "Function: print all subdirectories as a tree\n",
  113.    "          use special graphics for VT100 compatible terminals,\n",
  114.    "          IBM compatible printers, ATARI ST and Gepard systems.\n",
  115.    "Options: \n",
  116.    "   -f    print all files\n",
  117.    "   -u    unsorted printing\n",
  118.    "   -w=n  limit name field width to n characters (default: n=12)\n",
  119.    "   -l=n  limit tree depth to n level (max.:n = 40) (default: n=max)\n",
  120. #ifdef DEBUG
  121.    "   -d    internal debug flag\n",
  122. #endif
  123.    "   -a    force terminal type to be ANY_TERM (default)\n",
  124.    "   -v    force terminal type to be VT100\n",
  125.    "   -s    force terminal type to be ST/IBM\n",
  126.    "   -g    force terminal type to be Gepard\n",
  127.    ""
  128. };
  129.  
  130. #define MAXDEEP 40            /* absolute maximum directory depth */
  131. int pxd=0;                    /* pxd =0 look for
  132.                                       dir,owner executable,owner read attr. */
  133.                               /* pxd =1 look for dir,read attr. */
  134. char  *pelem[MAXDEEP+1];      /* path element pointers */
  135. direct char **pstk = pelem;   /* path element stack ptr */
  136. int     dir_depth;
  137. static direct int gpath;
  138.  
  139. /* ---------------------------------------- */
  140.  
  141. main (argc,argv)
  142. int  argc ;
  143. char *argv[];
  144.  
  145. {
  146.    char  *p;
  147.    int    argc1;                        /* duplicate counters/pointers */
  148.    char **argv1;
  149.    char   home[MAXLINE];                /* current home directory */
  150.    int    arg_finished;                 /* flag if an arg is finished by = */
  151.    int    done_once;                    /* flag if once done */
  152.  
  153.    debug = FALSE;                       /* defaults for options */
  154.    show_files = FALSE;
  155.    terminal_type = term_typ();          /* det. terminal type of stdout path */
  156.    name_field = DEF_NAME_FIELD;         /* set default field length */
  157.    dir_depth = MAXDEEP;                 /* set default directory depth */
  158.    sort_files = TRUE;
  159.  
  160.    argc1 = argc;                        /* scan arguments for options */
  161.    argv1 = &argv[0];
  162.    while (--argc1 > 0)
  163.    {
  164.       p = *++argv1;
  165.       if (*p++ == '-')
  166.       {
  167.          arg_finished = FALSE;
  168.          while (*p != '\0' && !arg_finished)
  169.          {
  170.             switch (tolower(*p++))
  171.             {
  172.                case 'a': terminal_type=ANY_TERM; break;
  173.                case 'v': terminal_type=VT100; break;
  174.                case 's': terminal_type=ST; break;
  175.                case 'g': terminal_type=GEPARD; break;
  176.                case 'd': debug++; break;
  177.                case 'f': show_files++; break;
  178.                case 'u': sort_files = FALSE; break;
  179.                case 'w': if (*p == '=')
  180.                          {
  181.                            name_field = atoi(&p[1]);
  182.                            arg_finished = TRUE;
  183.                          }
  184.                          break;
  185.                case 'l': if (*p == '=') 
  186.                          {
  187.                            dir_depth = atoi(&p[1]);
  188.                            arg_finished = TRUE;
  189.                            if ((dir_depth > MAXDEEP) | (dir_depth <= 0))
  190.                                dir_depth = MAXDEEP;
  191.                          }
  192.                          break;
  193.                default:  usage(); exit(0);
  194.             }
  195.          }
  196.       }
  197.    }
  198.    switch(terminal_type)
  199.    {
  200.       case VT100:     special_char = VT100_seq;  break;
  201.       case ST:        special_char = ST_seq;  break;
  202.       case GEPARD:    special_char = gepard_terminal;  break;
  203.       case ANY_TERM:
  204.       default:        special_char = any_terminal;  break;
  205.    }
  206.    printf("%s",special_char[INTRO]);
  207.  
  208.    done_once = FALSE;
  209.    while (--argc > 0)
  210.    {
  211.       p = *++argv;
  212.       if (p[0] != '-')
  213.       {
  214.          left[0] = '\0';                /* no chars left of actual pos. */
  215.          if (chdir(p) == ERROR)
  216.             non_fatal(errno,"can't chd to %s",p);
  217.          else
  218.          {
  219.             add_blanks(left,name_field);
  220.             print_to(p,name_field);
  221.             fflush(stdout);
  222.             directory(name_field-strlen(p));
  223.             if (chdir("..") == ERROR)
  224.                non_fatal(errno,"can't chd to ..");
  225.             done_once = TRUE;
  226.             printf("\n");
  227.          }
  228.       }
  229.    }
  230.    if (!done_once)
  231.    {                                      /* default current directory */
  232. #ifdef DEBUG
  233.       if (debug) printf ("No explicit directory specified\n");
  234. #endif
  235.       left[0] = '\0';
  236.       pd_str(home);             /* get home directory */
  237.       add_blanks(left,name_field);
  238.       print_to(home,name_field);
  239.       fflush(stdout);
  240.       directory(name_field-strlen(home));
  241.       printf("\n");
  242.    }
  243. }
  244.  
  245. /* ---------------------------------------- */
  246.  
  247. usage()
  248.  
  249. {
  250.    register char **p = cmds, **cmdsend = cmds+(sizeof cmds)/(sizeof(char **));
  251.  
  252.    while (p < cmdsend) fputs(*p++,stderr);
  253. }
  254.  
  255. /* ---------------------------------------- */
  256.  
  257. add_blanks(s,n)
  258. char *s;
  259. int n;
  260.  
  261. {
  262.    while (n-- > 0) strcat(s," ");
  263. };
  264.  
  265. /* ---------------------------------------- */
  266. /* print actual path
  267.    n  = field width
  268.    *s = actual path name
  269.  */
  270. print_to(s,n)
  271. char *s;
  272. int n;
  273.  
  274. {
  275.    int i,l;
  276.  
  277.    l=strlen(s);
  278.    if (n < l) l=n;
  279.    for (i = 0; i < l ; i++)
  280.       putc(s[i],stdout);
  281. };
  282.  
  283. /* ----------------------------------------
  284.  * sort POINTERS for dir entry    */
  285.  
  286. sort_dir(db,n)
  287. struct direct *db[];              /* pointer array to dir entries */
  288. int n;
  289.  
  290. {
  291.    register int gap,i,j;
  292.    register struct direct *temp;
  293.  
  294.    if (sort_files == TRUE)
  295.    {
  296.      for (gap = n/2; gap > 0; gap /= 2)
  297.      {
  298.        for (i = gap; i < n ; i++)
  299.        {
  300.          for (j = i-gap ; j >= 0; j -= gap)
  301.          {
  302.            if (strcmp(db[j]->d_name,db[j+gap]->d_name)<=0)  break;
  303.            temp=db[j+gap];
  304.            db[j+gap]=db[j];
  305.            db[j]=temp;
  306.          }
  307.        }
  308.      }
  309.    }
  310. }
  311.  
  312. /* ---------------------------------------- */
  313.  
  314. int directory (horiz_line)              /* size of all files in "name" */
  315. int horiz_line;     /* max. field with - actual field length */
  316.  
  317. {
  318.    int    i,j,cur_column,do_dir;
  319.    int    db_size,db_entries,entries_read;
  320.    char  *cur_dir;
  321.    struct direct *p,*dba,**db;
  322.    struct _dirdesc *dirp ;
  323.  
  324.    printf(" ");                         /* blank AFTER name */
  325.    add_blanks(left,1);
  326.    if ( (dirp = opendir(".")) == NULL) return(ERROR);
  327.    if ( (db_size = _gs_size(dirp->dd_fd)) == ERROR) return(ERROR);
  328.    db_entries = db_size / sizeof(struct dirent);    /* size in file !!!!! */
  329. #ifdef DEBUG
  330.    if (debug)
  331.       printf("db_size= %d, db_entries= %d, dir_depth= %d\n",db_size,db_entries,dir_depth);
  332. #endif
  333.    if ((db = (struct direct **) calloc(db_entries,4)) == NULL)  /* pointers */
  334.       fatal(errno,"can't get enough memory");
  335.    if ((dba= (struct direct *) calloc(db_entries,DIRSIZ)) == NULL)
  336.       fatal(errno,"can't get enough memory");
  337.    i=0;
  338.    while ( p=readdir(dirp) )
  339.    {
  340.       if ( p->d_name[0] != '.')
  341.       {
  342.          _strass( (db[i] = &dba[i]), p, DIRSIZ);  /* store in array */
  343. #ifdef DEBUG
  344.          if (debug) printf("db[%d]->d_name=%s\n",i,db[i]->d_name);
  345. #endif
  346.          if (show_files || (access(db[i]->d_name,S_IFDIR)==0)) i++;
  347.       }
  348.       if (i > db_entries) fatal (0," to many entries in dir ");
  349.    }
  350.    entries_read = i;
  351. #ifdef DEBUG
  352.    if (debug) printf("entries_read =%d\n",entries_read);
  353. #endif
  354.    sort_dir(db,entries_read);
  355.    for (i=0; i < entries_read; i++)
  356.    {
  357.       cur_dir = db[i]->d_name;
  358.       if (i == 0)                               /* are we at first entry ? */
  359.       {
  360.          j = (entries_read == 1)?RIGHT:RIGHT_DOWN;
  361.          while (horiz_line-- > 0) printf("%s",special_char[RIGHT]);
  362.       }
  363.       else
  364.       {
  365.          j = (i == entries_read-1) ? LAST_RIGHT:DOWN_RIGHT; /* `- or |- */
  366.          printf("\n%s",left);
  367.       }
  368.       printf("%s%s ",special_char[j],special_char[RIGHT]);
  369.       print_to(cur_dir,name_field);
  370.       fflush(stdout);
  371.       cur_column = strlen(left);
  372.       if (j == LAST_RIGHT || j == RIGHT)
  373.          strcat(left," ");
  374.       else
  375.          strcat(left,special_char[DOWN]);
  376.       add_blanks(left,name_field+2);
  377.       if (show_files)
  378.          do_dir = (access(cur_dir,S_IFDIR)==0);
  379.       else
  380.          do_dir = TRUE;                         /* not necessary to ask */
  381.       if (do_dir)
  382.       {
  383.          if (chdir(cur_dir) == ERROR)
  384.          {
  385.             non_fatal(errno,"can't chd to %s",cur_dir);
  386.             return (ERROR);
  387.          }
  388.          if (dir_depth-- > 1)  directory (name_field-strlen(cur_dir));
  389.          dir_depth++;
  390.          if (chdir("..") == ERROR)
  391.          {
  392.             non_fatal(errno,"can't chd to ..");
  393.             return (ERROR);
  394.          }
  395.       }
  396.       left[cur_column]='\0';
  397.    }
  398.    closedir(dirp);
  399.    free (db);
  400.    free (dba);
  401.    return(0);                        /* no error */
  402. }
  403.  
  404. /* ----------------------------------------
  405.  * print information and exit    */
  406.  
  407. non_fatal (err,f,p1,p2,p3)
  408. int err;
  409. char *f;
  410. int p1,p2,p3;
  411.  
  412. {
  413.    fflush(stdout);
  414.    fprintf(stderr,"tree: error, ");
  415.    fprintf(stderr,f,p1,p2,p3);
  416.    fprintf(stderr,"\n");
  417.    print_error(err);
  418.    fflush(stderr);
  419. }
  420.  
  421. /* ---------------------------------------- */
  422.  
  423. fatal (err,f,p1,p2,p3)
  424. int err;
  425. char *f;
  426. int p1,p2,p3;
  427.  
  428. {
  429.    non_fatal (err,f,p1,p2,p3);
  430.    exit(err);
  431. }
  432.  
  433. /* ----------------------------------------
  434.    print error routine ....
  435.    serach for error message file almost 'everywhere'
  436.  */
  437.  
  438. print_error(err_stat)
  439. int  err_stat;
  440.  
  441. {
  442.    register int    errmsg_path;         /* path no */
  443.    register char   **name_poi;
  444.  
  445.    static char *err_files[] =
  446.    {
  447.       "/dd/sys/errmsg",
  448.       "/h0/sys/errmsg",
  449.       "/d0/sys/errmsg",
  450.       ""                                /* delimit list */
  451.    };
  452.  
  453.    if (err_stat==0) return(0);
  454.    name_poi=err_files;
  455.    do
  456.    {
  457.       errmsg_path = open (*name_poi++,S_IREAD);      /* try to open error file */
  458.    }
  459.    while (errmsg_path==ERROR && **name_poi);
  460.    if (errmsg_path==ERROR)                /* if unsuccessfull, number only */
  461.       prerr(0,err_stat);
  462.    else
  463.       prerr(errmsg_path,err_stat);      /* print the error message */
  464.    close(errmsg_path);                  /* close the error message path */
  465. }
  466.  
  467. /* ---------------------------------------- */
  468.  
  469. opndir()
  470.  
  471. {
  472.    int dpath, mode;
  473.  
  474.    mode = pxd ? S_IFDIR|S_IEXEC|S_IREAD : S_IFDIR|S_IREAD;
  475.    if ((dpath = open(".",mode)) == ERROR)
  476.       exit(_errmsg(errno,"can't open current directory. "));
  477.    return dpath;
  478. }
  479.  
  480. /* ---------------------------------------- */
  481.  
  482. getcwd()
  483.  
  484. {
  485.    register char *dir;
  486.    char dots[MAXDEEP+2];
  487.  
  488.    for(dir=dots; dir<(dots+(sizeof dots)-1); ++dir)
  489.       *dir='.';
  490.    *dir='\0';
  491.    dir-=2;      /* point to ".." */
  492.    gpath=opndir();
  493.    getcwds(dir);
  494.    close(gpath);
  495. }
  496.  
  497. /* ---------------------------------------- */
  498.  
  499. getcwds(dir)
  500. char *dir;
  501.  
  502. {
  503.    static char devname[34] = {'/'};
  504.    struct dirent dirbuf;
  505.    register long cfds,pfds,nfds;
  506.    register char *p=devname+1,*fn=dirbuf.dir_name;
  507.    extern char* ebrk();
  508.  
  509.    lseek(gpath,nfds=0l,0);
  510.    read(gpath,&dirbuf,sizeof dirbuf);
  511.    pfds=dirbuf.dir_addr;
  512.    read(gpath,&dirbuf,sizeof dirbuf);
  513.    if((cfds = dirbuf.dir_addr) == pfds)
  514.    {
  515.       if(_gs_devn(gpath,p)==ERROR)
  516.          exit(_errmsg(errno,"can't get device name. "));
  517.       *pstk++ = devname;
  518.       while(*p++>0);
  519.    }
  520.    else
  521.    {
  522.       close(gpath);
  523.       if ((gpath = open(dir,
  524.                    pxd ? S_IREAD|S_IFDIR|S_IEXEC : S_IREAD|S_IFDIR)) == ERROR)
  525.          exit(_errmsg(errno,"can't open \"%s\". ",dir));
  526.       lseek(gpath,nfds=(sizeof dirbuf) * 2,0);
  527.       do
  528.       {
  529.          read(gpath,&dirbuf,sizeof dirbuf);
  530.       }
  531.       while(cfds != dirbuf.dir_addr);
  532.       getcwds(--dir);
  533.       if ((int)(*pstk++ = (p = ebrk(sizeof dirbuf.dir_name))) == ERROR)
  534.          exit(_errmsg(errno,"can't get memory. "));
  535.       while((*p++ = *fn++) > 0);
  536.    }
  537.    p[-1] &= 0x7f;
  538.    *p='\0';
  539. }
  540.  
  541. /* ---------------------------------------- */
  542.  
  543. pd_str(showp)
  544. char *showp;
  545.  
  546. {
  547.    register char **p,*sp,*pp;
  548.    getcwd();
  549.    for(sp=showp,p=pelem; p<pstk; ++p)
  550.    {
  551.       for(pp=*p; *pp; )
  552.          *sp++ = *pp++;
  553.       *sp++ = '/';
  554.    }
  555.    *--sp = '\0';
  556. }
  557.  
  558. /* ----------------------------------------
  559.    determine terminal type from environment var  */
  560.  
  561. int term_typ()
  562.  
  563. {
  564.    char *p;
  565.    extern char *getenv();
  566.    char **tt;
  567.  
  568.    p = getenv("TERM");
  569.    if (p)
  570.    {
  571.       for (tt = vt100_alias; *tt; tt++)
  572.          if (strcmp(p,*tt)==0) return (VT100);
  573.       for (tt = st_alias; *tt; tt++)
  574.          if (strcmp(p,*tt)==0) return (ST);
  575.       if (strcmp (p,"Gepard")==0) return (GEPARD);
  576.    }
  577.    return (ANY_TERM);
  578. }
  579.