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