quick links [ main: Text processing #comments ] [ tools: sed and /bin/sh functionality ideas #comments ] [ #comments ]
shell utility
Before going into sed'ing C, let's do some utility shell script.
coloring, understanding text easily
Hope, that " `grep` can do color " isn't surprise for you. We can't use grep, but we still can have useful coloring of matches, filtered stuff and more. Unfortunately wiki format can't help with this. If you have terminal emulator ready, then
is much better way to do exercises.
If reading script and all that quotes is hard, then read @archive.org: "Sh - the Bourne Shell" for programmers by Bruce Barnett first. As for syntax highlight in general, IMHO every processor, shell, sed, cpp should include option to output its input in highlighted form. They do parsing anyway, so why not to include this nice and very useful feature? This then can be used in editors or pagers.
c_func.defs.sed.sh
1 #!/bin/sh
2 # find linux-style lang:C function definitions
3 # Time-stamp: "Sat Mar 13 22:33:98 CET 2008 olecom@flower"
4
5 #linux-2.6>time nice -n 19 ./c_func.defs#0.sed.sh . >/dev/null
6
7 # real 0m12.978s
8 # user 0m12.553s
9 # sys 0m1.680s
10 # 0-!4~ +4.188
11
12 # handy fd
13 exec 3<>/dev/null
14
15 if [ -d "$1" ]
16 then DDD=$PWD
17 cd "$1" ; set -- "$PWD"
18 for i in `find . -type d`
19 do cd "$1/$i" ; echo "=@ $i"
20 cat *.[ch] ; echo "=@ $i"
21 done 2>&3
22 cd "$DDD"
23 else cat "$@" <&3
24 fi | sed -n '
25 # print directories
26 /^=@/{s-.*-\n&\n-p ; b}
27 '
28 : << ""
29 --
30 -o--=O`C
31 #oo'L O
32 <___=E M
So, [1] is hint for kernel (however, it uses /bin/sh as fallback anyway), [2][3] are hints for script users and authors. [5] is a way to run a benchmark. [7][8][9] are from the script, that doesn't implement function types on other line; it also uses different pattern for function definition, but numbers are quite good hint to start with.
Script runs on single directory [ "." || "linux/src" ] or on list of files [ "*.[ch]" ]. Former case produces file name on the start and the end of output for easy navigation.
sed runs on the pipe to eliminate re-run overhead. Its '-n' option disables default printing of input lines. This is useful, when script is filtering. After [24] goes actual sed script.
[26] is an utility output. Filename is wrapped with newlines ('s') and control jumps to the end of the script ('b').
linux-2.6/arch/m68k/atari$ time nice -n -19 c_func.defs#0.sed.sh .
1
2 =@ .
3
4
5 =@ .
6
7
8 real 0m0.006s
9 user 0m0.000s
10 sys 0m0.004s
sed#1: print command
Script's input is line oriented, much like stdin or console/tty input.
1 # print input
2 p
Notice:
form-feed symbols[114][244] [320] (no, doesn't work, this wiki parser is dumb)
linux-2.6/arch/m68k/atari$ time nice -n -19 c_func.defs#1.sed.sh stram.c
1 /*
2 * arch/m68k/atari/stram.c: Functions for ST-RAM allocations
3 *
4 * Copyright 1994-97 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive
8 * for more details.
9 */
10
11 #include <linux/types.h>
12 #include <linux/kernel.h>
13 #include <linux/mm.h>
14 #include <linux/kdev_t.h>
15 #include <linux/major.h>
16 #include <linux/init.h>
17 #include <linux/slab.h>
18 #include <linux/vmalloc.h>
19 #include <linux/pagemap.h>
20 #include <linux/bootmem.h>
21 #include <linux/mount.h>
22 #include <linux/blkdev.h>
23 #include <linux/module.h>
24
25 #include <asm/setup.h>
26 #include <asm/machdep.h>
27 #include <asm/page.h>
28 #include <asm/pgtable.h>
29 #include <asm/atarihw.h>
30 #include <asm/atari_stram.h>
31 #include <asm/io.h>
32 #include <asm/semaphore.h>
33
34 #undef DEBUG
35
36 #ifdef DEBUG
37 #define DPRINTK(fmt,args...) printk( fmt, ##args )
38 #else
39 #define DPRINTK(fmt,args...)
40 #endif
41
42 #if defined(CONFIG_PROC_FS) && defined(CONFIG_STRAM_PROC)
43 /* abbrev for the && above... */
44 #define DO_PROC
45 #include <linux/proc_fs.h>
46 #endif
47
48 /*
49 * ++roman:
50 *
51 * New version of ST-Ram buffer allocation. Instead of using the
52 * 1 MB - 4 KB that remain when the ST-Ram chunk starts at $1000
53 * (1 MB granularity!), such buffers are reserved like this:
54 *
55 * - If the kernel resides in ST-Ram anyway, we can take the buffer
56 * from behind the current kernel data space the normal way
57 * (incrementing start_mem).
58 *
59 * - If the kernel is in TT-Ram, stram_init() initializes start and
60 * end of the available region. Buffers are allocated from there
61 * and mem_init() later marks the such used pages as reserved.
62 * Since each TT-Ram chunk is at least 4 MB in size, I hope there
63 * won't be an overrun of the ST-Ram region by normal kernel data
64 * space.
65 *
66 * For that, ST-Ram may only be allocated while kernel initialization
67 * is going on, or exactly: before mem_init() is called. There is also
68 * no provision now for freeing ST-Ram buffers. It seems that isn't
69 * really needed.
70 *
71 */
72
73 /* Start and end (virtual) of ST-RAM */
74 static void *stram_start, *stram_end;
75
76 /* set after memory_init() executed and allocations via start_mem aren't
77 * possible anymore */
78 static int mem_init_done;
79
80 /* set if kernel is in ST-RAM */
81 static int kernel_in_stram;
82
83 typedef struct stram_block {
84 struct stram_block *next;
85 void *start;
86 unsigned long size;
87 unsigned flags;
88 const char *owner;
89 } BLOCK;
90
91 /* values for flags field */
92 #define BLOCK_FREE 0x01 /* free structure in the BLOCKs pool */
93 #define BLOCK_KMALLOCED 0x02 /* structure allocated by kmalloc() */
94 #define BLOCK_GFP 0x08 /* block allocated with __get_dma_pages() */
95
96 /* list of allocated blocks */
97 static BLOCK *alloc_list;
98
99 /* We can't always use kmalloc() to allocate BLOCK structures, since
100 * stram_alloc() can be called rather early. So we need some pool of
101 * statically allocated structures. 20 of them is more than enough, so in most
102 * cases we never should need to call kmalloc(). */
103 #define N_STATIC_BLOCKS 20
104 static BLOCK static_blocks[N_STATIC_BLOCKS];
105
106 /***************************** Prototypes *****************************/
107
108 static BLOCK *add_region( void *addr, unsigned long size );
109 static BLOCK *find_region( void *addr );
110 static int remove_region( BLOCK *block );
111
112 /************************* End of Prototypes **************************/
113
114 [[Anchor(114)]]
115 /* ------------------------------------------------------------------------ */
116 /* Public Interface */
117 /* ------------------------------------------------------------------------ */
118
119 /*
120 * This init function is called very early by atari/config.c
121 * It initializes some internal variables needed for stram_alloc()
122 */
123 void __init atari_stram_init(void)
124 {
125 int i;
126
127 /* initialize static blocks */
128 for( i = 0; i < N_STATIC_BLOCKS; ++i )
129 static_blocks[i].flags = BLOCK_FREE;
130
131 /* determine whether kernel code resides in ST-RAM (then ST-RAM is the
132 * first memory block at virtual 0x0) */
133 stram_start = phys_to_virt(0);
134 kernel_in_stram = (stram_start == 0);
135
136 for( i = 0; i < m68k_num_memory; ++i ) {
137 if (m68k_memory[i].addr == 0) {
138 /* skip first 2kB or page (supervisor-only!) */
139 stram_end = stram_start + m68k_memory[i].size;
140 return;
141 }
142 }
143 /* Should never come here! (There is always ST-Ram!) */
144 panic( "atari_stram_init: no ST-RAM found!" );
145 }
146
147
148 /*
149 * This function is called from setup_arch() to reserve the pages needed for
150 * ST-RAM management.
151 */
152 void __init atari_stram_reserve_pages(void *start_mem)
153 {
154 /* always reserve first page of ST-RAM, the first 2 kB are
155 * supervisor-only! */
156 if (!kernel_in_stram)
157 reserve_bootmem(0, PAGE_SIZE, BOOTMEM_DEFAULT);
158
159 }
160
161 void atari_stram_mem_init_hook (void)
162 {
163 mem_init_done = 1;
164 }
165
166
167 /*
168 * This is main public interface: somehow allocate a ST-RAM block
169 *
170 * - If we're before mem_init(), we have to make a static allocation. The
171 * region is taken in the kernel data area (if the kernel is in ST-RAM) or
172 * from the start of ST-RAM (if the kernel is in TT-RAM) and added to the
173 * rsvd_stram_* region. The ST-RAM is somewhere in the middle of kernel
174 * address space in the latter case.
175 *
176 * - If mem_init() already has been called, try with __get_dma_pages().
177 * This has the disadvantage that it's very hard to get more than 1 page,
178 * and it is likely to fail :-(
179 *
180 */
181 void *atari_stram_alloc(long size, const char *owner)
182 {
183 void *addr = NULL;
184 BLOCK *block;
185 int flags;
186
187 DPRINTK("atari_stram_alloc(size=%08lx,owner=%s)\n", size, owner);
188
189 if (!mem_init_done)
190 return alloc_bootmem_low(size);
191 else {
192 /* After mem_init(): can only resort to __get_dma_pages() */
193 addr = (void *)__get_dma_pages(GFP_KERNEL, get_order(size));
194 flags = BLOCK_GFP;
195 DPRINTK( "atari_stram_alloc: after mem_init, "
196 "get_pages=%p\n", addr );
197 }
198
199 if (addr) {
200 if (!(block = add_region( addr, size ))) {
201 /* out of memory for BLOCK structure :-( */
202 DPRINTK( "atari_stram_alloc: out of mem for BLOCK -- "
203 "freeing again\n" );
204 free_pages((unsigned long)addr, get_order(size));
205 return( NULL );
206 }
207 block->owner = owner;
208 block->flags |= flags;
209 }
210 return( addr );
211 }
212 EXPORT_SYMBOL(atari_stram_alloc);
213
214 void atari_stram_free( void *addr )
215
216 {
217 BLOCK *block;
218
219 DPRINTK( "atari_stram_free(addr=%p)\n", addr );
220
221 if (!(block = find_region( addr ))) {
222 printk( KERN_ERR "Attempt to free non-allocated ST-RAM block at %p "
223 "from %p\n", addr, __builtin_return_address(0) );
224 return;
225 }
226 DPRINTK( "atari_stram_free: found block (%p): size=%08lx, owner=%s, "
227 "flags=%02x\n", block, block->size, block->owner, block->flags );
228
229 if (!(block->flags & BLOCK_GFP))
230 goto fail;
231
232 DPRINTK("atari_stram_free: is kmalloced, order_size=%d\n",
233 get_order(block->size));
234 free_pages((unsigned long)addr, get_order(block->size));
235 remove_region( block );
236 return;
237
238 fail:
239 printk( KERN_ERR "atari_stram_free: cannot free block at %p "
240 "(called from %p)\n", addr, __builtin_return_address(0) );
241 }
242 EXPORT_SYMBOL(atari_stram_free);
243
244 [[Anchor(244)]]
245 /* ------------------------------------------------------------------------ */
246 /* Region Management */
247 /* ------------------------------------------------------------------------ */
248
249
250 /* insert a region into the alloced list (sorted) */
251 static BLOCK *add_region( void *addr, unsigned long size )
252 {
253 BLOCK **p, *n = NULL;
254 int i;
255
256 for( i = 0; i < N_STATIC_BLOCKS; ++i ) {
257 if (static_blocks[i].flags & BLOCK_FREE) {
258 n = &static_blocks[i];
259 n->flags = 0;
260 break;
261 }
262 }
263 if (!n && mem_init_done) {
264 /* if statics block pool exhausted and we can call kmalloc() already
265 * (after mem_init()), try that */
266 n = kmalloc( sizeof(BLOCK), GFP_KERNEL );
267 if (n)
268 n->flags = BLOCK_KMALLOCED;
269 }
270 if (!n) {
271 printk( KERN_ERR "Out of memory for ST-RAM descriptor blocks\n" );
272 return( NULL );
273 }
274 n->start = addr;
275 n->size = size;
276
277 for( p = &alloc_list; *p; p = &((*p)->next) )
278 if ((*p)->start > addr) break;
279 n->next = *p;
280 *p = n;
281
282 return( n );
283 }
284
285
286 /* find a region (by start addr) in the alloced list */
287 static BLOCK *find_region( void *addr )
288 {
289 BLOCK *p;
290
291 for( p = alloc_list; p; p = p->next ) {
292 if (p->start == addr)
293 return( p );
294 if (p->start > addr)
295 break;
296 }
297 return( NULL );
298 }
299
300
301 /* remove a block from the alloced list */
302 static int remove_region( BLOCK *block )
303 {
304 BLOCK **p;
305
306 for( p = &alloc_list; *p; p = &((*p)->next) )
307 if (*p == block) break;
308 if (!*p)
309 return( 0 );
310
311 *p = block->next;
312 if (block->flags & BLOCK_KMALLOCED)
313 kfree( block );
314 else
315 block->flags |= BLOCK_FREE;
316 return( 1 );
317 }
318
319
320
321 /* ------------------------------------------------------------------------ */
322 /* /proc statistics file stuff */
323 /* ------------------------------------------------------------------------ */
324
325 #ifdef DO_PROC
326
327 #define PRINT_PROC(fmt,args...) len += sprintf( buf+len, fmt, ##args )
328
329 int get_stram_list( char *buf )
330 {
331 int len = 0;
332 BLOCK *p;
333
334 PRINT_PROC("Total ST-RAM: %8u kB\n",
335 (stram_end - stram_start) >> 10);
336 PRINT_PROC( "Allocated regions:\n" );
337 for( p = alloc_list; p; p = p->next ) {
338 if (len + 50 >= PAGE_SIZE)
339 break;
340 PRINT_PROC("0x%08lx-0x%08lx: %s (",
341 virt_to_phys(p->start),
342 virt_to_phys(p->start+p->size-1),
343 p->owner);
344 if (p->flags & BLOCK_GFP)
345 PRINT_PROC( "page-alloced)\n" );
346 else
347 PRINT_PROC( "??)\n" );
348 }
349
350 return( len );
351 }
352
353 #endif
354
355
356 /*
357 * Local variables:
358 * c-indent-level: 4
359 * tab-width: 4
360 * End:
361 */
362
363 real 0m0.005s
364 user 0m0.000s
365 sys 0m0.004s
C multiline comments, #preprocessor and other noise
sed#2: just declarations mixed with function definitions left
linux-2.6/arch/m68k/atari$ time nice -n -19 c_func.defs#2.sed.sh stram.c
1 static void *stram_start, *stram_end;
2 static int mem_init_done;
3 static int kernel_in_stram;
4 typedef struct stram_block {
5 } BLOCK;
6 static BLOCK *alloc_list;
7 static BLOCK static_blocks[N_STATIC_BLOCKS];
8 static BLOCK *add_region( void *addr, unsigned long size );
9 static BLOCK *find_region( void *addr );
10 static int remove_region( BLOCK *block );
11 void __init atari_stram_init(void)
12 {
13 }
14 void __init atari_stram_reserve_pages(void *start_mem)
15 {
16 }
17 void atari_stram_mem_init_hook (void)
18 {
19 }
20 void *atari_stram_alloc(long size, const char *owner)
21 {
22 }
23 EXPORT_SYMBOL(atari_stram_alloc);
24 void atari_stram_free( void *addr )
25 {
26 }
27 EXPORT_SYMBOL(atari_stram_free);
28 static BLOCK *add_region( void *addr, unsigned long size )
29 {
30 }
31 static BLOCK *find_region( void *addr )
32 {
33 }
34 static int remove_region( BLOCK *block )
35 {
36 }
37 int get_stram_list( char *buf )
38 {
39 }
40
41 real 0m0.004s
42 user 0m0.004s
43 sys 0m0.000s
sed#2: script to skip noise
1 sed -n '
2 /^=@/{s-.*-\n&\n-p ; b}
3 /^[[:space:]]*\/\*/{
4 :_comment
5 /\*\//!{n ; b_comment}
6 b
7 }
8 /^[[:space:]]*#/{
9 :_define
10 /\\$/{n ; b_define}
11 b
12 }
13 /^[[:space:]/|")@]/b
14
15 /^[^[:blank:]]/{
16 p
17 }'
[2] is same utility.
[3]-[7] skips in-line and multi-line comments from the line start[^]. [:space:] is used instead of [:blank:], because there are contol symbols in the code. n command loads new input line. There is no need on keeping comments, thus space-consuming append command N isn't used. Algo:
if line-start[^] && whitespace[:space:] && c-comment-start[/*]
then until c-comment-end[*/]
do load-line
done
jump-to-end
fi
[8]-[12] skips preprocessor macros. Algo:
if line-start[^] && whitespace[:space:] && macro-key[#]
then while macro-continue-key[\] && line-end[$]
do load-line
done
jump-to-end
fi
[13] skips all other types of noise, found in the wild:
.|. linux-2.6/arch/m68k/fpsp040/fpsp.h
.". linux-2.6/arch/parisc/kernel/unaligned.c
//C++
Finally [15]-[17] is doing printing only, when line doesn't start from space or tab.
So, /BRE/ is a condition for some { processing block }. 'b' is branching, simple jump to the _lable (with