1 /*
2     TiMidity++ -- MIDI to WAVE converter and player
3     Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
4     Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 
20 */
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 
25 #include <string.h>
26 
27 #include "timidity.h"
28 #include "common.h"
29 
30 namespace TimidityPlus
31 {
32 
33 struct MBlock
34 {
35 	MBlockNode* free_mblock_list = NULL;
36 
~MBlockTimidityPlus::MBlock37 	~MBlock()
38 	{
39 		int cnt;
40 
41 		cnt = 0;
42 		while (free_mblock_list)
43 		{
44 			MBlockNode* tmp;
45 
46 			tmp = free_mblock_list;
47 			free_mblock_list = free_mblock_list->next;
48 			free(tmp);
49 			cnt++;
50 		}
51 	}
52 };
53 
54 static MBlock free_list;
55 
56 #define ADDRALIGN 8
57 /* #define DEBUG */
58 
init_mblock(MBlockList * mblock)59 void init_mblock(MBlockList *mblock)
60 {
61     mblock->first = NULL;
62     mblock->allocated = 0;
63 }
64 
new_mblock_node(size_t n)65 static MBlockNode *new_mblock_node(size_t n)
66 {
67 	MBlockNode *p;
68 
69 	if (n > MIN_MBLOCK_SIZE)
70 	{
71 		if ((p = (MBlockNode *)safe_malloc(n + sizeof(MBlockNode))) == NULL)
72 			return NULL;
73 		p->block_size = n;
74 	}
75 	else if (free_list.free_mblock_list == NULL)
76 	{
77 		if ((p = (MBlockNode *)safe_malloc(sizeof(MBlockNode) + MIN_MBLOCK_SIZE)) == NULL)
78 			return NULL;
79 		p->block_size = MIN_MBLOCK_SIZE;
80 	}
81 	else
82 	{
83 		p = free_list.free_mblock_list;
84 		free_list.free_mblock_list = free_list.free_mblock_list->next;
85 	}
86 
87 	p->offset = 0;
88 	p->next = NULL;
89 
90 	return p;
91 }
92 
enough_block_memory(MBlockList * mblock,size_t n)93 static int enough_block_memory(MBlockList *mblock, size_t n)
94 {
95     size_t newoffset;
96 
97     if(mblock->first == NULL)
98 	return 0;
99 
100     newoffset = mblock->first->offset + n;
101 
102     if(newoffset < mblock->first->offset) /* exceed representable in size_t */
103 	return 0;
104 
105     if(newoffset > mblock->first->block_size)
106 	return 0;
107 
108     return 1;
109 }
110 
new_segment(MBlockList * mblock,size_t nbytes)111 void *new_segment(MBlockList *mblock, size_t nbytes)
112 {
113 	MBlockNode *p;
114 	void *addr;
115 
116 	/* round up to ADDRALIGN */
117 	nbytes = ((nbytes + ADDRALIGN - 1) & ~(ADDRALIGN - 1));
118 	if (!enough_block_memory(mblock, nbytes))
119 	{
120 		p = new_mblock_node(nbytes);
121 		p->next = mblock->first;
122 		mblock->first = p;
123 		mblock->allocated += p->block_size;
124 	}
125 	else
126 		p = mblock->first;
127 
128 	addr = (void *)(p->buffer + p->offset);
129 	p->offset += nbytes;
130 
131 	return addr;
132 }
133 
reuse_mblock1(MBlockNode * p)134 static void reuse_mblock1(MBlockNode *p)
135 {
136 	if (p->block_size > MIN_MBLOCK_SIZE)
137 		free(p);
138 	else /* p->block_size <= MIN_MBLOCK_SIZE */
139 	{
140 		p->next = free_list.free_mblock_list;
141 		free_list.free_mblock_list = p;
142 	}
143 }
144 
reuse_mblock(MBlockList * mblock)145 void reuse_mblock(MBlockList *mblock)
146 {
147 	MBlockNode *p;
148 
149 	if ((p = mblock->first) == NULL)
150 		return;			/* There is nothing to collect memory */
151 
152 	while (p)
153 	{
154 		MBlockNode *tmp;
155 
156 		tmp = p;
157 		p = p->next;
158 		reuse_mblock1(tmp);
159 	}
160 	init_mblock(mblock);
161 }
162 
strdup_mblock(MBlockList * mblock,const char * str)163 char *strdup_mblock(MBlockList *mblock, const char *str)
164 {
165     int len;
166     char *p;
167 
168     len = (int)strlen(str);
169     p = (char *)new_segment(mblock, len + 1); /* for '\0' */
170     memcpy(p, str, len + 1);
171     return p;
172 }
173 
174 }