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