Another copy of my dotfiles. Because I don't completely trust GitHub.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

345 lines
8.0 KiB

  1. #!/bin/bash
  2. KEEP_FILES=0
  3. ECHO_COMMANDS=0
  4. RUN_SCRIPT=0
  5. DIRECTORY=.
  6. OUTPUT_DIRECTORY=
  7. KEEP_GITFILES=0
  8. DEBUG=0
  9. if [[ $# = 0 ]]; then
  10. set -- '-h'
  11. fi
  12. while (( $# )); do
  13. case "$1" in
  14. -d|--directory)
  15. shift
  16. DIRECTORY=$1 # source directory
  17. shift
  18. ;;
  19. -o|--output)
  20. shift
  21. OUTPUT_DIRECTORY=$1
  22. shift
  23. ;;
  24. --debug)
  25. shift
  26. DEBUG=1
  27. ;;
  28. -r|--run)
  29. shift
  30. RUN_SCRIPT=1
  31. ;;
  32. -e|--echo)
  33. shift
  34. ECHO_COMMANDS=1
  35. ;;
  36. -k|--keep)
  37. shift
  38. KEEP_FILES=1
  39. ;;
  40. -g|--git)
  41. shift
  42. KEEP_GITFILES=1
  43. ;;
  44. -h|--help)
  45. shift
  46. fmt=" %-31s%s\n"
  47. printf "%s" "Usage: $(basename ${BASH_SOURCE[0]}) [OPTION?]"
  48. printf "\n"
  49. printf "\nThis is a custom pre-processor designed to remove unused flexipatch patches and create a final build."
  50. printf "\n\n"
  51. printf "$fmt" "-r, --run" "include this flag to confirm that you really do want to run this script"
  52. printf "\n"
  53. printf "$fmt" "-d, --directory <dir>" "the flexipatch source directory to process (defaults to current directory)"
  54. printf "$fmt" "-o, --output <dir>" "the output directory to store the processed files"
  55. printf "$fmt" "-h, --help" "display this help section"
  56. printf "$fmt" "-k, --keep" "keep temporary files and do not replace the original ones"
  57. printf "$fmt" "-g, --git" "keep .git files"
  58. printf "$fmt" "-e, --echo" "echo commands that will be run rather than running them"
  59. printf "$fmt" " --debug" "prints additional debug information to stderr"
  60. printf "\nWarning! This script alters and removes files within the source directory."
  61. printf "\nWarning! This process is irreversible! Use with care. Do make a backup before running this."
  62. printf "\n\n"
  63. exit
  64. ;;
  65. *)
  66. echo "Ignoring unknown argument ($1)"
  67. shift
  68. ;;
  69. esac
  70. done
  71. if [[ $RUN_SCRIPT = 0 ]]; then
  72. echo "Re-run this command with the --run option to confirm that you really want to run this script."
  73. echo "The changes this script makes are irreversible."
  74. exit 1
  75. fi
  76. if [[ -z ${OUTPUT_DIRECTORY} ]]; then
  77. echo "Output directory not specified, see -o"
  78. exit 1
  79. fi
  80. DIRECTORY=$(readlink -f "${DIRECTORY}")
  81. OUTPUT_DIRECTORY=$(readlink -f "${OUTPUT_DIRECTORY}")
  82. if [[ $DIRECTORY != $OUTPUT_DIRECTORY ]]; then
  83. mkdir -p "${OUTPUT_DIRECTORY}"
  84. cp -r -f "${DIRECTORY}/." -t "${OUTPUT_DIRECTORY}"
  85. DIRECTORY=${OUTPUT_DIRECTORY}
  86. fi
  87. if [[ ! -e ${DIRECTORY}/patches.h ]]; then
  88. printf "No patches.h file found. Make sure you run this script within a flexipatch source directory."
  89. exit 1
  90. fi
  91. FILES_TO_DELETE=$(find $DIRECTORY -name "*.c" -o -name "*.h" | awk -v DEBUG="$DEBUG" -v DIRECTORY="$DIRECTORY" '
  92. function istrue(f) {
  93. ret = 0
  94. for ( i = 2; i in f; i++ ) {
  95. if ( f[i] == "||" ) {
  96. if ( ret == -1 ) {
  97. ret = 0
  98. } else if ( ret == 1 ) {
  99. break
  100. }
  101. continue
  102. } else if ( f[i] == "&&" ) {
  103. if ( ret == 0 ) {
  104. ret = -1
  105. }
  106. continue
  107. } else if ( ret == -1 ) {
  108. continue
  109. } else if ( f[i] !~ /_(PATCH|LAYOUT)$/ ) {
  110. ret = 1
  111. } else if ( f[i] ~ /^!/ ) {
  112. ret = !patches[substr(f[i],2)]
  113. } else {
  114. ret = patches[f[i]]
  115. }
  116. }
  117. if ( ret == -1 ) {
  118. ret = 0
  119. }
  120. return ret
  121. }
  122. function schedule_delete(file) {
  123. # Skip duplicates
  124. for ( i = 1; i in files_to_delete; i++ ) {
  125. if ( files_to_delete[i] == file) {
  126. return
  127. }
  128. }
  129. if (DEBUG) {
  130. print "Scheduling file " file " for deletion." > "/dev/stderr"
  131. }
  132. files_to_delete[i] = file
  133. }
  134. function is_flexipatch(patch) {
  135. return patch ~ /_(PATCH|LAYOUT)$/
  136. }
  137. BEGIN {
  138. # Read patches.h and store patch settings in the patches associative array
  139. if (DEBUG) {
  140. print "Reading file " DIRECTORY "/patches.h" > "/dev/stderr"
  141. }
  142. while (( getline line < (DIRECTORY"/patches.h") ) > 0 ) {
  143. split(line,f)
  144. if ( f[1] ~ /^#define$/ ) {
  145. if ( f[3] == 0 || f[3] == 1 ) {
  146. patches[f[2]] = f[3]
  147. } else {
  148. patches[f[2]] = istrue(f)
  149. }
  150. if (DEBUG) {
  151. print "Found " f[2] " = " patches[f[2]] > "/dev/stderr"
  152. }
  153. }
  154. }
  155. files_to_delete[0] = ""
  156. }
  157. {
  158. level = 0
  159. do_print[level] = 1
  160. has_printed[level] = 0
  161. condition[level] = ""
  162. while (( getline line < $0) > 0 ) {
  163. split(line,f)
  164. if ( f[1] ~ /^#if$/ ) {
  165. level++;
  166. do_print[level] = do_print[level-1]
  167. has_printed[level] = 0
  168. condition[level] = f[2]
  169. if ( do_print[level] ) {
  170. if ( istrue(f) ) {
  171. has_printed[level] = 1
  172. do_print[level] = 1
  173. } else {
  174. do_print[level] = 0
  175. }
  176. }
  177. if ( is_flexipatch(condition[level]) ) {
  178. continue
  179. }
  180. } else if ( f[1] ~ /^#ifdef$/ || f[1] ~ /^#ifndef$/ ) {
  181. level++;
  182. do_print[level] = do_print[level-1]
  183. has_printed[level] = 0
  184. condition[level] = f[2]
  185. if ( do_print[level] ) {
  186. has_printed[level] = 1
  187. do_print[level] = 1
  188. }
  189. if ( is_flexipatch(condition[level]) ) {
  190. continue
  191. }
  192. } else if ( f[1] ~ /^#elif$/ ) {
  193. if ( (!is_flexipatch(condition[level]) || has_printed[level] == 0) && do_print[level-1] == 1 ) {
  194. if ( istrue(f) ) {
  195. has_printed[level] = 1
  196. do_print[level] = 1
  197. } else {
  198. do_print[level] = 0
  199. }
  200. } else {
  201. do_print[level] = 0
  202. }
  203. if ( is_flexipatch(f[2]) ) {
  204. continue
  205. }
  206. } else if ( f[1] ~ /^#else$/ ) {
  207. if ( (!is_flexipatch(condition[level]) || has_printed[level] == 0) && do_print[level-1] == 1 ) {
  208. has_printed[level] = 1
  209. do_print[level] = 1
  210. } else {
  211. do_print[level] = 0
  212. }
  213. if ( is_flexipatch(condition[level]) ) {
  214. continue
  215. }
  216. } else if ( f[1] ~ /^#include$/ && f[2] ~ /^"/ && (do_print[level] == 0 || f[2] == "\"patches.h\"") ) {
  217. dir = ""
  218. if ( $0 ~ /\// ) {
  219. dir = $0
  220. sub("/[^/]+$", "/", dir)
  221. }
  222. schedule_delete(dir substr(f[2], 2, length(f[2]) - 2))
  223. continue
  224. } else if ( f[1] ~ /^#endif$/ ) {
  225. if ( is_flexipatch(condition[level]) ) {
  226. level--
  227. continue
  228. }
  229. level--
  230. }
  231. if ( do_print[level] ) {
  232. print line > $0 ".~"
  233. }
  234. }
  235. }
  236. END {
  237. for ( i = 1; i in files_to_delete; i++ ) {
  238. print files_to_delete[i]
  239. }
  240. }
  241. ')
  242. # Chmod and replace files
  243. for FILE in $(find $DIRECTORY -name "*.~"); do
  244. chmod --reference=${FILE%%.~} ${FILE}
  245. if [[ $KEEP_FILES = 0 ]] || [[ $ECHO_COMMANDS = 1 ]]; then
  246. if [[ $ECHO_COMMANDS = 1 ]]; then
  247. echo "mv ${FILE} ${FILE%%.~}"
  248. else
  249. mv ${FILE} ${FILE%%.~}
  250. fi
  251. fi
  252. done
  253. # Delete unnecessary files
  254. if [[ $KEEP_FILES = 0 ]] || [[ $ECHO_COMMANDS = 1 ]]; then
  255. # Remove dwmc shell script if patch not enabled
  256. if [[ -f ${DIRECTORY}/patch/dwmc ]] && [[ $(grep -cE '^#define DWMC_PATCH +0 *$' ${DIRECTORY}/patches.h) > 0 ]]; then
  257. if [[ $ECHO_COMMANDS = 1 ]]; then
  258. echo "rm ${DIRECTORY}/patch/dwmc"
  259. echo "sed -r -i -e '/cp -f patch\/dwmc/d' \"${DIRECTORY}/Makefile\""
  260. else
  261. rm "${DIRECTORY}/patch/dwmc"
  262. sed -r -i -e '/cp -f patch\/dwmc/d' "${DIRECTORY}/Makefile"
  263. fi
  264. fi
  265. # Remove layoutmenu.sh shell script if patch not enabled
  266. if [[ -f ${DIRECTORY}/patch/layoutmenu.sh ]] && [[ $(grep -cE '^#define BAR_LAYOUTMENU_PATCH +0 *$' ${DIRECTORY}/patches.h) > 0 ]]; then
  267. if [[ $ECHO_COMMANDS = 1 ]]; then
  268. echo "rm ${DIRECTORY}/patch/layoutmenu.sh"
  269. else
  270. rm "${DIRECTORY}/patch/layoutmenu.sh"
  271. fi
  272. fi
  273. for FILE in $FILES_TO_DELETE ${DIRECTORY}/patches.def.h; do
  274. if [[ $ECHO_COMMANDS = 1 ]]; then
  275. echo "rm $FILE"
  276. else
  277. rm "$FILE"
  278. fi
  279. done
  280. if [[ -f $DIRECTORY/README.md ]]; then
  281. if [[ $ECHO_COMMANDS = 1 ]]; then
  282. echo "rm $DIRECTORY/README.md"
  283. else
  284. rm $DIRECTORY/README.md
  285. fi
  286. fi
  287. if [[ $KEEP_GITFILES = 0 ]]; then
  288. rm -rf $DIRECTORY/.git*
  289. fi
  290. # Remove empty include files
  291. INCLUDE_RE='*patch/*include.[hc]'
  292. if [[ $ECHO_COMMANDS = 1 ]]; then
  293. INCLUDE_RE='*patch/*include.[hc][.]~'
  294. fi
  295. for FILE in $(find $DIRECTORY -path "$INCLUDE_RE"); do
  296. if [[ $(grep -c "#include " $FILE) = 0 ]]; then
  297. if [[ $ECHO_COMMANDS = 1 ]]; then
  298. echo "rm ${FILE%%.~}"
  299. else
  300. rm "$FILE"
  301. fi
  302. for LINE in $(grep -Ern "#include \"patch/$(basename ${FILE%%.~})\"" $DIRECTORY | grep -v '.~:' | awk -F":" '{print $1 ":" $2 }'); do
  303. INCFILE=$(echo $LINE | cut -d":" -f1)
  304. LINE_NO=$(echo $LINE | cut -d":" -f2)
  305. if [[ $ECHO_COMMANDS = 1 ]]; then
  306. echo "sed -i \"${LINE_NO}d\" ${INCFILE}"
  307. else
  308. sed -i "${LINE_NO}d" ${INCFILE}
  309. fi
  310. done
  311. fi
  312. done
  313. fi
  314. # Clean up the Makefile
  315. sed -r -i -e 's/ patches.h$//' -e '/^patches.h:$/{N;N;d;}' "${DIRECTORY}/Makefile"