home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume25 / perl / patch12 < prev    next >
Encoding:
Text File  |  1991-11-13  |  49.3 KB  |  1,735 lines

  1. Newsgroups: comp.sources.misc
  2. From: lwall@netlabs.com (Larry Wall)
  3. Subject:  v25i061:  perl - The perl programming language, Patch12
  4. Message-ID: <1991Nov13.214221.3565@sparky.imd.sterling.com>
  5. X-Md4-Signature: f2b6a10dc4714b35af7826f02964e4ac
  6. Date: Wed, 13 Nov 1991 21:42:21 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: lwall@netlabs.com (Larry Wall)
  10. Posting-number: Volume 25, Issue 61
  11. Archive-name: perl/patch12
  12. Environment: UNIX, MS-DOS, OS2
  13. Patch-To: perl: Volume 18, Issue 19-54
  14.  
  15. System: perl version 4.0
  16. Patch #: 12
  17. Priority: MED-HIGH
  18. Subject: patch #11, continued
  19.  
  20. Description:
  21.     See patch #11.
  22.  
  23. Fix:    From rn, say "| patch -p -N -d DIR", where DIR is your perl source
  24.     directory.  Outside of rn, say "cd DIR; patch -p -N <thisarticle".
  25.     If you don't have the patch program, apply the following by hand,
  26.     or get patch (version 2.0, latest patchlevel).
  27.  
  28.     After patching:
  29.         *** DO NOTHING--INSTALL ALL PATCHES UP THROUGH #18 FIRST ***
  30.  
  31.     If patch indicates that patchlevel is the wrong version, you may need
  32.     to apply one or more previous patches, or the patch may already
  33.     have been applied.  See the patchlevel.h file to find out what has or
  34.     has not been applied.  In any event, don't continue with the patch.
  35.  
  36.     If you are missing previous patches they can be obtained from me:
  37.  
  38.     Larry Wall
  39.     lwall@netlabs.com
  40.  
  41.     If you send a mail message of the following form it will greatly speed
  42.     processing:
  43.  
  44.     Subject: Command
  45.     @SH mailpatch PATH perl 4.0 LIST
  46.            ^ note the c
  47.  
  48.     where PATH is a return path FROM ME TO YOU either in Internet notation,
  49.     or in bang notation from some well-known host, and LIST is the number
  50.     of one or more patches you need, separated by spaces, commas, and/or
  51.     hyphens.  Saying 35- says everything from 35 to the end.
  52.  
  53.  
  54. Index: patchlevel.h
  55. Prereq: 11
  56. 1c1
  57. < #define PATCHLEVEL 11
  58. ---
  59. > #define PATCHLEVEL 12
  60.  
  61. Index: c2ph.SH
  62. *** c2ph.SH.old    Tue Nov  5 19:25:34 1991
  63. --- c2ph.SH    Tue Nov  5 19:25:34 1991
  64. ***************
  65. *** 0 ****
  66. --- 1,1101 ----
  67. + case $CONFIG in
  68. + '')
  69. +     if test ! -f config.sh; then
  70. +     ln ../config.sh . || \
  71. +     ln ../../config.sh . || \
  72. +     ln ../../../config.sh . || \
  73. +     (echo "Can't find config.sh."; exit 1)
  74. +     fi
  75. +     . config.sh
  76. +     ;;
  77. + esac
  78. + : This forces SH files to create target in same directory as SH file.
  79. + : This is so that make depend always knows where to find SH derivatives.
  80. + case "$0" in
  81. + */*) cd `expr X$0 : 'X\(.*\)/'` ;;
  82. + esac
  83. + echo "Extracting c2ph (with variable substitutions)"
  84. + : This section of the file will have variable substitutions done on it.
  85. + : Move anything that needs config subs from !NO!SUBS! section to !GROK!THIS!.
  86. + : Protect any dollar signs and backticks that you do not want interpreted
  87. + : by putting a backslash in front.  You may delete these comments.
  88. + $spitshell >c2ph <<!GROK!THIS!
  89. + #!$bin/perl
  90. + #
  91. + !GROK!THIS!
  92. + : In the following dollars and backticks do not need the extra backslash.
  93. + $spitshell >>c2ph <<'!NO!SUBS!'
  94. + #
  95. + #   c2ph (aka pstruct)
  96. + #   Tom Christiansen, <tchrist@convex.com>
  97. + #   
  98. + #   As pstruct, dump C structures as generated from 'cc -g -S' stabs.
  99. + #   As c2ph, do this PLUS generate perl code for getting at the structures.
  100. + #
  101. + #   See the usage message for more.  If this isn't enough, read the code.
  102. + #
  103. + $RCSID = '$RCSfile: c2ph.SH,v $$Revision: 4.0.1.1 $$Date: 91/11/05 16:02:29 $';
  104. + ######################################################################
  105. + # some handy data definitions.   many of these can be reset later.
  106. + $bitorder = 'b';  # ascending; set to B for descending bit fields
  107. + %intrinsics = 
  108. + %template = (
  109. +     'char',             'c',
  110. +     'unsigned char',         'C',
  111. +     'short',            's',
  112. +     'short int',        's',
  113. +     'unsigned short',        'S',
  114. +     'unsigned short int',    'S',
  115. +     'short unsigned int',    'S',
  116. +     'int',            'i',
  117. +     'unsigned int',        'I',
  118. +     'long',            'l',
  119. +     'long int',            'l',
  120. +     'unsigned long',        'L',
  121. +     'unsigned long',        'L',
  122. +     'long unsigned int',    'L',
  123. +     'unsigned long int',    'L',
  124. +     'long long',        'q',
  125. +     'long long int',        'q',
  126. +     'unsigned long long',    'Q',
  127. +     'unsigned long long int',    'Q',
  128. +     'float',            'f',
  129. +     'double',            'd',
  130. +     'pointer',            'p',
  131. +     'null',            'x',
  132. +     'neganull',            'X',
  133. +     'bit',            $bitorder,
  134. + ); 
  135. + &buildscrunchlist;
  136. + delete $intrinsics{'neganull'};
  137. + delete $intrinsics{'bit'};
  138. + delete $intrinsics{'null'};
  139. + # use -s to recompute sizes
  140. + %sizeof = (
  141. +     'char',             '1',
  142. +     'unsigned char',         '1',
  143. +     'short',            '2',
  144. +     'short int',        '2',
  145. +     'unsigned short',        '2',
  146. +     'unsigned short int',    '2',
  147. +     'short unsigned int',    '2',
  148. +     'int',            '4',
  149. +     'unsigned int',        '4',
  150. +     'long',            '4',
  151. +     'long int',            '4',
  152. +     'unsigned long',        '4',
  153. +     'unsigned long int',    '4',
  154. +     'long unsigned int',    '4',
  155. +     'long long',        '8',
  156. +     'long long int',        '8',
  157. +     'unsigned long long',    '8',
  158. +     'unsigned long long int',    '8',
  159. +     'float',            '4',
  160. +     'double',            '8',
  161. +     'pointer',            '4',
  162. + );
  163. + ($type_width, $member_width, $offset_width, $size_width) = (20, 20, 6, 5);
  164. + ($offset_fmt, $size_fmt) = ('d', 'd');
  165. + $indent = 2;
  166. + $CC = 'cc';
  167. + $CFLAGS = '-g -S';
  168. + $DEFINES = '';
  169. + $perl++ if $0 =~ m#/?c2ph$#;
  170. + require 'getopts.pl';
  171. + eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_]+=)(.*)/ && shift;
  172. + &Getopts('aixdpvtnws:') || &usage(0);
  173. + $opt_d && $debug++;
  174. + $opt_t && $trace++;
  175. + $opt_p && $perl++;
  176. + $opt_v && $verbose++;
  177. + $opt_n && ($perl = 0);
  178. + if ($opt_w) {
  179. +     ($type_width, $member_width, $offset_width) = (45, 35, 8);
  180. + } 
  181. + if ($opt_x) {
  182. +     ($offset_fmt, $offset_width, $size_fmt, $size_width) = ( 'x', '08', 'x', 04 );
  183. + }
  184. + eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_]+=)(.*)/ && shift;
  185. + sub PLUMBER {
  186. +     select(STDERR);
  187. +     print "oops, apperent pager foulup\n";
  188. +     $isatty++;
  189. +     &usage(1);
  190. + } 
  191. + sub usage {
  192. +     local($oops) = @_;
  193. +     unless (-t STDOUT) {
  194. +     select(STDERR);
  195. +     } elsif (!$oops) {
  196. +     $isatty++;
  197. +     $| = 1;
  198. +     print "hit <RETURN> for further explanation: ";
  199. +     <STDIN>;
  200. +     open (PIPE, "|". ($ENV{PAGER} || 'more'));
  201. +     $SIG{PIPE} = PLUMBER;
  202. +     select(PIPE);
  203. +     } 
  204. +     print "usage: $0 [-dpnP] [var=val] [files ...]\n";
  205. +     exit unless $isatty;
  206. +     print <<EOF;
  207. + Options:
  208. + -w    wide; short for: type_width=45 member_width=35 offset_width=8
  209. + -x    hex; short for:  offset_fmt=x offset_width=08 size_fmt=x size_width=04
  210. + -n      do not generate perl code  (default when invoked as pstruct)
  211. + -p      generate perl code         (default when invoked as c2ph)
  212. + -v    generate perl code, with C decls as comments
  213. + -i    do NOT recompute sizes for intrinsic datatypes
  214. + -a    dump information on intrinsics also
  215. + -t     trace execution
  216. + -d    spew reams of debugging output
  217. + -slist  give comma-separated list a structures to dump
  218. + Var Name        Default Value    Meaning
  219. + EOF
  220. +     &defvar('CC', 'which_compiler to call');
  221. +     &defvar('CFLAGS', 'how to generate *.s files with stabs');
  222. +     &defvar('DEFINES','any extra cflags or cpp defines, like -I, -D, -U');
  223. +     print "\n";
  224. +     &defvar('type_width', 'width of type field   (column 1)');
  225. +     &defvar('member_width', 'width of member field (column 2)');
  226. +     &defvar('offset_width', 'width of offset field (column 3)');
  227. +     &defvar('size_width', 'width of size field   (column 4)');
  228. +     print "\n";
  229. +     &defvar('offset_fmt', 'sprintf format type for offset');
  230. +     &defvar('size_fmt', 'sprintf format type for size');
  231. +     print "\n";
  232. +     &defvar('indent', 'how far to indent each nesting level');
  233. +    print <<'EOF';
  234. +     If any *.[ch] files are given, these will be catted together into
  235. +     a temporary *.c file and sent through:
  236. +         $CC $CFLAGS $DEFINES 
  237. +     and the resulting *.s groped for stab information.  If no files are
  238. +     supplied, then stdin is read directly with the assumption that it
  239. +     contains stab information.  All other liens will be ignored.  At
  240. +     most one *.s file should be supplied.
  241. + EOF
  242. +     close PIPE;
  243. +     exit 1;
  244. + } 
  245. + sub defvar {
  246. +     local($var, $msg) = @_;
  247. +     printf "%-16s%-15s  %s\n", $var, eval "\$$var", $msg;
  248. + } 
  249. + $recurse = 1;
  250. + if (@ARGV) {
  251. +     if (grep(!/\.[csh]$/,@ARGV)) {
  252. +     warn "Only *.[csh] files expected!\n";
  253. +     &usage;
  254. +     } 
  255. +     elsif (grep(/\.s$/,@ARGV)) {
  256. +     if (@ARGV > 1) { 
  257. +         warn "Only one *.s file allowed!\n";
  258. +         &usage;
  259. +     }
  260. +     } 
  261. +     elsif (@ARGV == 1 && $ARGV[0] =~ /\.c$/) {
  262. +     local($dir, $file) = $ARGV[0] =~ m#(.*/)?(.*)$#;
  263. +     $chdir = "cd $dir; " if $dir;
  264. +     &system("$chdir$CC $CFLAGS $DEFINES $file") && exit 1;
  265. +     $ARGV[0] =~ s/\.c$/.s/;
  266. +     } 
  267. +     else {
  268. +     $TMP = "/tmp/c2ph.$$.c";
  269. +     &system("cat @ARGV > $TMP") && exit 1;
  270. +     &system("cd /tmp; $CC $CFLAGS $DEFINES $TMP") && exit 1;
  271. +     unlink $TMP;
  272. +     $TMP =~ s/\.c$/.s/;
  273. +     @ARGV = ($TMP);
  274. +     } 
  275. + }
  276. + if ($opt_s) {
  277. +     for (split(/[\s,]+/, $opt_s)) {
  278. +     $interested{$_}++;
  279. +     } 
  280. + } 
  281. + $| = 1 if $debug;
  282. + main: {
  283. +     if ($trace) {
  284. +     if (-t && !@ARGV) { 
  285. +         print STDERR "reading from your keyboard: ";
  286. +     } else {
  287. +         print STDERR "reading from " . (@ARGV ? "@ARGV" : "<STDIN>").": ";
  288. +     }
  289. +     }
  290. + STAB: while (<>) {
  291. +     if ($trace && !($. % 10)) {
  292. +         $lineno = $..'';
  293. +         print STDERR $lineno, "\b" x length($lineno);
  294. +     } 
  295. +     next unless /^\s*\.stabs\s+/;
  296. +     $line = $_;
  297. +     s/^\s*\.stabs\s+//; 
  298. +     &stab; 
  299. +     }
  300. +     print STDERR "$.\n" if $trace;
  301. +     unlink $TMP if $TMP;
  302. +     &compute_intrinsics if $perl && !$opt_i;
  303. +     print STDERR "resolving types\n" if $trace;
  304. +     &resolve_types;
  305. +     &adjust_start_addrs;
  306. +     $sum = 2 + $type_width + $member_width;
  307. +     $pmask1 = "%-${type_width}s %-${member_width}s"; 
  308. +     $pmask2 = "%-${sum}s %${offset_width}${offset_fmt}%s %${size_width}${size_fmt}%s";
  309. +     if ($perl) {
  310. +     # resolve template -- should be in stab define order, but even this isn't enough.
  311. +     print STDERR "\nbuilding type templates: " if $trace;
  312. +     for $i (reverse 0..$#type) {
  313. +         next unless defined($name = $type[$i]);
  314. +         next unless defined $struct{$name};
  315. +         $build_recursed = 0;
  316. +         &build_template($name) unless defined $template{&psou($name)} ||
  317. +                     $opt_s && !$interested{$name};
  318. +     } 
  319. +     print STDERR "\n\n" if $trace;
  320. +     }
  321. +     print STDERR "dumping structs: " if $trace;
  322. +     foreach $name (sort keys %struct) {
  323. +     next if $opt_s && !$interested{$name};
  324. +     print STDERR "$name " if $trace;
  325. +     undef @sizeof;
  326. +     undef @typedef;
  327. +     undef @offsetof;
  328. +     undef @indices;
  329. +     undef @typeof;
  330. +     $mname = &munge($name);
  331. +     $fname = &psou($name);
  332. +     print "# " if $perl && $verbose;
  333. +     $pcode = '';
  334. +     print "$fname {\n" if !$perl || $verbose; 
  335. +     $template{$fname} = &scrunch($template{$fname}) if $perl;
  336. +     &pstruct($name,$name,0); 
  337. +     print "# " if $perl && $verbose;
  338. +     print "}\n" if !$perl || $verbose; 
  339. +     print "\n" if $perl && $verbose;
  340. +     if ($perl) {
  341. +         print "$pcode";
  342. +         printf("\nsub %-32s { %4d; }\n\n", "${mname}'struct", $countof{$name});
  343. +         print <<EOF;
  344. + sub ${mname}'typedef { 
  345. +     local(\$${mname}'index) = shift;
  346. +     defined \$${mname}'index 
  347. +     ? \$${mname}'typedef[\$${mname}'index] 
  348. +     : \$${mname}'typedef;
  349. + }
  350. + EOF
  351. +         print <<EOF;
  352. + sub ${mname}'sizeof { 
  353. +     local(\$${mname}'index) = shift;
  354. +     defined \$${mname}'index 
  355. +     ? \$${mname}'sizeof[\$${mname}'index] 
  356. +     : \$${mname}'sizeof;
  357. + }
  358. + EOF
  359. +         print <<EOF;
  360. + sub ${mname}'offsetof { 
  361. +     local(\$${mname}'index) = shift;
  362. +     defined \$${mname}index 
  363. +     ? \$${mname}'offsetof[\$${mname}'index] 
  364. +     : \$${mname}'sizeof;
  365. + }
  366. + EOF
  367. +         print <<EOF;
  368. + sub ${mname}'typeof { 
  369. +     local(\$${mname}'index) = shift;
  370. +     defined \$${mname}index 
  371. +     ? \$${mname}'typeof[\$${mname}'index] 
  372. +     : '$name';
  373. + }
  374. + EOF
  375. +     
  376. +         print "\$${mname}'typedef = '" . &scrunch($template{$fname}) 
  377. +         . "';\n";
  378. +         print "\$${mname}'sizeof = $sizeof{$name};\n\n";
  379. +         print "\@${mname}'indices = (", &squishseq(@indices), ");\n";
  380. +         print "\n";
  381. +         print "\@${mname}'typedef[\@${mname}'indices] = (",
  382. +             join("\n\t", '', @typedef), "\n    );\n\n";
  383. +         print "\@${mname}'sizeof[\@${mname}'indices] = (",
  384. +             join("\n\t", '', @sizeof), "\n    );\n\n";
  385. +         print "\@${mname}'offsetof[\@${mname}'indices] = (",
  386. +             join("\n\t", '', @offsetof), "\n    );\n\n";
  387. +         print "\@${mname}'typeof[\@${mname}'indices] = (",
  388. +             join("\n\t", '', @typeof), "\n    );\n\n";
  389. +         $template_printed{$fname}++;
  390. +         $size_printed{$fname}++;
  391. +     } 
  392. +     print "\n";
  393. +     }
  394. +     print STDERR "\n" if $trace;
  395. +     unless ($perl && $opt_a) { 
  396. +     print "\n1;\n";
  397. +     exit;
  398. +     }
  399. +     foreach $name (sort bysizevalue keys %intrinsics) {
  400. +     next if $size_printed{$name};
  401. +     print '$',&munge($name),"'sizeof = ", $sizeof{$name}, ";\n";
  402. +     }
  403. +     print "\n";
  404. +     sub bysizevalue { $sizeof{$a} <=> $sizeof{$b}; }
  405. +     foreach $name (sort keys %intrinsics) {
  406. +     print '$',&munge($name),"'typedef = '", $template{$name}, "';\n";
  407. +     }
  408. +     print "\n1;\n";
  409. +     
  410. +     exit;
  411. + }
  412. + ########################################################################################
  413. + sub stab {
  414. +     next unless /:[\$\w]+(\(\d+,\d+\))?=[\*\$\w]+/;  # (\d+,\d+) is for sun
  415. +     s/"//                         || next;
  416. +     s/",([x\d]+),([x\d]+),([x\d]+),.*//         || next;
  417. +     next if /^\s*$/;
  418. +     $size = $3 if $3;
  419. +     $line = $_;
  420. +     if (($name, $pdecl) = /^([\$ \w]+):[tT]((\d+)(=[rufs*](\d+))+)$/) {
  421. +     print "$name is a typedef for some funky pointers: $pdecl\n" if $debug;
  422. +     &pdecl($pdecl);
  423. +     next;
  424. +     }
  425. +     if (/(([ \w]+):t(\d+|\(\d+,\d+\)))=r?(\d+|\(\d+,\d+\))(;\d+;\d+;)?/) {  
  426. +     local($ident) = $2;
  427. +     push(@intrinsics, $ident);
  428. +     $typeno = &typeno($3);
  429. +     $type[$typeno] = $ident;
  430. +     print STDERR "intrinsic $ident in new type $typeno\n" if $debug; 
  431. +     next;
  432. +     }
  433. +     if (($name, $typeordef, $typeno, $extra, $struct, $_) 
  434. +     = /^([\$ \w]+):([ustT])(\d+|\(\d+,\d+\))(=[rufs*](\d+))?(.*)$/) 
  435. +     {
  436. +     $typeno = &typeno($typeno);  # sun foolery
  437. +     } 
  438. +     elsif (/^[\$\w]+:/) {
  439. +     next; # variable
  440. +     }
  441. +     else { 
  442. +     warn "can't grok stab: <$_> in: $line " if $_;
  443. +     next;
  444. +     } 
  445. +     #warn "got size $size for $name\n";
  446. +     $sizeof{$name} = $size if $size;
  447. +     s/;[-\d]*;[-\d]*;$//;  # we don't care about ranges
  448. +     $typenos{$name} = $typeno;
  449. +     unless (defined $type[$typeno]) {
  450. +     &panic("type 0??") unless $typeno;
  451. +     $type[$typeno] = $name unless defined $type[$typeno];
  452. +     printf "new type $typeno is $name" if $debug;
  453. +     if ($extra =~ /\*/ && defined $type[$struct]) {
  454. +         print ", a typedef for a pointer to " , $type[$struct] if $debug;
  455. +     }
  456. +     } else {
  457. +     printf "%s is type %d", $name, $typeno if $debug;
  458. +     print ", a typedef for " , $type[$typeno] if $debug;
  459. +     } 
  460. +     print "\n" if $debug;
  461. +     #next unless $extra =~ /[su*]/;
  462. +     #$type[$struct] = $name;
  463. +     if ($extra =~ /[us*]/) {
  464. +     &sou($name, $extra);
  465. +     $_ = &sdecl($name, $_, 0);
  466. +     }
  467. +     elsif (/^=ar/) {
  468. +     print "it's a bare array typedef -- that's pretty sick\n" if $debug;
  469. +     $_ = "$typeno$_";
  470. +     $scripts = '';
  471. +     $_ = &adecl($_,1);
  472. +     }
  473. +     elsif (s/((\w+):t(\d+|\(\d+,\d+\)))?=r?(;\d+;\d+;)?//) {  # the ?'s are for gcc
  474. +     push(@intrinsics, $2);
  475. +     $typeno = &typeno($3);
  476. +     $type[$typeno] = $2;
  477. +     print STDERR "intrinsic $2 in new type $typeno\n" if $debug; 
  478. +     }
  479. +     elsif (s/^=e//) { # blessed by thy compiler; mine won't do this
  480. +     &edecl;
  481. +     } 
  482. +     else {
  483. +     warn "Funny remainder for $name on line $_ left in $line " if $_;
  484. +     } 
  485. + }
  486. + sub typeno {  # sun thinks types are (0,27) instead of just 27
  487. +     local($_) = @_;
  488. +     s/\(\d+,(\d+)\)/$1/;
  489. +     $_;
  490. + } 
  491. + sub pstruct {
  492. +     local($what,$prefix,$base) = @_; 
  493. +     local($field, $fieldname, $typeno, $count, $offset, $entry); 
  494. +     local($fieldtype);
  495. +     local($type, $tname); 
  496. +     local($mytype, $mycount, $entry2);
  497. +     local($struct_count) = 0;
  498. +     local($pad, $revpad, $length, $prepad, $lastoffset, $lastlength, $fmt);
  499. +     local($bits,$bytes);
  500. +     local($template);
  501. +     local($mname) = &munge($name);
  502. +     sub munge { 
  503. +     local($_) = @_;
  504. +     s/[\s\$\.]/_/g;
  505. +     $_;
  506. +     }
  507. +     local($sname) = &psou($what);
  508. +     $nesting++;
  509. +     for $field (split(/;/, $struct{$what})) {
  510. +     $pad = $prepad = 0;
  511. +     $entry = ''; 
  512. +     ($fieldname, $typeno, $count, $offset, $length) = split(/,/, $field); 
  513. +     $type = $type[$typeno];
  514. +     $type =~ /([^[]*)(\[.*\])?/;
  515. +     $mytype = $1;
  516. +     $count .= $2;
  517. +     $fieldtype = &psou($mytype);
  518. +     local($fname) = &psou($name);
  519. +     if ($build_templates) {
  520. +         $pad = ($offset - ($lastoffset + $lastlength))/8 
  521. +         if defined $lastoffset;
  522. +         if (! $finished_template{$sname}) {
  523. +         if ($isaunion{$what}) {
  524. +             $template{$sname} .= 'X' x $revpad . ' '    if $revpad;
  525. +         } else {
  526. +             $template{$sname} .= 'x' x $pad    . ' '    if $pad;
  527. +         }
  528. +         }
  529. +         $template = &fetch_template($type) x 
  530. +                 ($count ? &scripts2count($count) : 1);
  531. +         if (! $finished_template{$sname}) {
  532. +         $template{$sname} .= $template;
  533. +         }
  534. +         $revpad = $length/8 if $isaunion{$what};
  535. +         ($lastoffset, $lastlength) = ($offset, $length);
  536. +     } else { 
  537. +         print '# ' if $perl && $verbose;
  538. +         $entry = sprintf($pmask1,
  539. +             ' ' x ($nesting * $indent) . $fieldtype,
  540. +             "$prefix.$fieldname" . $count); 
  541. +         $entry =~ s/(\*+)( )/$2$1/; 
  542. +         printf $pmask2,
  543. +             $entry,
  544. +             ($base+$offset)/8,
  545. +             ($bits = ($base+$offset)%8) ? ".$bits" : "  ",
  546. +             $length/8,
  547. +             ($bits = $length % 8) ? ".$bits": ""
  548. +             if !$perl || $verbose;
  549. +         if ($perl && $nesting == 1) {
  550. +         $template = &scrunch(&fetch_template($type) x 
  551. +                 ($count ? &scripts2count($count) : 1));
  552. +         push(@sizeof, int($length/8) .",\t# $fieldname");
  553. +         push(@offsetof, int($offset/8) .",\t# $fieldname");
  554. +         push(@typedef, "'$template', \t# $fieldname");
  555. +         $type =~ s/(struct|union) //;
  556. +         push(@typeof, "'$type" . ($count ? $count : '') .
  557. +             "',\t# $fieldname");
  558. +         }
  559. +         print '  ', ' ' x $indent x $nesting, $template
  560. +                 if $perl && $verbose;
  561. +         print "\n" if !$perl || $verbose;
  562. +     }    
  563. +     if ($perl) {
  564. +         local($mycount) = defined $struct{$mytype} ? $countof{$mytype} : 1;
  565. +         $mycount *= &scripts2count($count) if $count;
  566. +         if ($nesting==1 && !$build_templates) {
  567. +         $pcode .= sprintf("sub %-32s { %4d; }\n", 
  568. +             "${mname}'${fieldname}", $struct_count);
  569. +         push(@indices, $struct_count);
  570. +         }
  571. +         $struct_count += $mycount;
  572. +     } 
  573. +     &pstruct($type, "$prefix.$fieldname", $base+$offset) 
  574. +         if $recurse && defined $struct{$type}; 
  575. +     }
  576. +     $countof{$what} = $struct_count unless defined $countof{$whati};
  577. +     $template{$sname} .= '$' if $build_templates;
  578. +     $finished_template{$sname}++;
  579. +     if ($build_templates && !defined $sizeof{$name}) {
  580. +     local($fmt) = &scrunch($template{$sname});
  581. +     print STDERR "no size for $name, punting with $fmt..." if $debug;
  582. +     eval '$sizeof{$name} = length(pack($fmt, ()))';
  583. +     if ($@) {
  584. +         chop $@;
  585. +         warn "couldn't get size for \$name: $@";
  586. +     } else {
  587. +         print STDERR $sizeof{$name}, "\n" if $debUg;
  588. +     }
  589. +     } 
  590. +     --$nesting;
  591. + }
  592. + sub psize {
  593. +     local($me) = @_; 
  594. +     local($amstruct) = $struct{$me} ?  'struct ' : '';
  595. +     print '$sizeof{\'', $amstruct, $me, '\'} = '; 
  596. +     printf "%d;\n", $sizeof{$me}; 
  597. + }
  598. + sub pdecl {
  599. +     local($pdecl) = @_;
  600. +     local(@pdecls);
  601. +     local($tname);
  602. +     warn "pdecl: $pdecl\n" if $debug;
  603. +     $pdecl =~ s/\(\d+,(\d+)\)/$1/g;
  604. +     $pdecl =~ s/\*//g; 
  605. +     @pdecls = split(/=/, $pdecl); 
  606. +     $typeno = $pdecls[0];
  607. +     $tname = pop @pdecls;
  608. +     if ($tname =~ s/^f//) { $tname = "$tname&"; } 
  609. +     #else { $tname = "$tname*"; } 
  610. +     for (reverse @pdecls) {
  611. +     $tname  .= s/^f// ? "&" : "*"; 
  612. +     #$tname =~ s/^f(.*)/$1&/;
  613. +     print "type[$_] is $tname\n" if $debug;
  614. +     $type[$_] = $tname unless defined $type[$_];
  615. +     } 
  616. + }
  617. + sub adecl {
  618. +     ($arraytype, $unknown, $lower, $upper) = ();
  619. +     #local($typeno);
  620. +     # global $typeno, @type
  621. +     local($_, $typedef) = @_;
  622. +     while (s/^((\d+)=)?ar(\d+);//) {
  623. +     ($arraytype, $unknown) = ($2, $3); 
  624. +     if (s/^(\d+);(\d+);//) {
  625. +         ($lower, $upper) = ($1, $2); 
  626. +         $scripts .= '[' .  ($upper+1) . ']'; 
  627. +     } else {
  628. +         warn "can't find array bounds: $_"; 
  629. +     } 
  630. +     }
  631. +     if (s/^([\d*f=]*),(\d+),(\d+);//) {
  632. +     ($start, $length) = ($2, $3); 
  633. +     local($whatis) = $1;
  634. +     if ($whatis =~ /^(\d+)=/) {
  635. +         $typeno = $1;
  636. +         &pdecl($whatis);
  637. +     } else {
  638. +         $typeno = $whatis;
  639. +     }
  640. +     } elsif (s/^(\d+)(=[*suf]\d*)//) {
  641. +     local($whatis) = $2; 
  642. +     if ($whatis =~ /[f*]/) {
  643. +         &pdecl($whatis); 
  644. +     } elsif ($whatis =~ /[su]/) {  # 
  645. +         print "$prefix.$fieldname is an array$scripts anon structs; disgusting\n" 
  646. +         if $debug;
  647. +         #$type[$typeno] = $name unless defined $type[$typeno];
  648. +         ##printf "new type $typeno is $name" if $debug;
  649. +         $typeno = $1;
  650. +         $type[$typeno] = "$prefix.$fieldname";
  651. +         local($name) = $type[$typeno];
  652. +         &sou($name, $whatis);
  653. +         $_ = &sdecl($name, $_, $start+$offset);
  654. +         1;
  655. +         $start = $start{$name};
  656. +         $offset = $sizeof{$name};
  657. +         $length = $offset;
  658. +     } else {
  659. +         warn "what's this? $whatis in $line ";
  660. +     } 
  661. +     } elsif (/^\d+$/) {
  662. +     $typeno = $_;
  663. +     } else {
  664. +     warn "bad array stab: $_ in $line ";
  665. +     next STAB;
  666. +     } 
  667. +     #local($wasdef) = defined($type[$typeno]) && $debug;
  668. +     #if ($typedef) { 
  669. +     #print "redefining $type[$typeno] to " if $wasdef;
  670. +     #$type[$typeno] = "$whatis$scripts"; # unless defined $type[$typeno];
  671. +     #print "$type[$typeno]\n" if $wasdef;
  672. +     #} else {
  673. +     #$type[$arraytype] = $type[$typeno] unless defined $type[$arraytype];
  674. +     #}
  675. +     $type[$arraytype] = "$type[$typeno]$scripts" if defined $type[$typeno];
  676. +     print "type[$arraytype] is $type[$arraytype]\n" if $debug;
  677. +     print "$prefix.$fieldname is an array of $type[$arraytype]\n" if $debug;
  678. +     $_;
  679. + }
  680. + sub sdecl {
  681. +     local($prefix, $_, $offset) = @_;
  682. +     local($fieldname, $scripts, $type, $arraytype, $unknown,
  683. +     $whatis, $pdecl, $upper,$lower, $start,$length) = ();
  684. +     local($typeno,$sou);
  685. + SFIELD:
  686. +     while (/^([^;]+);/) {
  687. +     $scripts = '';
  688. +     warn "sdecl $_\n" if $debug;
  689. +     if (s/^([\$\w]+)://) { 
  690. +         $fieldname = $1;
  691. +     } elsif (s/(\d+)=([us])(\d+|\(\d+,\d+\))//) { # 
  692. +         $typeno = &typeno($1);
  693. +         $type[$typeno] = "$prefix.$fieldname";
  694. +         local($name) = "$prefix.$fieldname";
  695. +         &sou($name,$2);
  696. +         $_ = &sdecl("$prefix.$fieldname", $_, $start+$offset);
  697. +         $start = $start{$name};
  698. +         $offset += $sizeof{$name};
  699. +         #print "done with anon, start is $start, offset is $offset\n";
  700. +         #next SFIELD;
  701. +     } else  {
  702. +         warn "weird field $_ of $line" if $debug;
  703. +         next STAB;
  704. +         #$fieldname = &gensym;
  705. +         #$_ = &sdecl("$prefix.$fieldname", $_, $start+$offset);
  706. +     }
  707. +     if (/^\d+=ar/) {
  708. +         $_ = &adecl($_);
  709. +     }
  710. +     elsif (s/^(\d+|\(\d+,\d+\))?,(\d+),(\d+);//) {
  711. +         ($start, $length) =  ($2, $3); 
  712. +         &panic("no length?") unless $length;
  713. +         $typeno = &typeno($1) if $1;
  714. +     }
  715. +     elsif (s/^((\d+|\(\d+,\d+\))(=[*f](\d+|\(\d+,\d+\)))+),(\d+),(\d+);//) {
  716. +         ($pdecl, $start, $length) =  ($1,$5,$6); 
  717. +         &pdecl($pdecl); 
  718. +     }
  719. +     elsif (s/(\d+)=([us])(\d+|\(\d+,\d+\))//) { # the dratted anon struct
  720. +         ($typeno, $sou) = ($1, $2);
  721. +         $typeno = &typeno($typeno);
  722. +         if (defined($type[$typeno])) {
  723. +         warn "now how did we get type $1 in $fieldname of $line?";
  724. +         } else {
  725. +         print "anon type $typeno is $prefix.$fieldname\n" if $debug;
  726. +         $type[$typeno] = "$prefix.$fieldname" unless defined $type[$typeno];
  727. +         };
  728. +         local($name) = "$prefix.$fieldname";
  729. +         &sou($name,$sou);
  730. +         print "anon ".($isastruct{$name}) ? "struct":"union"." for $prefix.$fieldname\n" if $debug;
  731. +         $type[$typeno] = "$prefix.$fieldname";
  732. +         $_ = &sdecl("$prefix.$fieldname", $_, $start+$offset); 
  733. +         $start = $start{$name};
  734. +         $length = $sizeof{$name};
  735. +     }
  736. +     else {
  737. +         warn "can't grok stab for $name ($_) in line $line "; 
  738. +         next STAB; 
  739. +     }
  740. +     &panic("no length for $prefix.$fieldname") unless $length;
  741. +     $struct{$name} .= join(',', $fieldname, $typeno, $scripts, $start, $length) . ';';
  742. +     }
  743. +     if (s/;\d*,(\d+),(\d+);//) {
  744. +     local($start, $size) = ($1, $2); 
  745. +     $sizeof{$prefix} = $size;
  746. +     print "start of $prefix is $start, size of $sizeof{$prefix}\n" if $debug; 
  747. +     $start{$prefix} = $start; 
  748. +     } 
  749. +     $_;
  750. + }
  751. + sub edecl {
  752. +     s/;$//;
  753. +     $enum{$name} = $_;
  754. +     $_ = '';
  755. + } 
  756. + sub resolve_types {
  757. +     local($sou);
  758. +     for $i (0 .. $#type) {
  759. +     next unless defined $type[$i];
  760. +     $_ = $type[$i];
  761. +     unless (/\d/) {
  762. +         print "type[$i] $type[$i]\n" if $debug;
  763. +         next;
  764. +     }
  765. +     print "type[$i] $_ ==> " if $debug;
  766. +     s/^(\d+)(\**)\&\*(\**)/"$2($3".&type($1) . ')()'/e;
  767. +     s/^(\d+)\&/&type($1)/e; 
  768. +     s/^(\d+)/&type($1)/e; 
  769. +     s/(\*+)([^*]+)(\*+)/$1$3$2/;
  770. +     s/\((\*+)(\w+)(\*+)\)/$3($1$2)/;
  771. +     s/^(\d+)([\*\[].*)/&type($1).$2/e;
  772. +     #s/(\d+)(\*|(\[[\[\]\d\*]+]\])+)/&type($1).$2/ge;
  773. +     $type[$i] = $_;
  774. +     print "$_\n" if $debug;
  775. +     }
  776. + }
  777. + sub type { &psou($type[$_[0]] || "<UNDEFINED>"); } 
  778. + sub adjust_start_addrs {
  779. +     for (sort keys %start) {
  780. +     ($basename = $_) =~ s/\.[^.]+$//;
  781. +     $start{$_} += $start{$basename};
  782. +     print "start: $_ @ $start{$_}\n" if $debug;
  783. +     }
  784. + }
  785. + sub sou {
  786. +     local($what, $_) = @_;
  787. +     /u/ && $isaunion{$what}++;
  788. +     /s/ && $isastruct{$what}++;
  789. + }
  790. + sub psou {
  791. +     local($what) = @_;
  792. +     local($prefix) = '';
  793. +     if ($isaunion{$what})  {
  794. +     $prefix = 'union ';
  795. +     } elsif ($isastruct{$what})  {
  796. +     $prefix = 'struct ';
  797. +     }
  798. +     $prefix . $what;
  799. + }
  800. + sub scrunch {
  801. +     local($_) = @_;
  802. +     study;
  803. +     s/\$//g;
  804. +     s/  / /g;
  805. +     1 while s/(\w) \1/$1$1/g;
  806. +     # i wanna say this, but perl resists my efforts:
  807. +     #       s/(\w)(\1+)/$2 . length($1)/ge;
  808. +     &quick_scrunch;
  809. +     s/ $//;
  810. +     $_;
  811. + }
  812. + sub buildscrunchlist {
  813. +     $scrunch_code = "sub quick_scrunch {\n";
  814. +     for (values %intrinsics) {
  815. +         $scrunch_code .= "\ts/($_{2,})/'$_' . length(\$1)/ge;\n";
  816. +     } 
  817. +     $scrunch_code .= "}\n";
  818. +     print "$scrunch_code" if $debug;
  819. +     eval $scrunch_code;
  820. +     &panic("can't eval scrunch_code $@ \nscrunch_code") if $@;
  821. + } 
  822. + sub fetch_template {
  823. +     local($mytype) = @_;
  824. +     local($fmt);
  825. +     local($count) = 1;
  826. +     &panic("why do you care?") unless $perl;
  827. +     if ($mytype =~ s/(\[\d+\])+$//) {
  828. +     $count .= $1;
  829. +     } 
  830. +     if ($mytype =~ /\*/) {
  831. +     $fmt = $template{'pointer'};
  832. +     } 
  833. +     elsif (defined $template{$mytype}) {
  834. +     $fmt = $template{$mytype};
  835. +     } 
  836. +     elsif (defined $struct{$mytype}) {
  837. +     if (!defined $template{&psou($mytype)}) {
  838. +         &build_template($mytype) unless $mytype eq $name;
  839. +     } 
  840. +     elsif ($template{&psou($mytype)} !~ /\$$/) {
  841. +         #warn "incomplete template for $mytype\n";
  842. +     } 
  843. +     $fmt = $template{&psou($mytype)} || '?';
  844. +     } 
  845. +     else {
  846. +     warn "unknown fmt for $mytype\n";
  847. +     $fmt = '?';
  848. +     } 
  849. +     $fmt x $count . ' ';
  850. + }
  851. + sub compute_intrinsics {
  852. +     local($TMP) = "/tmp/c2ph-i.$$.c";
  853. +     open (TMP, ">$TMP") || die "can't open $TMP: $!";
  854. +     select(TMP);
  855. +     print STDERR "computing intrinsic sizes: " if $trace;
  856. +     undef %intrinsics;
  857. +     print <<'EOF';
  858. + main() {
  859. +     char *mask = "%d %s\n";
  860. + EOF
  861. +     for $type (@intrinsics) {
  862. +     next if $type eq 'void';
  863. +     print <<"EOF";
  864. +     printf(mask,sizeof($type), "$type");
  865. + EOF
  866. +     } 
  867. +     print <<'EOF';
  868. +     printf(mask,sizeof(char *), "pointer");
  869. +     exit(0);
  870. + }
  871. + EOF
  872. +     close TMP;
  873. +     select(STDOUT);
  874. +     open(PIPE, "cd /tmp && $CC $TMP && /tmp/a.out|");
  875. +     while (<PIPE>) {
  876. +     chop;
  877. +     split(' ',$_,2);;
  878. +     print "intrinsic $_[1] is size $_[0]\n" if $debug;
  879. +     $sizeof{$_[1]} = $_[0];
  880. +     $intrinsics{$_[1]} = $template{$_[0]};
  881. +     } 
  882. +     close(PIPE) || die "couldn't read intrinsics!";
  883. +     unlink($TMP, '/tmp/a.out');
  884. +     print STDERR "done\n" if $trace;
  885. + } 
  886. + sub scripts2count {
  887. +     local($_) = @_;
  888. +     s/^\[//;
  889. +     s/\]$//;
  890. +     s/\]\[/*/g;
  891. +     $_ = eval;
  892. +     &panic("$_: $@") if $@;
  893. +     $_;
  894. + }
  895. + sub system {
  896. +     print STDERR "@_\n" if $trace;
  897. +     system @_;
  898. + } 
  899. + sub build_template { 
  900. +     local($name) = @_;
  901. +     &panic("already got a template for $name") if defined $template{$name};
  902. +     local($build_templates) = 1;
  903. +     local($lparen) = '(' x $build_recursed;
  904. +     local($rparen) = ')' x $build_recursed;
  905. +     print STDERR "$lparen$name$rparen " if $trace;
  906. +     $build_recursed++;
  907. +     &pstruct($name,$name,0);
  908. +     print STDERR "TEMPLATE for $name is ", $template{&psou($name)}, "\n" if $debug;
  909. +     --$build_recursed;
  910. + }
  911. + sub panic {
  912. +     select(STDERR);
  913. +     print "\npanic: @_\n";
  914. +     exit 1 if $] <= 4.003;  # caller broken
  915. +     local($i,$_);
  916. +     local($p,$f,$l,$s,$h,$a,@a,@sub);
  917. +     for ($i = 0; ($p,$f,$l,$s,$h,$w) = caller($i); $i++) {
  918. +     @a = @DB'args;
  919. +     for (@a) {
  920. +         if (/^StB\000/ && length($_) == length($_main{'_main'})) {
  921. +         $_ = sprintf("%s",$_);
  922. +         }
  923. +         else {
  924. +         s/'/\\'/g;
  925. +         s/([^\0]*)/'$1'/ unless /^-?[\d.]+$/;
  926. +         s/([\200-\377])/sprintf("M-%c",ord($1)&0177)/eg;
  927. +         s/([\0-\37\177])/sprintf("^%c",ord($1)^64)/eg;
  928. +         }
  929. +     }
  930. +     $w = $w ? '@ = ' : '$ = ';
  931. +     $a = $h ? '(' . join(', ', @a) . ')' : '';
  932. +     push(@sub, "$w&$s$a from file $f line $l\n");
  933. +     last if $signal;
  934. +     }
  935. +     for ($i=0; $i <= $#sub; $i++) {
  936. +     last if $signal;
  937. +     print $sub[$i];
  938. +     }
  939. +     exit 1;
  940. + } 
  941. + sub squishseq {
  942. +     local($num);
  943. +     local($last) = -1e8;
  944. +     local($string);
  945. +     local($seq) = '..';
  946. +     while (defined($num = shift)) {
  947. +         if ($num == ($last + 1)) {
  948. +             $string .= $seq unless $inseq++;
  949. +             $last = $num;
  950. +             next;
  951. +         } elsif ($inseq) {
  952. +             $string .= $last unless $last == -1e8;
  953. +         }
  954. +         $string .= ',' if defined $string;
  955. +         $string .= $num;
  956. +         $last = $num;
  957. +         $inseq = 0;
  958. +     }
  959. +     $string .= $last if $inseq && $last != -e18;
  960. +     $string;
  961. + }
  962. + !NO!SUBS!
  963. + $eunicefix c2ph
  964. + rm -f pstruct
  965. + ln c2ph pstruct
  966.  
  967. Index: c2ph.doc
  968. *** c2ph.doc.old    Tue Nov  5 19:25:36 1991
  969. --- c2ph.doc    Tue Nov  5 19:25:36 1991
  970. ***************
  971. *** 0 ****
  972. --- 1,191 ----
  973. + Article 484 of comp.lang.perl:
  974. + Xref: netlabs comp.lang.perl:484 comp.lang.c:983 alt.sources:134
  975. + Path: netlabs!psinntp!iggy.GW.Vitalink.COM!lll-winken!sun-barr!cronkite.Central.Sun.COM!spdev!texsun!convex!tchrist
  976. + From: tchrist@convex.com (Tom Christiansen)
  977. + Newsgroups: comp.lang.perl,comp.lang.c,alt.sources
  978. + Subject: pstruct -- a C structure formatter; AKA c2ph, a C to perl header translator
  979. + Keywords: C perl tranlator
  980. + Message-ID: <1991Jul25.081021.8104@convex.com>
  981. + Date: 25 Jul 91 08:10:21 GMT
  982. + Sender: usenet@convex.com (news access account)
  983. + Followup-To: comp.lang.perl
  984. + Organization: CONVEX Computer Corporation, Richardson, Tx., USA
  985. + Lines: 1208
  986. + Nntp-Posting-Host: pixel.convex.com
  987. + Once upon a time, I wrote a program called pstruct.  It was a perl 
  988. + program that tried to parse out C structures and display their member
  989. + offsets for you.  This was especially useful for people looking at
  990. + binary dumps or poking around the kernel.  
  991. + Pstruct was not a pretty program.  Neither was it particularly robust.
  992. + The problem, you see, was that the C compiler was much better at parsing
  993. + C than I could ever hope to be.  
  994. + So I got smart:  I decided to be lazy and let the C compiler parse the C,
  995. + which would spit out debugger stabs for me to read.  These were much
  996. + easier to parse.  It's still not a pretty program, but at least it's more
  997. + robust.  
  998. + Pstruct takes any .c or .h files, or preferably .s ones, since that's
  999. + the format it is going to massage them into anyway, and spits out
  1000. + listings like this:
  1001. + struct tty {
  1002. +   int                          tty.t_locker                         000      4
  1003. +   int                          tty.t_mutex_index                    004      4
  1004. +   struct tty *                 tty.t_tp_virt                        008      4
  1005. +   struct clist                 tty.t_rawq                           00c     20
  1006. +     int                        tty.t_rawq.c_cc                      00c      4
  1007. +     int                        tty.t_rawq.c_cmax                    010      4
  1008. +     int                        tty.t_rawq.c_cfx                     014      4
  1009. +     int                        tty.t_rawq.c_clx                     018      4
  1010. +     struct tty *               tty.t_rawq.c_tp_cpu                  01c      4
  1011. +     struct tty *               tty.t_rawq.c_tp_iop                  020      4
  1012. +     unsigned char *            tty.t_rawq.c_buf_cpu                 024      4
  1013. +     unsigned char *            tty.t_rawq.c_buf_iop                 028      4
  1014. +   struct clist                 tty.t_canq                           02c     20
  1015. +     int                        tty.t_canq.c_cc                      02c      4
  1016. +     int                        tty.t_canq.c_cmax                    030      4
  1017. +     int                        tty.t_canq.c_cfx                     034      4
  1018. +     int                        tty.t_canq.c_clx                     038      4
  1019. +     struct tty *               tty.t_canq.c_tp_cpu                  03c      4
  1020. +     struct tty *               tty.t_canq.c_tp_iop                  040      4
  1021. +     unsigned char *            tty.t_canq.c_buf_cpu                 044      4
  1022. +     unsigned char *            tty.t_canq.c_buf_iop                 048      4
  1023. +   struct clist                 tty.t_outq                           04c     20
  1024. +     int                        tty.t_outq.c_cc                      04c      4
  1025. +     int                        tty.t_outq.c_cmax                    050      4
  1026. +     int                        tty.t_outq.c_cfx                     054      4
  1027. +     int                        tty.t_outq.c_clx                     058      4
  1028. +     struct tty *               tty.t_outq.c_tp_cpu                  05c      4
  1029. +     struct tty *               tty.t_outq.c_tp_iop                  060      4
  1030. +     unsigned char *            tty.t_outq.c_buf_cpu                 064      4
  1031. +     unsigned char *            tty.t_outq.c_buf_iop                 068      4
  1032. +   (*int)()                     tty.t_oproc_cpu                      06c      4
  1033. +   (*int)()                     tty.t_oproc_iop                      070      4
  1034. +   (*int)()                     tty.t_stopproc_cpu                   074      4
  1035. +   (*int)()                     tty.t_stopproc_iop                   078      4
  1036. +   struct thread *              tty.t_rsel                           07c      4
  1037. +   etc.
  1038. + Actually, this was generated by a particular set of options.  You can control
  1039. + the formatting of each column, whether you prefer wide or fat, hex or decimal,
  1040. + leading zeroes or whatever.
  1041. + All you need to be able to use this is a C compiler than generates
  1042. + BSD/GCC-style stabs.  The -g option on native BSD compilers and GCC
  1043. + should get this for you.   
  1044. + To learn more, just type a bogus option, like -\?, and a long usage message
  1045. + will be provided.  There are a fair number of possibilities.
  1046. + If you're only a C programmer, than this is the end of the message for you.
  1047. + You can quit right now, and if you care to, save off the source and run it
  1048. + when you feel like it.  Or not.
  1049. + But if you're a perl programmer, then for you I have something much more
  1050. + wondrous than just a structure offset printer.
  1051. + You see, if you call pstruct by its other incybernation, c2ph, you have a code
  1052. + generator that translates C code into perl code!  Well, structure and union 
  1053. + declarations at least, but that's quite a bit.  
  1054. + Prior to this point, anyone programming in perl who wanted to interact
  1055. + with C programs, like the kernel, was forced to guess the layouts of the C
  1056. + strutures, and then hardwire these into his program.  Of course, when you
  1057. + took your wonderfully to a system where the sgtty structure was laid out
  1058. + differently, you program broke.  Which is a shame.
  1059. + We've had Larry's h2ph translator, which helped, but that only works on
  1060. + cpp symbols, not real C, which was also very much needed.  What I offer
  1061. + you is a symbolic way of getting at all the C structures.  I've couched
  1062. + them in terms of packages and functions.  Consider the following program:
  1063. +     #!/usr/local/bin/perl
  1064. +     require 'syscall.ph';
  1065. +     require 'sys/time.ph';
  1066. +     require 'sys/resource.ph';
  1067. +     $ru = "\0" x &rusage'sizeof();
  1068. +     syscall(&SYS_getrusage, &RUSAGE_SELF, $ru)      && die "getrusage: $!";
  1069. +     @ru = unpack($t = &rusage'typedef(), $ru);
  1070. +     $utime =  $ru[ &rusage'ru_utime + &timeval'tv_sec  ]
  1071. +        + ($ru[ &rusage'ru_utime + &timeval'tv_usec ]) / 1e6;
  1072. +     $stime =  $ru[ &rusage'ru_stime + &timeval'tv_sec  ]
  1073. +        + ($ru[ &rusage'ru_stime + &timeval'tv_usec ]) / 1e6;
  1074. +     printf "you have used %8.3fs+%8.3fu seconds.\n", $utime, $stime;
  1075. + As you see, the name of the package is the name of the structure.  Regular
  1076. + fields are just their own names.  Plus the follwoing  accessor functions are
  1077. + provided for your convenience:
  1078. +     struct    This takes no arguments, and is merely the number of first-level
  1079. +         elements in the structure.  You would use this for indexing
  1080. +         into arrays of structures, perhaps like this
  1081. +             
  1082. +             $usec = $u[ &user'u_utimer
  1083. +                 + (&ITIMER_VIRTUAL * &itimerval'struct)
  1084. +                 + &itimerval'it_value
  1085. +                 + &timeval'tv_usec
  1086. +                   ];
  1087. +     sizeof       Returns the bytes in the structure, or the member if 
  1088. +              you pass it an argument, such as
  1089. +             &rusage'sizeof(&rusage'ru_utime)
  1090. +     typedef      This is the perl format definition for passing to pack and
  1091. +              unpack.  If you ask for the typedef of a nothing, you get 
  1092. +              the whole structure, otherwise you get that of the member
  1093. +              you ask for.  Padding is taken care of, as is the magic to 
  1094. +              guarantee that a union is unpacked into all its aliases.
  1095. +              Bitfields are not quite yet supported however.
  1096. +     offsetof    This function is the byte offset into the array of that
  1097. +         member.  You may wish to use this for indexing directly
  1098. +         into the packed structure with vec() if you're too lazy
  1099. +         to unpack it.
  1100. +     typeof    Not to be confused with the typedef accessor function, this
  1101. +         one returns the C type of that field.  This would allow 
  1102. +         you to print out a nice structured pretty print of some
  1103. +         structure without knoning anything about it beforehand.
  1104. +         No args to this one is a noop.  Someday I'll post such 
  1105. +         a thing to dump out your u structure for you.
  1106. + The way I see this being used is like basically this:
  1107. +     % h2ph <some_include_file.h  >  /usr/lib/perl/tmp.ph
  1108. +     % c2ph  some_include_file.h  >> /usr/lib/perl/tmp.ph
  1109. +     % install 
  1110. + It's a little tricker with c2ph because you have to get the includes right.
  1111. + I can't know this for your system, but it's not usually too terribly difficult.  
  1112. + The code isn't pretty as I mentioned  -- I never thought it would be a 1000-
  1113. + line program when I started, or I might not have begun. :-)  But I would have
  1114. + been less cavalier in how the parts of the program communicated with each 
  1115. + other, etc.  It might also have helped if I didn't have to divine the makeup
  1116. + of the stabs on the fly, and then account for micro differences between my 
  1117. + compiler and gcc. 
  1118. + Anyway, here it is.  Should run on perl v4 or greater.  Maybe less.
  1119. + --tom
  1120.  
  1121. Index: cflags.SH
  1122. *** cflags.SH.old    Tue Nov  5 19:25:38 1991
  1123. --- cflags.SH    Tue Nov  5 19:25:38 1991
  1124. ***************
  1125. *** 6,12 ****
  1126.       ln ../../../config.sh . || \
  1127.       (echo "Can't find config.sh."; exit 1)
  1128.       fi
  1129. !     . config.sh
  1130.       ;;
  1131.   esac
  1132.   : This forces SH files to create target in same directory as SH file.
  1133. --- 6,12 ----
  1134.       ln ../../../config.sh . || \
  1135.       (echo "Can't find config.sh."; exit 1)
  1136.       fi
  1137. !     . ./config.sh
  1138.       ;;
  1139.   esac
  1140.   : This forces SH files to create target in same directory as SH file.
  1141.  
  1142. Index: lib/chat2.pl
  1143. *** lib/chat2.pl.old    Tue Nov  5 19:26:52 1991
  1144. --- lib/chat2.pl    Tue Nov  5 19:26:52 1991
  1145. ***************
  1146. *** 0 ****
  1147. --- 1,333 ----
  1148. + ## chat.pl: chat with a server
  1149. + ## V2.01.alpha.7 91/06/16
  1150. + ## Randal L. Schwartz
  1151. + package chat;
  1152. + $sockaddr = 'S n a4 x8';
  1153. + chop($thishost = `hostname`); $thisaddr = (gethostbyname($thishost))[4];
  1154. + $thisproc = pack($sockaddr, 2, 0, $thisaddr);
  1155. + # *S = symbol for current I/O, gets assigned *chatsymbol....
  1156. + $next = "chatsymbol000000"; # next one
  1157. + $nextpat = "^chatsymbol"; # patterns that match next++, ++, ++, ++
  1158. + ## $handle = &chat'open_port("server.address",$port_number);
  1159. + ## opens a named or numbered TCP server
  1160. + sub open_port { ## public
  1161. +     local($server, $port) = @_;
  1162. +     local($serveraddr,$serverproc);
  1163. +     *S = ++$next;
  1164. +     if ($server =~ /^(\d+)+\.(\d+)\.(\d+)\.(\d+)$/) {
  1165. +         $serveraddr = pack('C4', $1, $2, $3, $4);
  1166. +     } else {
  1167. +         local(@x) = gethostbyname($server);
  1168. +         return undef unless @x;
  1169. +         $serveraddr = $x[4];
  1170. +     }
  1171. +     $serverproc = pack($sockaddr, 2, $port, $serveraddr);
  1172. +     unless (socket(S, 2, 1, 6)) {
  1173. +         # XXX hardwired $AF_SOCKET, $SOCK_STREAM, 'tcp'
  1174. +         # but who the heck would change these anyway? (:-)
  1175. +         ($!) = ($!, close(S)); # close S while saving $!
  1176. +         return undef;
  1177. +     }
  1178. +     unless (bind(S, $thisproc)) {
  1179. +         ($!) = ($!, close(S)); # close S while saving $!
  1180. +         return undef;
  1181. +     }
  1182. +     unless (connect(S, $serverproc)) {
  1183. +         ($!) = ($!, close(S)); # close S while saving $!
  1184. +         return undef;
  1185. +     }
  1186. +     select((select(S), $| = 1)[0]);
  1187. +     $next; # return symbol for switcharound
  1188. + }
  1189. + ## ($host, $port, $handle) = &chat'open_listen([$port_number]);
  1190. + ## opens a TCP port on the current machine, ready to be listened to
  1191. + ## if $port_number is absent or zero, pick a default port number
  1192. + ## process must be uid 0 to listen to a low port number
  1193. + sub open_listen { ## public
  1194. +     *S = ++$next;
  1195. +     local($thisport) = shift || 0;
  1196. +     local($thisproc_local) = pack($sockaddr, 2, $thisport, $thisaddr);
  1197. +     local(*NS) = "__" . time;
  1198. +     unless (socket(NS, 2, 1, 6)) {
  1199. +         # XXX hardwired $AF_SOCKET, $SOCK_STREAM, 'tcp'
  1200. +         # but who the heck would change these anyway? (:-)
  1201. +         ($!) = ($!, close(NS));
  1202. +         return undef;
  1203. +     }
  1204. +     unless (bind(NS, $thisproc_local)) {
  1205. +         ($!) = ($!, close(NS));
  1206. +         return undef;
  1207. +     }
  1208. +     unless (listen(NS, 1)) {
  1209. +         ($!) = ($!, close(NS));
  1210. +         return undef;
  1211. +     }
  1212. +     select((select(NS), $| = 1)[0]);
  1213. +     local($family, $port, @myaddr) =
  1214. +         unpack("S n C C C C x8", getsockname(NS));
  1215. +     $S{"needs_accept"} = *NS; # so expect will open it
  1216. +     (@myaddr, $port, $next); # returning this
  1217. + }
  1218. + ## $handle = &chat'open_proc("command","arg1","arg2",...);
  1219. + ## opens a /bin/sh on a pseudo-tty
  1220. + sub open_proc { ## public
  1221. +     local(@cmd) = @_;
  1222. +     *S = ++$next;
  1223. +     local(*TTY) = "__TTY" . time;
  1224. +     local($pty,$tty) = &_getpty(S,TTY);
  1225. +     die "Cannot find a new pty" unless defined $pty;
  1226. +     local($pid) = fork;
  1227. +     die "Cannot fork: $!" unless defined $pid;
  1228. +     unless ($pid) {
  1229. +         close STDIN; close STDOUT; close STDERR;
  1230. +         setpgrp(0,$$);
  1231. +         if (open(DEVTTY, "/dev/tty")) {
  1232. +             ioctl(DEVTTY,0x20007471,0);        # XXX s/b &TIOCNOTTY
  1233. +             close DEVTTY;
  1234. +         }
  1235. +         open(STDIN,"<&TTY");
  1236. +         open(STDOUT,">&TTY");
  1237. +         open(STDERR,">&STDOUT");
  1238. +         die "Oops" unless fileno(STDERR) == 2;    # sanity
  1239. +         close(S);
  1240. +         exec @cmd;
  1241. +         die "Cannot exec @cmd: $!";
  1242. +     }
  1243. +     close(TTY);
  1244. +     $next; # return symbol for switcharound
  1245. + }
  1246. + # $S is the read-ahead buffer
  1247. + ## $return = &chat'expect([$handle,] $timeout_time,
  1248. + ##     $pat1, $body1, $pat2, $body2, ... )
  1249. + ## $handle is from previous &chat'open_*().
  1250. + ## $timeout_time is the time (either relative to the current time, or
  1251. + ## absolute, ala time(2)) at which a timeout event occurs.
  1252. + ## $pat1, $pat2, and so on are regexs which are matched against the input
  1253. + ## stream.  If a match is found, the entire matched string is consumed,
  1254. + ## and the corresponding body eval string is evaled.
  1255. + ##
  1256. + ## Each pat is a regular-expression (probably enclosed in single-quotes
  1257. + ## in the invocation).  ^ and $ will work, respecting the current value of $*.
  1258. + ## If pat is 'TIMEOUT', the body is executed if the timeout is exceeded.
  1259. + ## If pat is 'EOF', the body is executed if the process exits before
  1260. + ## the other patterns are seen.
  1261. + ##
  1262. + ## Pats are scanned in the order given, so later pats can contain
  1263. + ## general defaults that won't be examined unless the earlier pats
  1264. + ## have failed.
  1265. + ##
  1266. + ## The result of eval'ing body is returned as the result of
  1267. + ## the invocation.  Recursive invocations are not thought
  1268. + ## through, and may work only accidentally. :-)
  1269. + ##
  1270. + ## undef is returned if either a timeout or an eof occurs and no
  1271. + ## corresponding body has been defined.
  1272. + ## I/O errors of any sort are treated as eof.
  1273. + $nextsubname = "expectloop000000"; # used for subroutines
  1274. + sub expect { ## public
  1275. +     if ($_[0] =~ /$nextpat/) {
  1276. +         *S = shift;
  1277. +     }
  1278. +     local($endtime) = shift;
  1279. +     local($timeout,$eof) = (1,1);
  1280. +     local($caller) = caller;
  1281. +     local($rmask, $nfound, $timeleft, $thisbuf);
  1282. +     local($cases, $pattern, $action, $subname);
  1283. +     $endtime += time if $endtime < 600_000_000;
  1284. +     if (defined $S{"needs_accept"}) { # is it a listen socket?
  1285. +         local(*NS) = $S{"needs_accept"};
  1286. +         delete $S{"needs_accept"};
  1287. +         $S{"needs_close"} = *NS;
  1288. +         unless(accept(S,NS)) {
  1289. +             ($!) = ($!, close(S), close(NS));
  1290. +             return undef;
  1291. +         }
  1292. +         select((select(S), $| = 1)[0]);
  1293. +     }
  1294. +     # now see whether we need to create a new sub:
  1295. +     unless ($subname = $expect_subname{$caller,@_}) {
  1296. +         # nope.  make a new one:
  1297. +         $expect_subname{$caller,@_} = $subname = $nextsubname++;
  1298. +         $cases .= <<"EDQ"; # header is funny to make everything elsif's
  1299. + sub $subname {
  1300. +     LOOP: {
  1301. +         if (0) { ; }
  1302. + EDQ
  1303. +         while (@_) {
  1304. +             ($pattern,$action) = splice(@_,0,2);
  1305. +             if ($pattern =~ /^eof$/i) {
  1306. +                 $cases .= <<"EDQ";
  1307. +         elsif (\$eof) {
  1308. +              package $caller;
  1309. +             $action;
  1310. +         }
  1311. + EDQ
  1312. +                 $eof = 0;
  1313. +             } elsif ($pattern =~ /^timeout$/i) {
  1314. +             $cases .= <<"EDQ";
  1315. +         elsif (\$timeout) {
  1316. +              package $caller;
  1317. +             $action;
  1318. +         }
  1319. + EDQ
  1320. +                 $timeout = 0;
  1321. +             } else {
  1322. +                 $pattern =~ s#/#\\/#g;
  1323. +             $cases .= <<"EDQ";
  1324. +         elsif (\$S =~ /$pattern/) {
  1325. +             \$S = \$';
  1326. +              package $caller;
  1327. +             $action;
  1328. +         }
  1329. + EDQ
  1330. +             }
  1331. +         }
  1332. +         $cases .= <<"EDQ" if $eof;
  1333. +         elsif (\$eof) {
  1334. +             undef;
  1335. +         }
  1336. + EDQ
  1337. +         $cases .= <<"EDQ" if $timeout;
  1338. +         elsif (\$timeout) {
  1339. +             undef;
  1340. +         }
  1341. + EDQ
  1342. +         $cases .= <<'ESQ';
  1343. +         else {
  1344. +             $rmask = "";
  1345. +             vec($rmask,fileno(S),1) = 1;
  1346. +             ($nfound, $rmask) =
  1347. +                  select($rmask, undef, undef, $endtime - time);
  1348. +             if ($nfound) {
  1349. +                 $nread = sysread(S, $thisbuf, 1024);
  1350. +                 if ($nread > 0) {
  1351. +                     $S .= $thisbuf;
  1352. +                 } else {
  1353. +                     $eof++, redo LOOP; # any error is also eof
  1354. +                 }
  1355. +             } else {
  1356. +                 $timeout++, redo LOOP; # timeout
  1357. +             }
  1358. +             redo LOOP;
  1359. +         }
  1360. +     }
  1361. + }
  1362. + ESQ
  1363. +         eval $cases; die "$cases:\n$@" if $@;
  1364. +     }
  1365. +     $eof = $timeout = 0;
  1366. +     do $subname();
  1367. + }
  1368. + ## &chat'print([$handle,] @data)
  1369. + ## $handle is from previous &chat'open().
  1370. + ## like print $handle @data
  1371. + sub print { ## public
  1372. +     if ($_[0] =~ /$nextpat/) {
  1373. +         *S = shift;
  1374. +     }
  1375. +     print S @_;
  1376. + }
  1377. + ## &chat'close([$handle,])
  1378. + ## $handle is from previous &chat'open().
  1379. + ## like close $handle
  1380. + sub close { ## public
  1381. +     if ($_[0] =~ /$nextpat/) {
  1382. +          *S = shift;
  1383. +     }
  1384. +     close(S);
  1385. +     if (defined $S{"needs_close"}) { # is it a listen socket?
  1386. +         local(*NS) = $S{"needs_close"};
  1387. +         delete $S{"needs_close"};
  1388. +         close(NS);
  1389. +     }
  1390. + }
  1391. + ## @ready_handles = &chat'select($timeout, @handles)
  1392. + ## select()'s the handles with a timeout value of $timeout seconds.
  1393. + ## Returns an array of handles that are ready for I/O.
  1394. + ## Both user handles and chat handles are supported (but beware of
  1395. + ## stdio's buffering for user handles).
  1396. + sub select { ## public
  1397. +     local($timeout) = shift;
  1398. +     local(@handles) = @_;
  1399. +     local(%handlename) = ();
  1400. +     local(%ready) = ();
  1401. +     local($caller) = caller;
  1402. +     local($rmask) = "";
  1403. +     for (@handles) {
  1404. +         if (/$nextpat/o) { # one of ours... see if ready
  1405. +             local(*SYM) = $_;
  1406. +             if (length($SYM)) {
  1407. +                 $timeout = 0; # we have a winner
  1408. +                 $ready{$_}++;
  1409. +             }
  1410. +             $handlename{fileno($_)} = $_;
  1411. +         } else {
  1412. +             $handlename{fileno(/'/ ? $_ : "$caller\'$_")} = $_;
  1413. +         }
  1414. +     }
  1415. +     for (sort keys %handlename) {
  1416. +         vec($rmask, $_, 1) = 1;
  1417. +     }
  1418. +     select($rmask, undef, undef, $timeout);
  1419. +     for (sort keys %handlename) {
  1420. +         $ready{$handlename{$_}}++ if vec($rmask,$_,1);
  1421. +     }
  1422. +     sort keys %ready;
  1423. + }
  1424. + # ($pty,$tty) = $chat'_getpty(PTY,TTY):
  1425. + # internal procedure to get the next available pty.
  1426. + # opens pty on handle PTY, and matching tty on handle TTY.
  1427. + # returns undef if can't find a pty.
  1428. + sub _getpty { ## private
  1429. +     local($_PTY,$_TTY) = @_;
  1430. +     $_PTY =~ s/^([^']+)$/(caller)[$[]."'".$1/e;
  1431. +     $_TTY =~ s/^([^']+)$/(caller)[$[]."'".$1/e;
  1432. +     local($pty,$tty);
  1433. +     for $bank (112..127) {
  1434. +         next unless -e sprintf("/dev/pty%c0", $bank);
  1435. +         for $unit (48..57) {
  1436. +             $pty = sprintf("/dev/pty%c%c", $bank, $unit);
  1437. +             open($_PTY,"+>$pty") || next;
  1438. +             select((select($_PTY), $| = 1)[0]);
  1439. +             ($tty = $pty) =~ s/pty/tty/;
  1440. +             open($_TTY,"+>$tty") || next;
  1441. +             select((select($_TTY), $| = 1)[0]);
  1442. +             system "stty nl>$tty";
  1443. +             return ($pty,$tty);
  1444. +         }
  1445. +     }
  1446. +     undef;
  1447. + }
  1448. + 1;
  1449.  
  1450. *** End of Patch 12 ***
  1451. exit 0 # Just in case...
  1452. -- 
  1453. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1454. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1455. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1456. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1457.