1#!/bin/awk -f 2# scripts/dfn.awk - process a .dfn file 3# 4# last changed in libpng version 1.5.19 - August 21, 2014 5# 6# Copyright (c) 2013-2014 Glenn Randers-Pehrson 7# 8# This code is released under the libpng license. 9# For conditions of distribution and use, see the disclaimer 10# and license in png.h 11 12# The output of this script is written to the file given by 13# the variable 'out', which should be set on the command line. 14# Error messages are printed to stdout and if any are printed 15# the script will exit with error code 1. 16 17BEGIN{ 18 out="/dev/null" # as a flag 19 out_count=0 # count of output lines 20 err=0 # set if an error occurred 21 sort=0 # sort the output 22 array[""]="" 23} 24 25# The output file must be specified before any input: 26NR==1 && out == "/dev/null" { 27 print "out=output.file must be given on the command line" 28 # but continue without setting the error code; this allows the 29 # script to be checked easily 30} 31 32# Output can be sorted; two lines are recognized 33$1 == "PNG_DFN_START_SORT"{ 34 sort=0+$2 35 next 36} 37 38$1 ~ /^PNG_DFN_END_SORT/{ 39 # Do a very simple, slow, sort; notice that blank lines won't be 40 # output by this 41 for (entry in array) { 42 while (array[entry] != "") { 43 key = entry 44 value = array[key] 45 array[key] = "" 46 47 for (alt in array) { 48 if (array[alt] != "" && alt < key) { 49 array[key] = value 50 value = array[alt] 51 key = alt 52 array[alt] = "" 53 } 54 } 55 56 print value >out 57 } 58 } 59 sort=0 60 next 61} 62 63/^[^"]*PNG_DFN *".*"[^"]*$/{ 64 # A definition line, apparently correctly formatted; extract the 65 # definition then replace any doubled "" that remain with a single 66 # double quote. Notice that the original doubled double quotes 67 # may have been split by tokenization 68 # 69 # Sometimes GCC splits the PNG_DFN lines; we know this has happened 70 # if the quotes aren't closed and must read another line. In this 71 # case it is essential to reject lines that start with '#' because those 72 # are introduced #line directives. 73 orig=$0 74 line=$0 75 lineno=FNR 76 if (lineno == "") lineno=NR 77 78 if (sub(/^[^"]*PNG_DFN *"/,"",line) != 1) { 79 print "line", lineno ": processing failed:" 80 print orig 81 err=1 82 next 83 } else { 84 ++out_count 85 } 86 87 # Now examine quotes within the value: 88 # 89 # @" - delete this and any following spaces 90 # "@ - delete this and any preceding spaces 91 # @' - replace this by a double quote 92 # 93 # This allows macro substitution by the C compiler thus: 94 # 95 # #define first_name John 96 # #define last_name Smith 97 # 98 # PNG_DFN"#define name @'@" first_name "@ @" last_name "@@'" 99 # 100 # Might get C preprocessed to: 101 # 102 # PNG_DFN "#define foo @'@" John "@ @" Smith "@@'" 103 # 104 # Which this script reduces to: 105 # 106 # #define name "John Smith" 107 # 108 while (1) { 109 # While there is an @" remove it and the next "@ 110 if (line ~ /@"/) { 111 if (line ~ /@".*"@/) { 112 # Do this special case first to avoid swallowing extra spaces 113 # before or after the @ stuff: 114 if (!sub(/@" *"@/, "", line)) { 115 # Ok, do it in pieces - there has to be a non-space between the 116 # two. NOTE: really weird things happen if a leading @" is 117 # lost - the code will error out below (I believe). 118 if (!sub(/@" */, "", line) || !sub(/ *"@/, "", line)) { 119 print "line", lineno, ": internal error:", orig 120 exit 1 121 } 122 } 123 } 124 125 # There is no matching "@. Assume a split line 126 else while (1) { 127 if (getline nextline) { 128 # If the line starts with '#' it is a preprocesor line directive 129 # from cc -E; skip it: 130 if (nextline !~ /^#/) { 131 line = line " " nextline 132 break 133 } 134 } else { 135 # This is end-of-input - probably a missing "@ on the first line: 136 print "line", lineno ": unbalanced @\" ... \"@ pair" 137 err=1 138 next 139 } 140 } 141 142 # Keep going until all the @" have gone 143 continue 144 } 145 146 # Attempt to remove a trailing " (not preceded by '@') - if this can 147 # be done, stop now; if not assume a split line again 148 if (sub(/"[^"]*$/, "", line)) 149 break 150 151 # Read another line 152 while (1) { 153 if (getline nextline) { 154 if (nextline !~ /^#/) { 155 line = line " " nextline 156 # Go back to stripping @" "@ pairs 157 break 158 } 159 } else { 160 print "line", lineno ": unterminated PNG_DFN string" 161 err=1 162 next 163 } 164 } 165 } 166 167 # Put any needed double quotes in (at the end, because these would otherwise 168 # interfere with the processing above.) 169 gsub(/@'/,"\"", line) 170 171 # Remove any trailing spaces (not really required, but for 172 # editorial consistency 173 sub(/ *$/, "", line) 174 175 # Remove trailing CR 176 sub(/ 177$/, "", line) 178 179 if (sort) { 180 if (split(line, parts) < sort) { 181 print "line", lineno ": missing sort field:", line 182 err=1 183 } else 184 array[parts[sort]] = line 185 } 186 187 else 188 print line >out 189 next 190} 191 192/PNG_DFN/{ 193 print "line", NR, "incorrectly formatted PNG_DFN line:" 194 print $0 195 err = 1 196} 197 198END{ 199 if (out_count > 0 || err > 0) 200 exit err 201 202 print "no definition lines found" 203 exit 1 204} 205