home *** CD-ROM | disk | FTP | other *** search
/ Audio Version 4.94 / audioversion4.94knowledgemediaresourcelibraryoctober1994.iso / amiga / utils / exp_iv / files.c < prev    next >
C/C++ Source or Header  |  1991-05-16  |  12KB  |  583 lines

  1. /* files.c */
  2.  
  3. /* songs management, mainly some iterators
  4.  */
  5.  
  6. /* 
  7.  * $Author: Espie $
  8.  * $Date: 91/05/16 15:05:01 $
  9.  * $Revision: 1.8 $
  10.  * $Log:    files.c,v $
  11.  * Revision 1.8  91/05/16  15:05:01  Espie
  12.  * *** empty log message ***
  13.  * 
  14.  * Revision 1.7  91/05/12  19:53:05  Espie
  15.  * Corrected the non-freed icons problem.
  16.  * 
  17.  * Revision 1.6  91/05/12  15:56:53  Espie
  18.  * Bugs mostly corrected.
  19.  * 
  20.  * Revision 1.5  91/05/11  14:58:02  Espie
  21.  * Corrected an auto-cleanup problem.
  22.  * 
  23.  * Revision 1.4  91/05/10  00:04:19  Espie
  24.  * Added albums support. Directories missing, not sure
  25.  * I will add it...
  26.  * 
  27.  * Revision 1.3  91/05/09  17:35:17  Espie
  28.  * Support for appwindow, mk_wbarg optimization.
  29.  * 
  30.  * Revision 1.2  91/05/08  18:33:46  Espie
  31.  * Added check_abort() for loooong runs.
  32.  * Added support for arp pattern-matching... need checking that arp is around.
  33.  * Does enter subdirectories too !
  34.  * 
  35.  * Revision 1.1  91/05/08  15:50:32  Espie
  36.  * Initial revision
  37.  * 
  38.  *
  39.  */
  40.  
  41. #include <exec/types.h>
  42. #include <dos/dos.h>
  43. #include <exec/memory.h>
  44. #include <workbench/startup.h>
  45. #include <workbench/workbench.h>
  46. #include <string.h>
  47. #include <stddef.h>
  48. #include <custom/cleanup.h>
  49. #include <proto/exec.h>
  50. #include <proto/dos.h>
  51. #include <proto/icon.h>
  52. #include <stdio.h>
  53.  
  54. #include <libraries/arpbase.h>
  55. #include <proto/arp.h>
  56.  
  57. #include "song.h"
  58. #include "public_play.h"
  59.  
  60. void *malloc();
  61.     
  62. #include "proto.h"
  63.  
  64. LOCAL struct WBStartup *msg;
  65. LOCAL char **tools;
  66.  
  67. /***
  68.  *
  69.  *        Tooltypes management
  70.  *
  71.  ***/
  72.  
  73. /* get_arg(tools, tooltype, def): reads the tooltype in the tools array,
  74.  * as a numerical argument, with def as a default value.
  75.  */
  76.  
  77. int get_arg(char **tools, char *tooltype, int def)
  78.     {
  79.     int val;
  80.     char *string = NULL;
  81.         if (tools)
  82.             string = FindToolType(tools, tooltype);
  83.         if (string && sscanf(string, "%d", &val) == 1)
  84.             return val;
  85.         else
  86.             return def;
  87.     }
  88.  
  89. /* same thing with default tools */
  90.  
  91. int do_get_arg(char *tooltype, int def)
  92.     {
  93.         return get_arg(tools, tooltype, def);
  94.     }
  95.     
  96.  
  97. /* map_arg: gives a numerical argument from a limited set
  98.  * of strings values
  99.  */
  100. int map_arg(char **tools, char *tooltype, char **names, int def)
  101.     {
  102.     int val;
  103.     char *string = NULL;
  104.         if (tools)
  105.             string = FindToolType(tools, tooltype);
  106.         if (string)
  107.         {
  108.                 for (val = 0; names; val++, names++)
  109.                     if (MatchToolValue(string, *names))
  110.                         return val;
  111.             }
  112.         return def;
  113.     }    
  114.  
  115. int do_map_arg(char *tooltype, char **names, int def)
  116.     {
  117.         return map_arg(tools, tooltype, names, def);
  118.     }
  119.  
  120. /* exist_tooltype(tools, tooltype): checks if tooltype exists among tools
  121.  */
  122. BOOL exist_tooltype(char **tools, char *tooltype)
  123.     {
  124.         if (!tools)
  125.             return NULL;
  126.         return (FindToolType(tools, tooltype) != NULL);
  127.     }
  128.  
  129.  
  130.  
  131. /***
  132.  *
  133.  *        Iterators.
  134.  *        Every argument is managed as an iterator
  135.  *        you can resume later. This makes a nice
  136.  *        framework for multiple arguments, pattern-matching,
  137.  *        albums, directory traversal...
  138.  *
  139.  ***/
  140.  
  141.  
  142.  
  143.  
  144. enum it_tag {CLI_list, Match_list, Dir_list, WB_list, Album, Empty};
  145.  
  146. struct CLI_it
  147.     {
  148.         int number;
  149.         int index;
  150.         char **names;
  151.     };
  152.  
  153. struct WB_it
  154.     {
  155.         int number;
  156.         int index;
  157.         struct WBArg *args;
  158.     };
  159.     
  160.  
  161. #define MAX_LENGTH 400
  162.  
  163. struct Album_it
  164.     {
  165.         FILE *f;
  166.         char *pbuf;
  167.         char buffer[MAX_LENGTH];
  168.     };
  169.  
  170. struct Match_it
  171.     {
  172.         struct AnchorPath anchor;
  173.         BYTE suppl_buffer[MAX_LENGTH];
  174.     };
  175.     
  176.  
  177. /*
  178.  
  179. struct Dir_List
  180.     {
  181.         struct FileInfoBlock examiner;
  182.     };
  183.  
  184.  */    
  185.     
  186. /* be careful of the fields you use, the FileInfoBlock/AnchorPath
  187.  * must be longword aligned !
  188.  */
  189.  
  190. struct iterator
  191.     {
  192.         enum it_tag tag;
  193.         struct iterator *next;
  194.         CLEAN auto_clean;
  195.         BPTR save_lock;
  196.         struct DiskObject *currenticon;
  197.         BOOL cd;
  198.         BOOL ownlock;
  199.         union
  200.             {
  201.                 struct CLI_it CLI;
  202.                 struct WB_it WB;
  203.                 struct Album_it Album;
  204.                 struct Match_it Match;
  205.             } u;
  206.     };
  207.     
  208.  
  209.  
  210. /***
  211.  *
  212.  *        Support functions
  213.  *
  214.  ***/
  215.  
  216.  
  217. LOCAL void free_last_icon(struct iterator *it)
  218.     {
  219.         if (it->currenticon)
  220.             FreeDiskObject(it->currenticon);
  221.         it->currenticon = NULL;
  222.     }
  223.     
  224. /* where do we get the tooltypes from anyway
  225.  */    
  226. char **grab_tooltypes(struct iterator *it, char *arg)
  227.     {
  228.     struct DiskObject *icon;
  229.         if (icon_around())
  230.             {
  231.                 icon = GetDiskObject(arg);
  232.                 if (icon)
  233.                     {
  234.                         if (it)
  235.                             {
  236.                                 free_last_icon(it);
  237.                                 it->currenticon = icon;
  238.                             }
  239.                         else
  240.                             ToClean(FreeDiskObject, icon);
  241.                         return icon->do_ToolTypes;
  242.                     }
  243.             }
  244.         return NULL;
  245.     }
  246. /* we need doFreeAnchorChain 'cause FreeAnchorChain exists only as a pragma
  247.  */  
  248.  
  249. LOCAL void doFreeAnchorChain(struct AnchorPath *ap)
  250.     {
  251.         FreeAnchorChain(ap);
  252.     }
  253.  
  254.  
  255. /* getline(buffer, bufsize, f): read a line from file f into buffer,
  256.  * upto bufsize characters. Puts a \0 at the end of line in place of
  257.  * the \n. The last line may end without a \n.
  258.  * If the line is too long, remaining characters are skipped.
  259.  * returns the strlen of buffer, or -1 if the line is too long.
  260.  * A NULL f is allowed, in that case, the call will never succeed.
  261.  * 
  262.  * It is the responsibility of the client to close that file.
  263.  */
  264.  
  265. LOCAL int getline(char *buffer, int bufsize, FILE *f)
  266.     {
  267.     int i, c;
  268.         if (!f)
  269.             return 0;
  270.         for (i = 0; i < bufsize; i++)
  271.             {
  272.                 c = fgetc(f);
  273.                 if (c == EOF)
  274.                     {
  275.                         buffer[i] = '\0';
  276.                         return i;
  277.                     }
  278.                 if (c == '\n')
  279.                     {
  280.                         buffer[i] = '\0';
  281.                         return i;
  282.                     }
  283.                 buffer[i] = c;
  284.             }
  285.         while((c=fgetc(f)) != '\n' && c != EOF);
  286.         return (-1);
  287.     }
  288.  
  289. /* The iterators need to change dir in an effective way.
  290.  */
  291. LOCAL void un_dir(struct iterator *it)
  292.     {
  293.         if (it->cd)
  294.             {
  295.                 if (it->ownlock)
  296.                     UnLock(CurrentDir(it->save_lock));
  297.                 else
  298.                     CurrentDir(it->save_lock);
  299.             }
  300.         it->cd = FALSE;
  301.         it->ownlock = FALSE;
  302.     }
  303.  
  304. LOCAL void change_dir(struct iterator *it, BPTR new_dir)
  305.     {
  306.         un_dir(it);
  307.         it->save_lock = CurrentDir(new_dir);
  308.         it->cd = TRUE;
  309.     }
  310.  
  311. /* iterator creation. An iterator is always the son of another,
  312.  * except the root, of course. new_iterator() initializes all
  313.  * relevant fields to reasonable values.
  314.  */
  315.      
  316. LOCAL struct iterator *new_iterator(struct iterator *father)
  317.     {
  318.     struct iterator *new;
  319.             /* this is an aligned structure */
  320.         new = AllocMem(sizeof(struct iterator), MEMF_ANY);
  321.         if (!new)
  322.             return NULL;
  323.         new->auto_clean = AllocClean(NIL);
  324.         ToClean2L(new->auto_clean, FreeMem, new, sizeof(struct iterator));
  325.         new->ownlock = FALSE;
  326.         new->cd = FALSE;
  327.         new->next = father;
  328.         new->currenticon = NULL;
  329.         ToCleanL(new->auto_clean, un_dir, new);
  330.         ToCleanL(new->auto_clean, free_last_icon, new);
  331.         return new;
  332.     }
  333.  
  334. /* insert_iterator(it): returns a new iterator inserted as a son
  335.  * of it, so executed before we resume it. Note that the address of
  336.  * it is necessary.
  337.  */
  338.   
  339. LOCAL struct iterator *insert_iterator(struct iterator **head)
  340.     {
  341.     struct iterator *base;
  342.         base = new_iterator(*head);
  343.         *head = base;
  344.         return base;
  345.     }
  346.  
  347. /* creation of common iterator types
  348.  */
  349. LOCAL struct iterator *mk_CLI_iterator(struct iterator **head, 
  350.         int argc, char **argv)
  351.     {
  352.     struct iterator *new;
  353.         new = insert_iterator(head);
  354.         new->tag = CLI_list;
  355.         new->u.CLI.names = argv;
  356.         new->u.CLI.number = argc;
  357.         new->u.CLI.index = 0;
  358.         return new;
  359.     }
  360.     
  361. LOCAL struct iterator *mk_WB_iterator(struct iterator **head,
  362.         int argn, struct WBArg *argarray)
  363.     {
  364.     struct iterator *new;
  365.         new = insert_iterator(head);
  366.         new->tag = WB_list;
  367.         new->u.WB.args = argarray;
  368.         new->u.WB.number = argn;
  369.         new->u.WB.index = 0;
  370.         return new;
  371.     }
  372.  
  373. /* the arp pattern matcher... */
  374. LOCAL char *match_next(struct AnchorPath *ap)
  375.     {
  376.     int res;
  377.         forever
  378.             {
  379.                 res = FindNext(ap);
  380.                 if (res)
  381.                     return NULL;
  382.                 if (ap->ap_Info.fib_DirEntryType < 0)
  383.                     return ap->ap_Buf;
  384.                 if (!ap->ap_Flags & APF_DidDir)
  385.                     ap->ap_Flags |= APF_DoDir;
  386.             }
  387.     }
  388.  
  389. /* ...and the start of it */    
  390. LOCAL char *match_CLI(struct iterator **head)
  391.     {
  392.     struct iterator *first, *new;
  393.         first = *head;
  394.         forever
  395.             {
  396.                 if (first->u.CLI.index >= first->u.CLI.number)
  397.                     return NULL;
  398.                 if (requester_type() != ARP)
  399.                     return first->u.CLI.names[first->u.CLI.index++];
  400.                 else
  401.                     {
  402.                     struct AnchorPath *ap;
  403.                     int res;
  404.                         new = insert_iterator(head);
  405.                         new->tag = Match_list;
  406.                         ap = &new->u.Match.anchor;
  407.                             ap->ap_BreakBits = 0;
  408.                             ap->ap_Flags = APF_DoWild;
  409.                             ap->ap_StrLen = MAX_LENGTH;
  410.                         ToCleanL(new->auto_clean, doFreeAnchorChain, ap);
  411.                         res = FindFirst(first->u.CLI.names[first->u.CLI.index++], ap);
  412.                         if (!res)
  413.                             {
  414.                                 if (ap->ap_Info.fib_DirEntryType < 0)
  415.                                     return ap->ap_Buf;
  416.                                 else
  417.                                     {
  418.                                         ap->ap_Flags |= APF_DoDir;
  419.                                         return match_next(ap);
  420.                                     }
  421.                             }
  422.                     }
  423.             }
  424.     }    
  425.  
  426. /* how to restart an existing iterator */
  427.  
  428. LOCAL char *resume_iterator(struct iterator **head)
  429.     {
  430.     struct iterator *new, *first;
  431.     struct WBArg *temp;
  432.         first = *head;
  433.         switch(first->tag)
  434.             {
  435.             case CLI_list:
  436.                 return match_CLI(head);
  437.             case WB_list:
  438.                 if (first->u.WB.index >= first->u.WB.number)
  439.                     return NULL;
  440.                 temp = first->u.WB.args + first->u.WB.index++;
  441.                 if (temp->wa_Lock)
  442.                     change_dir(first, temp->wa_Lock);
  443.                 return temp->wa_Name;
  444.             case Match_list:
  445.                 return match_next(&first->u.Match.anchor);
  446.             case Album:
  447.                 if (!getline(first->u.Album.pbuf, MAX_LENGTH, first->u.Album.f))
  448.                     {
  449.                         /* temporary kludge */
  450.                         if (first->u.Album.f)
  451.                             {
  452.                                 fclose(first->u.Album.f);
  453.                                 first->u.Album.f = NULL;
  454.                             }
  455.                         return NULL;
  456.                     }
  457.                 else
  458.                     {
  459.                         new = mk_CLI_iterator(head, 1, &(first->u.Album.pbuf));
  460.                         return match_CLI(head);
  461.                     }
  462.             }
  463.     }
  464.  
  465. LOCAL void delete_first(struct iterator **head)
  466.     {
  467.     struct iterator *next;
  468.         next = (*head)->next;
  469.         CleanUp((*head)->auto_clean);
  470.         *head = next;
  471.     }
  472.     
  473. /* basic stuff about iterators. Still needs a special test
  474.  * about albums.
  475.  */                        
  476. LOCAL char *do_next_song(struct iterator **head)
  477.     {
  478.     char *temp;
  479.         forever
  480.             {
  481.                 check_abort();
  482.                 if (!*head)
  483.                     return NULL;
  484.                 if (temp = resume_iterator(head))
  485.                     return temp;
  486.                 else
  487.                     delete_first(head);
  488.             }
  489.     }
  490.  
  491. /* basic code to deal with albums. Once we've detected an album,
  492.  * we can insert it.
  493.  */
  494. LOCAL void insert_album(struct iterator **head, char *arg)
  495.     {
  496.     struct iterator *base;
  497.         base = insert_iterator(head);
  498.         base->tag = Album;
  499.         base->u.Album.pbuf = base->u.Album.buffer;
  500.         base->u.Album.f = fopen(arg, "r");
  501.         /* I can't autoclean this stuff: conflict with Lattice
  502.             ToCleanL(base->auto_clean, fclose, base->u.Album.f);
  503.          */
  504.     }
  505.  
  506.  
  507. char *next_song(struct iterator **head, BOOL req)
  508.     {
  509.     char *test;
  510.     struct iterator *new;
  511.     static struct WBArg holder;
  512.     forever
  513.         {
  514.             test = do_next_song(head);
  515.             if (test)
  516.                 {
  517.                     if (exist_tooltype(grab_tooltypes(*head, test), "ALBUM"))
  518.                         {
  519.                             insert_album(head, test);
  520.                         }    
  521.                     else
  522.                         return test;
  523.                 }
  524.             else
  525.                 {
  526.                     if (req && query_name("Module to play", &holder))
  527.                         {
  528.                             new = mk_WB_iterator(head, 1, &holder);
  529.                             new->ownlock = TRUE;
  530.                         }
  531.                     else
  532.                         return NULL;
  533.                 }
  534.         }
  535.     }                    
  536.  
  537.  
  538. /* init_iterator(): builds an initial iterator from the arguments
  539.  * supplied by the user.
  540.  */
  541. LOCAL struct iterator *zero;
  542.  
  543. LOCAL struct iterator *init_iterator(int argc, char **argv)
  544.     {
  545.     struct iterator *base;
  546.         zero = NULL;
  547.         if (argc)
  548.             {
  549.                 msg = NULL;
  550.                 base = mk_CLI_iterator(&zero, argc, argv);
  551.             }
  552.         else
  553.             {
  554.                 msg = (struct WBStartup *)argv;
  555.                 base = mk_WB_iterator(&zero, msg->sm_NumArgs, msg->sm_ArgList);
  556.             }
  557.         return base;
  558.     }
  559.  
  560. /* insert_args: adds new songs given to the appwindow.
  561.  */
  562. void insert_args(struct iterator **head, struct AppMessage *msg)
  563.     {
  564.     struct iterator *new;
  565.         new = mk_WB_iterator(head, msg->am_NumArgs, msg->am_ArgList);
  566.         ToCleanL(new->auto_clean, ReplyMsg, msg);
  567.     }
  568.  
  569.  
  570. /* setup_arguments: initial setup for everything
  571.  */
  572. struct iterator *setup_arguments(int argc, char **argv)
  573.     {
  574.     struct iterator *result;
  575.         result = init_iterator(argc, argv);
  576.         if (argc)
  577.             tools = argv; /* grab_tooltypes(NIL, next_song(&result, FALSE)); */
  578.         else
  579.             tools = grab_tooltypes(NIL, next_song(&result, FALSE));
  580.         return result;
  581.     }
  582.     
  583.