• Immutable Page
  • Info
  • Attachments

olecom/c func.def.sed.sh

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:

  • /* comments */
  • #preprocessor stuff
  • 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 

skip output

   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 

skip output

   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