1 /*
2     opcode.c:
3 
4     Copyright (C) 1997 John ffitch
5               (C) 2005 Istvan Varga
6 
7     This file is part of Csound.
8 
9     The Csound Library is free software; you can redistribute it
10     and/or modify it under the terms of the GNU Lesser General Public
11     License as published by the Free Software Foundation; either
12     version 2.1 of the License, or (at your option) any later version.
13 
14     Csound is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU Lesser General Public License for more details.
18 
19     You should have received a copy of the GNU Lesser General Public
20     License along with Csound; if not, write to the Free Software
21     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22     02110-1301 USA
23 */
24 
25                                 /* OPCODE.C */
26                                 /* Print opcodes in system */
27 
28                                 /* John ffitch -- 26 Jan 97 */
29                                 /*  4 april 02 -- ma++ */
30                                 /*  restructure to retrieve externally  */
31                                 /* And suppressing deprecated Oct 2015 -- JPff */
32 #include "csoundCore.h"
33 #include <ctype.h>
34 #include "interlocks.h"
35 
opcode_cmp_func(const void * a,const void * b)36 static int opcode_cmp_func(const void *a, const void *b)
37 {
38     opcodeListEntry *ep1 = (opcodeListEntry*) a;
39     opcodeListEntry *ep2 = (opcodeListEntry*) b;
40     int             retval;
41 
42     if ((retval = strcmp(ep1->opname, ep2->opname)) != 0)
43       return retval;
44     if ((retval = strcmp(ep1->outypes, ep2->outypes)) != 0)
45       return retval;
46     if ((retval = strcmp(ep1->intypes, ep2->intypes)) != 0)
47       return retval;
48     if (ep1 < ep2)
49       return -1;
50     if (ep1 > ep2)
51       return 1;
52 
53     return 0;
54 }
55 
56 /**
57  * Gets an alphabetically sorted list of all opcodes.
58  * Should be called after externals are loaded by csoundCompile().
59  * Returns the number of opcodes, or a negative error code on failure.
60  * Make sure to call csoundDisposeOpcodeList() when done with the list.
61  */
62 
csoundNewOpcodeList(CSOUND * csound,opcodeListEntry ** lstp)63 PUBLIC int csoundNewOpcodeList(CSOUND *csound, opcodeListEntry **lstp)
64 {
65     void    *lst = NULL;
66     OENTRY  *ep;
67     char    *s;
68     size_t  nBytes = (size_t) 0;
69     int     i, cnt = 0;
70     CONS_CELL *head, *items, *temp;
71 
72     (*lstp) = NULL;
73     if (UNLIKELY(csound->opcodes == NULL))
74       return -1;
75 
76     head = items = cs_hash_table_values(csound, csound->opcodes);
77 
78     /* count the number of opcodes, and bytes to allocate */
79     while (items != NULL) {
80       temp = items->value;
81       while (temp != NULL) {
82         ep = temp->value;
83         if (ep->opname != NULL &&
84             ep->opname[0] != '\0' && isalpha(ep->opname[0]) &&
85             ep->outypes != NULL && ep->intypes != NULL) {
86           cnt++;
87 #ifdef JPFF
88           if (strchr(ep->intypes, 'x'))
89             printf("%s, type %d %s -> %s\n", ep->opname, ep->thread,
90                    ep->intypes, ep->outypes);
91           /* else if (ep->thread==5 */
92           /*   printf("%s, type 6 %s -> %s\n", ep->opname, */
93           /*          ep->intypes, ep->outypes); */
94 #endif
95           nBytes += sizeof(opcodeListEntry);
96           for (i = 0; ep->opname[i] != '\0' && ep->opname[i] != '.'; i++);
97           nBytes += (size_t) i;
98           nBytes += strlen(ep->outypes);
99           nBytes += strlen(ep->intypes);
100           nBytes += 3;    /* for null characters */
101         }
102         temp = temp->next;
103       }
104       items = items->next;
105     }
106     nBytes += sizeof(opcodeListEntry);
107     /* allocate memory for opcode list */
108     lst = csound->Malloc(csound, nBytes);
109     if (UNLIKELY(lst == NULL))
110       return CSOUND_MEMORY;
111     (*lstp) = (opcodeListEntry*) lst;
112     /* store opcodes in list */
113     items = head;
114     s = (char*) lst + ((int) sizeof(opcodeListEntry) * (cnt + 1));
115     cnt = 0;
116     while (items != NULL) {
117         temp = items->value;
118         while (temp != NULL) {
119           ep = temp->value;
120 
121           if (ep->opname != NULL &&
122               ep->opname[0] != '\0' && isalpha(ep->opname[0]) &&
123               ep->outypes != NULL && ep->intypes != NULL) {
124             for (i = 0; ep->opname[i] != '\0' && ep->opname[i] != '.'; i++)
125               s[i] = ep->opname[i];
126             s[i++] = '\0';
127             ((opcodeListEntry*) lst)[cnt].opname = s;
128             s += i;
129             strcpy(s, ep->outypes);
130             ((opcodeListEntry*) lst)[cnt].outypes = s;
131             s += ((int) strlen(ep->outypes) + 1);
132 #ifdef JPFF
133             if (strlen(ep->outypes)==0) printf("***potential WI opcode %s\n", ep->opname);
134 #endif
135             strcpy(s, ep->intypes);
136             ((opcodeListEntry*) lst)[cnt].intypes = s;
137             s += ((int) strlen(ep->intypes) + 1);
138             ((opcodeListEntry*) lst)[cnt].flags = ep->flags;
139             //if (ep->flags&_QQ) printf("DEPRICATED: %s\n", ep->opname);
140             //if (ep->flags&_QQ) *deprec++;
141             cnt++;
142           }
143           temp = temp->next;
144         }
145       items = items->next;
146     }
147     ((opcodeListEntry*) lst)[cnt].opname = NULL;
148     ((opcodeListEntry*) lst)[cnt].outypes = NULL;
149     ((opcodeListEntry*) lst)[cnt].intypes = NULL;
150     ((opcodeListEntry*) lst)[cnt].flags = 0;
151 
152     cs_cons_free(csound, head);
153 
154     /* sort list */
155     qsort(lst, (size_t) cnt, sizeof(opcodeListEntry), opcode_cmp_func);
156 
157     /* return the number of opcodes */
158     return cnt;
159 }
160 
csoundDisposeOpcodeList(CSOUND * csound,opcodeListEntry * lst)161 PUBLIC void csoundDisposeOpcodeList(CSOUND *csound, opcodeListEntry *lst)
162 {
163     csound->Free(csound, lst);
164 }
165 
list_opcodes(CSOUND * csound,int level)166 void list_opcodes(CSOUND *csound, int level)
167 {
168     opcodeListEntry *lst;
169     const char      *sp = "                    ";   /* length should be 20 */
170     int             j, k;
171     int             cnt, len = 0, xlen = 0;
172     int             count = 0;
173 
174     cnt = csoundNewOpcodeList(csound, &lst);
175     if (UNLIKELY(cnt <= 0)) {
176       csound->ErrorMsg(csound, Str("Error creating opcode list"));
177       csoundDisposeOpcodeList(csound, lst);
178       return;
179     }
180 
181     for (j = 0, k = -1; j < cnt; j++) {
182       if ((level&1) == 0) {                         /* Print in 4 columns */
183         if (j > 0 && strcmp(lst[j - 1].opname, lst[j].opname) == 0)
184           continue;
185         if ((level&2)==0 && ((lst[j].flags&_QQ) !=0)) {
186           //printf("dropping %s\n", lst[j].opname);
187           continue;
188         }
189         k++;
190         xlen = 0;
191         if (!(k & 3))
192           csound->Message(csound, "\n");
193         else {
194           if (len > 19) {
195             xlen = len - 19;
196             len = 19;
197           }
198           csound->Message(csound, "%s", sp + len);
199         }
200         csound->Message(csound, "%s", lst[j].opname);
201         len = (int) strlen(lst[j].opname) + xlen;
202       }
203       else {
204         char *ans = lst[j].outypes, *arg = lst[j].intypes;
205         if ((level&2)==0 && ((lst[j].flags&_QQ) !=0)) {
206           //printf("dropping %s\n", lst[j].opname);
207           continue;
208         }
209         csound->Message(csound, "%s", lst[j].opname);
210         len = (int) strlen(lst[j].opname);
211         if (len > 11) {
212           xlen = len - 11;
213           len = 11;
214         }
215         csound->Message(csound, "%s", sp + (len + 8));
216         if (ans == NULL || *ans == '\0') ans = "(null)";
217         if (arg == NULL || *arg == '\0') arg = "(null)";
218         csound->Message(csound, "%s", ans);
219         len = (int) strlen(ans) + xlen;
220         len = (len < 11 ? len : 11);
221         xlen = 0;
222         csound->Message(csound, "%s", sp + (len + 8));
223         csound->Message(csound, "%s\n", arg);
224       }
225       count++;
226     }
227     csound->Message(csound, "\n");
228     csound->Message(csound, Str("%d opcodes\n\n"), count);
229     csoundDisposeOpcodeList(csound, lst);
230 }
231